[
  {
    "path": ".build-test-rules.yml",
    "content": "led_strip/examples/led_strip_rmt_ws2812:\n  disable:\n    - if: CONFIG_SOC_RMT_SUPPORTED != 1\n      reason: Relevant only for RMT enabled targets\n\nled_strip/examples/led_strip_spi_ws2812:\n  enable:\n    - if: (IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR >= 1) or (IDF_VERSION_MAJOR > 5)\n      reason: Example uses some SPI driver features which was introduced in IDF v5.1\n  disable:\n    - if: CONFIG_SOC_GPSPI_SUPPORTED != 1\n      reason: Relevant only for SPI enabled targets\n\nesp_delta_ota:\n  enable:\n    - if: IDF_VERSION_MAJOR > 4\n      reason: Example uses esp_app_format component which was introduced in IDF v5.0\n  disable:\n    - if: SOC_WIFI_SUPPORTED != 1\n      reason: Relevant only for WiFi enabled targets\n\nesp_encrypted_img/examples/pre_encrypted_ota:\n  enable:\n    - if: IDF_TARGET in [\"esp32\", \"esp32s3\"]\n      reason: ESP32 runs RSA OTA encryption test, ESP32-S3 runs ECC OTA encryption test\n\nesp_ext_part_tables/test_apps:\n  enable:\n    - if: ((IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR >= 1) or (IDF_VERSION_MAJOR >= 6)) and IDF_TARGET == \"linux\"\n      reason: Host test is enough\n\nsh2lib/examples/http2_request:\n  enable:\n    - if: IDF_VERSION_MAJOR > 4 and INCLUDE_DEFAULT == 1\n      reason: Example uses sh2lib component which was introduced in IDF v5.0\n\nesp_jpeg/examples/get_started:\n  enable:\n    - if: IDF_VERSION_MAJOR > 4 and IDF_TARGET in [\"esp32\", \"esp32s2\", \"esp32s3\"]\n      reason: Example depends on BSP, which is supported only for IDF >= 5.0 and limited targets\n\nesp_schedule/examples/get_started:\n  enable:\n    - if: ((IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR >= 1) or (IDF_VERSION_MAJOR > 5)) and SOC_WIFI_SUPPORTED == 1\n      reason: Network provisioning component has dependencies IDF >= 5.1; example only supports Wi-Fi enabled targets\n\ncatch2/examples/catch2-test:\n  enable:\n    - if: INCLUDE_DEFAULT == 1 or IDF_TARGET == \"linux\"\n  disable:\n    - if: IDF_VERSION_MAJOR < 5\n      reason: Example relies on WHOLE_ARCHIVE component property which was introduced in IDF v5.0\n    - if: ((IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR < 1) and IDF_TARGET == \"linux\")\n      reason: Docker container for release/v5.0 doesn't contain a C++ compiler\n\ncatch2/examples/catch2-console:\n  disable:\n    - if: IDF_VERSION_MAJOR < 5\n      reason: Example relies on WHOLE_ARCHIVE component property which was introduced in IDF v5.0\n\nnetwork_provisioning/examples/thread_prov:\n  enable:\n    - if: ((IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR >= 1) or (IDF_VERSION_MAJOR > 5))\n      reason: Network provisioning component has dependencies IDF >= 5.1\n  disable:\n    - if: SOC_IEEE802154_SUPPORTED != 1\n      reason: Relevant only for IEEE802.15.4 enabled targets\n\nnetwork_provisioning/examples/wifi_prov:\n  enable:\n    - if: ((IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR >= 1) or (IDF_VERSION_MAJOR > 5))\n      reason: Network provisioning component has dependencies IDF >= 5.1\n  disable:\n    - if: SOC_WIFI_SUPPORTED != 1\n      reason: Relevant only for WiFi enabled targets\n\nesp_lcd_qemu_rgb/examples/lcd_qemu_rgb_panel:\n  enable:\n    - if: ((IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR >= 3) or (IDF_VERSION_MAJOR > 5)) and (IDF_TARGET in [\"esp32\", \"esp32c3\"])\n      reason: Example is meant to be run under QEMU, which currently only supports ESP32 and ESP32-C3\n\nspi_nand_flash/test_app:\n  disable:\n    - if: IDF_VERSION_MAJOR < 5\n      reason: The spi_nand_flash component is compatible with IDF version v5.0 and above, due to a change in the f_mkfs API in versions above v5.0, which is not supported in older IDF versions.\n    - if: IDF_VERSION_MAJOR < 6 and CONFIG_NAME == \"bdl\"\n      reason: BDL support requires the esp_blockdev interface, available starting from IDF version v6.0.\n\nspi_nand_flash/host_test:\n  enable:\n    - if: IDF_TARGET == \"linux\"\n  disable:\n    - if: IDF_VERSION_MAJOR < 5\n      reason: The spi_nand_flash component is compatible with IDF version v5.0 and above, due to a change in the f_mkfs API in versions above v5.0, which is not supported in older IDF versions.\n    - if: IDF_VERSION_MAJOR == 5 and (IDF_VERSION_MINOR < 3)\n      reason: Fails to build on older versions of IDF\n\nspi_nand_flash_fatfs/examples/nand_flash:\n  disable:\n    - if: IDF_VERSION_MAJOR < 5\n      reason: The spi_nand_flash component is compatible with IDF version v5.0 and above, due to a change in the f_mkfs API in versions above v5.0, which is not supported in older IDF versions.\n"
  },
  {
    "path": ".codespellrc",
    "content": "[codespell]\nskip = build,COPYING.*,LICENSE,*.svg\nignore-words-list = ser,DOUT,dout,ans,nd,Dettached,IST\nwrite-changes = true\n"
  },
  {
    "path": ".editorconfig",
    "content": "# EditorConfig helps developers define and maintain consistent\n# coding styles between different editors and IDEs\n# http://editorconfig.org\n\nroot = true\n\n[*]\nindent_style = space\nindent_size = 4\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[{*.md,*.rst}]\ntrim_trailing_whitespace = false\n\n[{*.cmake,CMakeLists.txt}]\nindent_style = space\nindent_size = 4\nmax_line_length = 120\n\n[{*.sh,*.yml,*.yaml}]\nindent_style = space\nindent_size = 2\n"
  },
  {
    "path": ".git-blame-ignore-revs",
    "content": "# Fix configuration files\n9e76da9fa7ddbeef8cb0d47fd8f2e7668f58b3ec\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.yml",
    "content": "name: Bug report\ndescription: Report build and runtime bugs\nlabels: [\"Type: Bug\"]\nbody:\n  - type: checkboxes\n    id: checklist\n    attributes:\n      label: Answers checklist.\n      description: Before submitting a new issue, please follow the checklist and try to find the answer.\n      options:\n        - label: I have read the component documentation [ESP-IDF Components](https://components.espressif.com) and the issue is not addressed there.\n          required: true\n        - label: I am using target and esp-idf version as defined in component's idf_component.yml\n          required: true\n        - label: I have searched the [issue tracker](https://github.com/espressif/idf-extra-components/issues?q=is%3Aissue) for a similar issue and not found any related issue.\n          required: true\n  - type: dropdown\n    id: component\n    attributes:\n      label: Which component are you using? If you choose Other, provide details in More Information.\n      multiple: false\n      options:\n        - argtable3\n        - bdc_motor\n        - catch2\n        - cbor\n        - ccomp_timer\n        - cjson\n        - coap\n        - coremark\n        - dhara\n        - eigen\n        - esp_daylight\n        - esp_delta_ota\n        - esp_cli_commands\n        - esp_encrypted_img\n        - esp_flash_dispatcher\n        - esp_ext_part_tables\n        - esp_gcov\n        - esp_isotp\n        - esp_jpeg\n        - esp_lcd_qemu_rgb\n        - esp_schedule\n        - esp_cli\n        - esp_serial_slave_link\n        - esp_sysview\n        - expat\n        - fmt\n        - freetype\n        - iqmath\n        - jsmn\n        - json_generator\n        - json_parser\n        - led_strip\n        - libpng\n        - libsodium\n        - esp_linenoise\n        - network_provisioning\n        - nghttp\n        - onewire_bus\n        - pcap\n        - pid_ctrl\n        - qrcode\n        - quirc\n        - sh2lib\n        - spi_nand_flash\n        - spi_nand_flash_fatfs\n        - supertinycron\n        - thorvg\n        - touch_element\n        - unit-test-app\n        - zlib\n        - libjpeg-turbo\n        - Other\n    validations:\n      required: true\n  - type: input\n    id: idf_version\n    attributes:\n      label: ESP-IDF version.\n      description: On which ESP-IDF version does this issue occur on? Run `git describe --tags` in your esp-idf folder to find it.\n      placeholder: ex. v5.0-rc1\n    validations:\n      required: true\n  - type: input\n    id: devkit\n    attributes:\n      label: Development Kit.\n      description: On which Development Kit does this issue occur on?\n      placeholder: ex. ESP32-Wrover-Kit v2 | Custom Board\n    validations:\n      required: true\n  - type: input\n    id: component_version\n    attributes:\n      label: Used Component version.\n      description: On which Component version does this issue occur on? Check `dependencies.lock` file in your project root to find it.\n      placeholder: ex. v1.2.0-rc0\n    validations:\n      required: true\n  - type: textarea\n    id: more-info\n    attributes:\n      label: More Information.\n      description: Do you have any other information from investigating this?\n      placeholder: ex. I tried on my friend's Windows 10 PC and the command works there.\n    validations:\n      required: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Component Registry\n    url: https://components.espressif.com\n    about: Registry with all available ESP-IDF components.\n  - name: ESP-IDF Programming Guide\n    url: https://docs.espressif.com/projects/esp-idf/en/latest/\n    about: Documentation for configuring and using ESP-IDF.\n  - name: Espressif documentation page\n    url: https://www.espressif.com/en/support/download/documents\n    about: Hardware documentation (datasheets, Technical Reference Manual, etc).\n  - name: Forum\n    url: https://esp32.com\n    about: For questions about using ESP-IDF and/or ESP32 series chips. Please submit all questions starting \"How do I...\" here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-request.yml",
    "content": "name: Feature request\ndescription: Suggest an idea or new component for this project.\nlabels: [\"Type: Feature Request\"]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        * We welcome any ideas or feature requests! It’s helpful if you can explain exactly why the feature would be useful.\n        * There are usually some outstanding feature requests in the [existing issues list](https://github.com/espressif/idf-extra-components/labels/Type%3A%20Feature%20Request), feel free to add comments to them.\n  - type: textarea\n    id: problem-related\n    attributes:\n      label: Is your feature request related to a problem?\n      description: Please provide a clear and concise description of what the problem is.\n      placeholder: ex. I'm always frustrated when ...\n  - type: textarea\n    id: solution\n    attributes:\n      label: Describe the solution you'd like.\n      description: Please provide a clear and concise description of what you want to happen.\n      placeholder: ex. When building my application ...\n  - type: textarea\n    id: alternatives\n    attributes:\n      label: Describe alternatives you've considered.\n      description: Please provide a clear and concise description of any alternative solutions or features you've considered.\n      placeholder: ex. Choosing other approach wouldn't work, because ...\n  - type: textarea\n    id: context\n    attributes:\n      label: Additional context.\n      description: Please add any other context or screenshots about the feature request here.\n      placeholder: ex. This would work only when ...\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/other-issue.yml",
    "content": "name: General issue report\ndescription: File an issue report\nbody:\n  - type: checkboxes\n    id: checklist\n    attributes:\n      label: Answers checklist.\n      description: Before submitting a new issue, please follow the checklist and try to find the answer.\n      options:\n        - label: I have read the documentation of the component in question and the issue is not addressed there.\n          required: true\n        - label: I have searched the issue tracker for a similar issue and not found a similar issue.\n          required: true\n  - type: textarea\n    id: issue\n    attributes:\n      label: General issue report\n      description: Your issue report goes here.\n      placeholder: ex. How do I...\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/new_component.md",
    "content": "# Checklist\n\n- [ ] Component contains License\n- [ ] Component contains README.md\n- [ ] Component contains idf_component.yml file with `url` field defined\n- [ ] Component was added to [upload job](https://github.com/espressif/idf-extra-components/blob/master/.github/workflows/upload_component.yml#L18)\n- [ ] Component was added to [bug report](https://github.com/espressif/idf-extra-components/blob/master/.github/ISSUE_TEMPLATE/bug-report.yml?plain=1#L22)\n- [ ] Component has an example project\n- [ ] _Optional:_ Component has a test_app\n- [ ] CI passing\n\n# Change description\n_Please describe your change here_\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/update_component.md",
    "content": "# Checklist\n\n- [ ] Version in idf_component.yml file bumped\n- [ ] _Optional:_ README.md updated\n- [ ] CI passing\n\n# Change description\n_Please describe your change here_\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "# Checklist\n\n- [ ] Component contains License\n- [ ] Component contains README.md\n- [ ] Component contains idf_component.yml file with `url` field defined\n- [ ] Component was added to [upload job](https://github.com/espressif/idf-extra-components/blob/master/.github/workflows/upload_component.yml#L18)\n- [ ] Component was added to [build job](https://github.com/espressif/idf-extra-components/blob/master/test_app/CMakeLists.txt#L8)\n- [ ] _Optional:_ Component contains unit tests\n- [ ] CI passing\n\n# Change description\n_Please describe your change here_\n"
  },
  {
    "path": ".github/build_docs.py",
    "content": "#!/usr/bin/env python3\n\"\"\"\nDocumentation build script for ESP-IDF Extra Components.\n\nThis script searches for components with documentation, builds them using mdbook,\nand copies the built documentation to an output directory.\n\"\"\"\n\nimport argparse\nimport logging\nimport os\nimport pathlib\nimport shutil\nimport subprocess\nimport sys\nfrom contextlib import contextmanager\nfrom dataclasses import dataclass\nfrom typing import List, Union\n\n\n# Configure logging\nlogging.basicConfig(\n    level=logging.INFO,\n    format=\"%(asctime)s - %(levelname)s - %(message)s\",\n    datefmt=\"%Y-%m-%d %H:%M:%S\"\n)\nlogger = logging.getLogger(\"build_docs\")\n\n\n@dataclass\nclass BuildConfig:\n    \"\"\"Configuration for the documentation build process.\"\"\"\n    repo_root: pathlib.Path\n    output_dir: pathlib.Path\n    version: str = \"latest\"\n    fail_fast: bool = True\n\n\n@contextmanager\ndef change_directory(path: Union[str, pathlib.Path]):\n    \"\"\"Context manager for temporarily changing the working directory.\"\"\"\n    original_dir = pathlib.Path.cwd()\n    try:\n        os.chdir(path)\n        yield\n    finally:\n        os.chdir(original_dir)\n\n\ndef find_components_with_docs(repo_root: pathlib.Path) -> List[str]:\n    \"\"\"\n    Search the repo for component folders that have docs/book.toml.\n\n    Args:\n        repo_root: Repository root directory\n\n    Returns:\n        List of component names with documentation\n    \"\"\"\n    components = []\n\n    for item in repo_root.iterdir():\n        if not item.is_dir():\n            continue\n\n        docs_path = item / \"docs\"\n        book_toml_path = docs_path / \"book.toml\"\n\n        if docs_path.is_dir() and book_toml_path.is_file():\n            components.append(item.name)\n            logger.info(f\"Found component with docs: {item.name}\")\n\n    return components\n\n\ndef generate_api_docs(component_docs_path: pathlib.Path) -> bool:\n    \"\"\"\n    Generate API documentation using esp-doxybook.\n\n    Args:\n        component_docs_path: Path to component docs directory\n\n    Returns:\n        True if successful, False otherwise\n    \"\"\"\n    api_md_path = component_docs_path / \"src\" / \"api.md\"\n\n    # Create src directory if it doesn't exist\n    (component_docs_path / \"src\").mkdir(exist_ok=True)\n\n    logger.info(f\"Generating API documentation in {api_md_path}\")\n\n    try:\n        with change_directory(component_docs_path):\n            # Note: Using relative paths since we're in the docs directory\n            subprocess.run(\n                [\"esp-doxybook\", \"-i\", \"doxygen_output/xml\", \"-o\", \"src/api.md\"],\n                check=True,\n                capture_output=True,\n                text=True\n            )\n        logger.info(\"API documentation generated successfully\")\n        return True\n    except subprocess.CalledProcessError as e:\n        logger.warning(f\"Failed to generate API documentation: {e}\")\n        logger.warning(f\"stdout: {e.stdout if hasattr(e, 'stdout') else 'N/A'}\")\n        logger.warning(f\"stderr: {e.stderr if hasattr(e, 'stderr') else 'N/A'}\")\n        logger.warning(\"Continuing with mdbook build...\")\n        return False\n\n\ndef build_component_docs(component_name: str, config: BuildConfig) -> bool:\n    \"\"\"\n    Build documentation for a component using mdbook.\n\n    Args:\n        component_name: Component name\n        config: Build configuration\n\n    Returns:\n        True if build was successful, False otherwise\n    \"\"\"\n    component_docs_path = config.repo_root / component_name / \"docs\"\n\n    logger.info(f\"Building docs for {component_name}...\")\n\n    try:\n        # Generate API documentation\n        generate_api_docs(component_docs_path)\n\n        # Build mdbook\n        env = os.environ.copy()\n\n        # Set site-url based on version\n        site_url = f\"/idf-extra-components/{config.version}/{component_name}/\"\n\n        logger.info(f\"Setting site-url to: {site_url}\")\n        env[\"MDBOOK_OUTPUT__HTML__SITE_URL\"] = site_url\n\n        result = subprocess.run(\n            [\"mdbook\", \"build\", str(component_docs_path)],\n            check=True,\n            env=env,\n            capture_output=True,\n            text=True\n        )\n\n        # Log mdbook output at debug level\n        logger.debug(f\"mdbook stdout: {result.stdout}\")\n        logger.debug(f\"mdbook stderr: {result.stderr}\")\n\n        # Verify the book directory was created\n        book_path = component_docs_path / \"book\"\n        if not book_path.exists():\n            logger.error(f\"Book path {book_path} does not exist after build\")\n            return False\n\n        return True\n    except subprocess.CalledProcessError as e:\n        logger.error(f\"Error building docs for {component_name}: {e}\")\n        logger.error(f\"stdout: {e.stdout if hasattr(e, 'stdout') else 'N/A'}\")\n        logger.error(f\"stderr: {e.stderr if hasattr(e, 'stderr') else 'N/A'}\")\n        return False\n\n\ndef copy_docs_to_output(component_name: str, config: BuildConfig) -> bool:\n    \"\"\"\n    Copy the built documentation to the docs output directory.\n\n    Args:\n        component_name: Component name\n        config: Build configuration\n\n    Returns:\n        True if copy was successful, False otherwise\n    \"\"\"\n    source_path = config.repo_root / component_name / \"docs\" / \"book\"\n    dest_path = config.output_dir / component_name\n\n    if not source_path.exists():\n        logger.warning(f\"Source path {source_path} does not exist, skipping copy\")\n        return False\n\n    # Remove destination if it exists to avoid issues with copytree\n    if dest_path.exists():\n        shutil.rmtree(dest_path)\n\n    # Create parent directory if needed\n    dest_path.parent.mkdir(exist_ok=True)\n\n    # Copy the documentation\n    shutil.copytree(source_path, dest_path)\n    logger.info(f\"Copied docs from {source_path} to {dest_path}\")\n    return True\n\n\ndef build_all_docs(config: BuildConfig) -> bool:\n    \"\"\"\n    Build documentation for all components.\n\n    Args:\n        config: Build configuration\n\n    Returns:\n        True if all builds were successful, False otherwise\n    \"\"\"\n    # Find components with docs\n    components = find_components_with_docs(config.repo_root)\n    logger.info(f\"Found {len(components)} components with documentation: {', '.join(components)}\")\n\n    if not components:\n        logger.warning(\"No components with documentation found\")\n        return True\n\n    # Clean output directory\n    if config.output_dir.exists():\n        shutil.rmtree(config.output_dir)\n    config.output_dir.mkdir(exist_ok=True)\n\n    # Build docs for each component\n    build_success = True\n\n    for component in components:\n        if not build_component_docs(component, config):\n            logger.error(f\"Documentation build failed for component {component}\")\n            build_success = False\n            if config.fail_fast:\n                logger.info(\"Fail-fast enabled, stopping build\")\n                break\n        else:\n            # Only copy docs if build was successful\n            copy_docs_to_output(component, config)\n\n    return build_success\n\n\ndef parse_args() -> argparse.Namespace:\n    \"\"\"Parse command line arguments.\"\"\"\n    parser = argparse.ArgumentParser(\n        description=\"Build component documentation\",\n        formatter_class=argparse.ArgumentDefaultsHelpFormatter\n    )\n    parser.add_argument(\n        \"--version\",\n        type=str,\n        default=\"latest\",\n        help=\"Version identifier for the docs (e.g., 'latest', 'v1.0', 'pr-preview-123')\"\n    )\n    parser.add_argument(\n        \"--output-dir\",\n        type=str,\n        default=\"docs_build_output\",\n        help=\"Directory where built documentation will be stored\"\n    )\n    parser.add_argument(\n        \"--no-fail-fast\",\n        action=\"store_true\",\n        help=\"Continue building even if one component fails\"\n    )\n    parser.add_argument(\n        \"--verbose\", \"-v\",\n        action=\"store_true\",\n        help=\"Enable verbose output\"\n    )\n    return parser.parse_args()\n\n\ndef main():\n    \"\"\"Main entry point.\"\"\"\n    args = parse_args()\n\n    # Set logging level based on verbosity\n    if args.verbose:\n        logger.setLevel(logging.DEBUG)\n\n    # Create build configuration\n    config = BuildConfig(\n        repo_root=pathlib.Path.cwd(),\n        output_dir=pathlib.Path.cwd() / args.output_dir,\n        version=args.version,\n        fail_fast=not args.no_fail_fast\n    )\n\n    logger.info(\"Building documentation with config:\")\n    logger.info(f\"- Output directory: {config.output_dir}\")\n    logger.info(f\"- Version: {config.version}\")\n    logger.info(f\"- Fail fast: {config.fail_fast}\")\n\n    # Build all documentation\n    success = build_all_docs(config)\n\n    if success:\n        logger.info(\"All documentation built successfully\")\n        return 0\n    else:\n        logger.error(\"Documentation build failed\")\n        return 1\n\n\nif __name__ == \"__main__\":\n    sys.exit(main())\n"
  },
  {
    "path": ".github/clang-tidy/test_app/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\n# add all the components from the root directory of the repo\nset(root_dir ${CMAKE_CURRENT_LIST_DIR}/../../..)\nfile(GLOB component_cmakelists_files ${root_dir}/*/CMakeLists.txt)\n\n# convert to absolute paths\nset(component_dirs)\nset(component_names)\nforeach(component_cmakelists_file ${component_cmakelists_files})\n    get_filename_component(component_dir ${component_cmakelists_file} DIRECTORY)\n    get_filename_component(component_name ${component_dir} NAME)\n    # skip touch_element because it does not support esp32\n    if(${component_name} STREQUAL \"touch_element\")\n        continue()\n    endif()\n    if(${component_name} STREQUAL \"test_app\")\n        continue()\n    endif()\n    list(APPEND component_names ${component_name})\n    list(APPEND component_dirs ${component_dir})\nendforeach()\n\nset(EXTRA_COMPONENT_DIRS ${component_dirs})\n\n# generate an idf.py argument file with `--exclude-paths <submodule_path>` for each submodule\nset(clang_check_args \"--include-paths ${root_dir}\")\nlist(APPEND clang_check_args \"--exclude-paths ${root_dir}/.github\")\nlist(APPEND clang_check_args \"--exclude-paths $ENV{IDF_PATH}\")\n\n# Exclude third-party code from clang-tidy checks\nlist(APPEND clang_check_args \"--exclude-paths ${root_dir}/esp_sysview/src/SEGGER\")\nlist(APPEND clang_check_args \"--exclude-paths ${root_dir}/esp_sysview/src/Sample\")\n\n# get the list of submodules\nexecute_process(\n    COMMAND git config --file ${root_dir}/.gitmodules --get-regexp path\n    OUTPUT_VARIABLE submodules_output\n)\n\n# each line will be in the format \"submodule.<name>.path <path>\", extract the part after the last space\nSTRING(REGEX REPLACE \"\\r?\\n\" \";\" submodules_output \"${submodules_output}\")\nforeach(line ${submodules_output})\n    # extract the path\n    STRING(REGEX REPLACE \".* \" \"\" submodule_path \"${line}\")\n    # add the exclude-paths argument\n    list(APPEND clang_check_args \"--exclude-paths ${root_dir}/${submodule_path}\")\nendforeach()\n\nset(clang_check_args_file ${CMAKE_CURRENT_BINARY_DIR}/clang_check_args)\nlist(JOIN clang_check_args \" \" clang_check_args_str)\nfile(WRITE ${clang_check_args_file} ${clang_check_args_str})\n\n# actual project definition...\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\n\nproject(test_app)\n"
  },
  {
    "path": ".github/consistency_check.py",
    "content": "#!/usr/bin/env python\n# This script performs various consistency checks on the repository.\nimport argparse\nimport logging\nimport glob\nimport os\nfrom pathlib import Path\n\nimport yaml\n\n\nLOG = logging.getLogger(\"consistency_check\")\nfailures = 0\n\n\ndef main():\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\"--root\", default=\".\", help=\"Root directory of the repository\")\n    args = parser.parse_args()\n\n    logging.basicConfig(level=logging.INFO)\n\n    check_build_manifests_added_to_config(args)\n    check_components_added_to_upload_job(args)\n    check_components_added_to_issue_template(args)\n\n    if failures:\n        LOG.error(f\"Found {failures} issues\")\n        raise SystemExit(1)\n\n\n#### Checks ####\n\ndef check_build_manifests_added_to_config(args):\n    LOG.info(\"Checking that all .build-test-rules.yml files are added to .idf_build_apps.toml\")\n\n    build_manifests_from_repo = set(glob.glob(f\"{args.root}/**/.build-test-rules.yml\", recursive=True))\n    # exclude the ones under 'managed_components'\n    build_manifests_from_repo = set([Path(f) for f in build_manifests_from_repo if \"managed_components\" not in f])\n\n    idf_build_apps_toml = load_toml(os.path.join(args.root, \".idf_build_apps.toml\"))\n    build_manifests_from_config = set([Path(f) for f in idf_build_apps_toml.get(\"manifest_file\", [])])\n\n    missing = build_manifests_from_repo - build_manifests_from_config\n    if missing:\n        LOG.error(f\"Missing build manifests in .idf_build_apps.toml: {missing}\")\n        add_failure()\n\n\ndef check_components_added_to_upload_job(args):\n    LOG.info(\"Checking that all components are added to the upload job\")\n\n    components_from_repo = set([Path(f).name for f in get_component_dirs(args)])\n\n    upload_job = load_yaml(os.path.join(args.root, \".github/workflows/upload_component.yml\"))\n    upload_job_steps = upload_job.get(\"jobs\", {}).get(\"upload_components\", {}).get(\"steps\", [])\n    upload_job_step = next((step for step in upload_job_steps if step.get(\"name\") == \"Upload components to component service\"), None)\n    components_from_upload_job = set([name.strip() for name in upload_job_step.get(\"with\", {}).get(\"components\", \"\").split(\"\\n\") if name.strip()])\n\n    missing = components_from_repo - components_from_upload_job\n    if missing:\n        LOG.error(f\"Missing components in upload job: {missing}\")\n        add_failure()\n\n\ndef check_components_added_to_issue_template(args):\n    LOG.info(\"Checking that all components are added to the issue template\")\n\n    issue_template = load_yaml(os.path.join(args.root, \".github/ISSUE_TEMPLATE/bug-report.yml\"))\n    issue_template_component = next((element for element in issue_template.get(\"body\", []) if element.get(\"id\") == \"component\"), None)\n    components_from_issue_template = set(issue_template_component.get(\"attributes\", {}).get(\"options\", []))\n\n    components_from_repo = set([Path(component).name for component in get_component_dirs(args)])\n    missing = components_from_repo - components_from_issue_template\n    if missing:\n        LOG.error(f\"Missing components in issue template: {missing}\")\n        add_failure()\n    extra = components_from_issue_template - components_from_repo - set([\"Other\"])\n    if extra:\n        LOG.error(f\"Extra components in issue template: {extra}\")\n        add_failure()\n\n\n#### Utility functions ####\n\ndef load_toml(filepath) -> dict:\n    try:\n        import tomllib  # type: ignore # python 3.11\n\n        try:\n            with open(str(filepath), 'rb') as fr:\n                return tomllib.load(fr)\n        except Exception as e:\n            raise ValueError(f\"Failed to load {filepath}: {e}\")\n    except ImportError:\n        import toml\n\n        try:\n            return toml.load(str(filepath))\n        except Exception as e:\n            raise ValueError(f\"Failed to load {filepath}: {e}\")\n\n\ndef load_yaml(filepath) -> dict:\n    with open(filepath, \"r\") as f:\n        return yaml.safe_load(f)\n\n\ndef get_component_dirs(args):\n    \"\"\"\n    Returns a list of component paths in this repository.\n    \"\"\"\n    components_from_repo = set(glob.glob(f\"{args.root}/*/idf_component.yml\"))\n    components_from_repo = [Path(f).parent.name for f in components_from_repo]\n    return components_from_repo\n\ndef add_failure():\n    global failures\n    failures += 1\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": ".github/filter_sarif.py",
    "content": "#!/usr/bin/env python3\n\nimport argparse\nimport copy\nimport json\nimport typing as t\n\n\ndef main():\n    parser = argparse.ArgumentParser()\n    parser.add_argument('-o', '--output', type=argparse.FileType('w'), help='Output filtered SARIF file')\n    parser.add_argument('--include-prefix', required=True, action='append',\n                        help='File prefix for source code to include in analysis')\n    parser.add_argument('--exclude-text-contains', action='append', default=[],\n                        help='Exclude results whose message.text contains this substring (may be repeated)')\n    parser.add_argument('input_file', type=argparse.FileType('r'), help='Input SARIF file')\n    args = parser.parse_args()\n    process(args.input_file, args.output, args.include_prefix, args.exclude_text_contains)\n\n\ndef process(in_file: t.TextIO, out_file: t.TextIO, include_prefix_list: t.List[str], exclude_text_contains_list: t.List[str]) -> None:\n    in_json = json.load(in_file)\n    if len(in_json['runs']) != 1:\n        raise NotImplementedError('Only 1 run is supported')\n    in_results = in_json['runs'][0]['results']\n    out_results = []\n    for result in in_results:\n        transformed = transform_result(result, include_prefix_list, exclude_text_contains_list)\n        if transformed is not None:\n            out_results.append(transformed)\n\n    out_json = copy.deepcopy(in_json)\n    out_json['runs'][0]['results'] = out_results\n    json.dump(out_json, out_file, indent=True)\n\n\ndef normalize_uri_optional(uri: t.Optional[str], include_prefix_list: t.List[str], strict: bool) -> t.Optional[str]:\n    if uri is None:\n        return None\n    for include_prefix in include_prefix_list:\n        if uri.startswith(include_prefix):\n            return uri.replace(include_prefix, '')\n    return None if strict else uri\n\n\ndef message_contains_any(text: str, substrings: t.List[str]) -> bool:\n    return any(substr in text for substr in substrings)\n\n\ndef dedupe_related_locations(related_locations: t.Any, include_prefix_list: t.List[str]) -> t.List[t.Dict[str, t.Any]]:\n    if not isinstance(related_locations, list) or not related_locations:\n        return []\n    seen_keys: t.Set[t.Tuple[t.Any, ...]] = set()\n    deduped: t.List[t.Dict[str, t.Any]] = []\n    for rel in related_locations:\n        if not isinstance(rel, dict):\n            continue\n        rel_msg_text = rel['message']['text']\n        rel_uri = rel['physicalLocation']['artifactLocation']['uri']\n        rel_uri_norm = normalize_uri_optional(rel_uri, include_prefix_list, strict=False)\n        rel['physicalLocation']['artifactLocation']['uri'] = rel_uri_norm\n        key = (rel_msg_text,\n               rel_uri_norm,\n               rel['physicalLocation']['region']['startLine'],\n               rel['physicalLocation']['region']['startColumn'])\n        if key in seen_keys:\n            continue\n        seen_keys.add(key)\n        deduped.append(rel)\n    return deduped\n\n\ndef transform_result(result: t.Dict[str, t.Any], include_prefix_list: t.List[str], exclude_text_contains_list: t.List[str]) -> t.Optional[t.Dict[str, t.Any]]:\n    locations = result['locations']\n    if len(locations) != 1:\n        raise NotImplementedError('Only 1 location is supported')\n    artifact_location = locations[0]['physicalLocation']['artifactLocation']\n    uri = artifact_location['uri']\n    normalized_uri = normalize_uri_optional(uri, include_prefix_list, strict=True)\n    if not normalized_uri:\n        return None\n    message_text = result['message']['text']\n    if message_contains_any(message_text, exclude_text_contains_list):\n        return None\n    new_result = copy.deepcopy(result)\n    new_result['locations'][0]['physicalLocation']['artifactLocation']['uri'] = normalized_uri\n    deduped_related = dedupe_related_locations(new_result.get('relatedLocations'), include_prefix_list)\n    if deduped_related:\n        new_result['relatedLocations'] = deduped_related\n    elif 'relatedLocations' in new_result:\n        # Ensure we have a list per schema even if empty\n        new_result['relatedLocations'] = []\n    return new_result\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": ".github/get_idf_build_apps_args.py",
    "content": "#!/usr/bin/env python3\n\nimport argparse\nimport os\n\ndef main():\n    parser = argparse.ArgumentParser()\n    parser.add_argument('-v', '--verbose', action='store_true', help='Enable verbose output')\n    parser.add_argument('modified_files_list', type=argparse.FileType('r'), help='Input file containing list of modified files')\n    parser.add_argument('idf_build_apps_args', type=argparse.FileType('w'), help='Output file containing idf-build-apps arguments')\n    args = parser.parse_args()\n\n    modified_files = args.modified_files_list.read().splitlines()\n    idf_build_apps_args = []\n    if modified_files:\n        idf_build_apps_args += [\n            '--modified-files',\n            '\"' + ';'.join(modified_files) + '\"'\n            ]\n    \n    if args.verbose:\n        print('Modified files:')\n        for file in sorted(modified_files):\n            print(f'  - {file}')\n\n    modified_components = set()\n    excluded_dirs = ['.github']\n    for file in modified_files:\n        toplevel = file.split('/')[0]\n        if toplevel in excluded_dirs:\n            continue\n        if not os.path.isdir(toplevel):\n            continue\n        modified_components.add(toplevel)\n    \n    if modified_components:\n        idf_build_apps_args += [\n            '--modified-components',\n            '\"' + ';'.join(modified_components) + '\"'\n            ]\n    else:\n        idf_build_apps_args += [\n            '--modified-components',\n            'dummy_component'\n            ]\n\n    if args.verbose:\n        print('Modified components:')\n        for component in sorted(modified_components):\n            print(f'  - {component}')\n\n    args.idf_build_apps_args.write(' '.join(idf_build_apps_args))\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": ".github/get_pytest_args.py",
    "content": "#!/usr/bin/env python3\n\nimport argparse\nimport json\nimport glob\n\n\ndef main():\n    parser = argparse.ArgumentParser()\n    parser.add_argument('-v', '--verbose', action='store_true', help='Enable verbose output')\n    parser.add_argument('--target', type=str, required=True, help='Target to run tests for')\n    parser.add_argument('build_info_json', type=str, help='Input file(s) containing build info generated by idf-build-apps. Accepts globs.')\n    parser.add_argument('pytest_args', type=argparse.FileType('w'), help='Output file containing pytest arguments')\n\n    args = parser.parse_args()\n    pytest_args = []\n    app_ignore_status = {}\n    app_json_files = glob.glob(args.build_info_json)\n    if args.verbose:\n        print(f'Found {len(app_json_files)} app_json files')\n        for app_json_file in app_json_files:\n            print(f'  - {app_json_file}')\n    for app_json_file in app_json_files:\n        with open(app_json_file, 'r') as build_info_json:\n            if args.verbose:\n                print(f'Processing {app_json_file}')\n            for app_json_line in build_info_json.readlines():\n                app_json = json.loads(app_json_line)\n                app_dir = app_json['app_dir']\n                if app_dir not in app_ignore_status.keys():\n                    app_ignore_status[app_dir] = True\n                if app_json['target'] == args.target and app_json['build_status'] != 'skipped':\n                    app_ignore_status[app_dir] = False\n\n    for app_dir, ignore in app_ignore_status.items():\n        if ignore:\n            if args.verbose:\n                print(f'Skipping {app_dir}')\n            pytest_args += [\n                '--ignore',\n                app_dir\n            ]\n        else:\n            if args.verbose:\n                print(f'Not skipping {app_dir}')\n\n\n    args.pytest_args.write(' '.join(pytest_args))\n\n\nif __name__ == '__main__':\n    main()\n\n"
  },
  {
    "path": ".github/readme_workflows.md",
    "content": "# CI in idf-extra-components\n\n## Build and test apps\n\nThe workflow defined in [build_and_run_apps.yml](workflows/build_and_run_apps.yml) builds the apps (examples, test apps) and runs the tests on self-hosted runners.\n\n\n```mermaid\nflowchart TD\n        PR((Pull Request))\n        PR -->labels\n\n        schedule((Schedule<br>Push to master))\n        schedule -->idf-build-apps-build\n\n    subgraph \"Generate pipeline\"\n        labels[Get labels] --> get-changes\n        get-changes[Get changed files]\n        get-changes --> build-all\n        build-all{Build all apps<br> label set?}\n        build-all --> |yes| changed-components\n        changed-components --> idf-build-apps-args\n        build-all --> |no| idf-build-apps-args        \n        changed-components[Get changed components]\n        idf-build-apps-args[Prepare idf-build-apps arguments]\n    end\n    subgraph \"Build apps\"\n        idf-build-apps-args --> idf-build-apps-build\n        idf-build-apps-build[idf-build-apps build] --> \n        build-only\n        build-only{Build only<br>label set?}\n        build-only --> |no| upload-artifacts\n        \n        upload-artifacts[Upload artifacts]\n\n    end\n    subgraph \"Test apps\"\n        upload-artifacts -->download-artifacts\n        download-artifacts[Download artifacts] -->pytest\n        pytest[Pytest] -->upload-results\n        upload-results[Upload results]\n    end\n    subgraph \"Generate report\"\n        upload-results -->download-results\n        download-results[Download results] -->generate-report\n        generate-report[Generate report]\n    end\n\n    build-only --> |yes| fin\n    generate-report -->fin\n    fin([Finish])\n```"
  },
  {
    "path": ".github/setup_qemu.sh",
    "content": "#!/bin/sh\nset -e\n\n# QEMU version and date string for easy maintenance\nQEMU_VERSION=\"9.2.2\"\nQEMU_DATE=\"20250817\"\nQEMU_RELEASE=\"esp-develop-${QEMU_VERSION}-${QEMU_DATE}\"\n\n# 1. Detect host architecture\nARCH=$(uname -m)\ncase \"$ARCH\" in\n    x86_64)\n        QEMU_ARCH=\"x86_64\"\n        QEMU_RISCV32_FILE=\"qemu-riscv32-softmmu-esp_develop_${QEMU_VERSION}_${QEMU_DATE}-x86_64-linux-gnu.tar.xz\"\n        QEMU_XTENSA_FILE=\"qemu-xtensa-softmmu-esp_develop_${QEMU_VERSION}_${QEMU_DATE}-x86_64-linux-gnu.tar.xz\"\n        ;;\n    aarch64 | arm64)\n        QEMU_ARCH=\"aarch64\"\n        QEMU_RISCV32_FILE=\"qemu-riscv32-softmmu-esp_develop_${QEMU_VERSION}_${QEMU_DATE}-aarch64-linux-gnu.tar.xz\"\n        QEMU_XTENSA_FILE=\"qemu-xtensa-softmmu-esp_develop_${QEMU_VERSION}_${QEMU_DATE}-aarch64-linux-gnu.tar.xz\"\n        ;;\n    *)\n        echo \"Unsupported architecture: $ARCH\"\n        exit 1\n        ;;\nesac\n\n# Install some dependencies\napt-get update\napt-get install -y libgcrypt20 libglib2.0-0 libpixman-1-0 libsdl2-2.0-0 libslirp0\n\nQEMU_DIR=\"qemu\"\n\n# 2. Download the correct binary\nQEMU_RISCV32_URL=\"https://github.com/espressif/qemu/releases/download/${QEMU_RELEASE}/$QEMU_RISCV32_FILE\"\ncurl -LO \"$QEMU_RISCV32_URL\"\n# 3. Extract the compressed file\ntar -xJf \"$QEMU_RISCV32_FILE\"\nrm \"$QEMU_RISCV32_FILE\"\n\nif [ -f \"$QEMU_DIR/bin/qemu-system-riscv32\" ]; then\n    echo \"QEMU RISCV32 installation successful.\"\nelse\n    echo \"QEMU RISCV32 installation failed.\"\n    exit 1\nfi\n# Rename qemu directory to avoid conflicts\nmv \"$QEMU_DIR\" \"${QEMU_DIR}_riscv32\"\n\nQEMU_XTENSA_URL=\"https://github.com/espressif/qemu/releases/download/${QEMU_RELEASE}/$QEMU_XTENSA_FILE\"\ncurl -LO \"$QEMU_XTENSA_URL\"\n# 3. Extract the compressed file\ntar -xJf \"$QEMU_XTENSA_FILE\"\nrm \"$QEMU_XTENSA_FILE\"\n\nif [ -f \"$QEMU_DIR/bin/qemu-system-xtensa\" ]; then\n    echo \"QEMU XTENSA installation successful.\"\nelse\n    echo \"QEMU XTENSA installation failed.\"\n    exit 1\nfi\n\n# Rename qemu directory to avoid conflicts\nmv \"$QEMU_DIR\" \"${QEMU_DIR}_xtensa\"\n\nQEMU_DIR=$(pwd)/qemu\n# 4. Add both QEMU directories to PATH\nexport PATH=\"$PATH:${QEMU_DIR}_riscv32/bin:${QEMU_DIR}_xtensa/bin\"\n# 5. Verify QEMU installation\nif command -v qemu-system-xtensa &> /dev/null; then\n    echo \"QEMU XTENSA is installed and available in PATH.\"\nelse\n    echo \"QEMU XTENSA is not installed or not available in PATH.\"\n    exit 1\nfi\nif command -v qemu-system-riscv32 &> /dev/null; then\n    echo \"QEMU RISCV32 is installed and available in PATH.\"\nelse\n    echo \"QEMU RISCV32 is not installed or not available in PATH.\"\n    exit 1\nfi\n"
  },
  {
    "path": ".github/workflows/build_and_run_apps.yml",
    "content": "name: Build and Run Apps\n\non:\n  schedule:\n    - cron: '0 0 * * *' # Once per day at midnight\n  pull_request:\n    types: [opened, reopened, synchronize]\n  push:\n    branches:\n      - master\n\njobs:\n  prepare:\n    name: Prepare pipeline\n    runs-on: ubuntu-22.04\n    permissions:\n      contents: read\n      pull-requests: read\n    outputs:\n      test_all_apps: ${{ steps.get_labels.outputs.test_all_apps }}\n      build_only: ${{ steps.get_labels.outputs.build_only }}\n      idf_build_apps_args: ${{ steps.find_changes.outputs.idf_build_apps_args }}\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          submodules: 'true'\n      - name: Fix git repo permissions\n        # Needed by the next git diff step.\n        # See https://github.com/actions/runner/issues/2033\n        if: github.event_name == 'pull_request'\n        run: |\n          build_dir=$PWD\n          cd /\n          git config --global --add safe.directory $build_dir\n          cd -\n      - name: Install dependencies\n        run: pip install 'idf-build-apps~=2.12'\n      - name: Get labels\n        id: get_labels\n        if: github.event_name == 'pull_request'\n        env:\n          GH_TOKEN: ${{ github.token }}\n        # Check for labels\n        # \"PR: test all apps\"\n        # \"PR: build only\"\n        run: |\n          gh api --jq '.labels.[].name' /repos/{owner}/{repo}/pulls/${{ github.event.number }} > labels.txt\n          test_all_apps=$(grep -c 'PR: test all apps' labels.txt || true)\n          build_only=$(grep -c 'PR: build only' labels.txt || true)\n          echo \"test_all_apps=$test_all_apps\" >> $GITHUB_OUTPUT\n          echo \"build_only=$build_only\" >> $GITHUB_OUTPUT\n          echo \"test_all_apps=$test_all_apps\"\n          echo \"build_only=$build_only\"\n\n      - name: Find changed files and components\n        id: find_changes\n        if: github.event_name == 'pull_request' && steps.get_labels.outputs.test_all_apps == '0'\n        # - based on the files list, determine which components have changed\n        # - output both lists as a file of idf-build-apps arguments\n        run: |\n          git fetch --recurse-submodules=no origin ${{ github.base_ref }}:base_ref\n          git fetch --recurse-submodules=no origin pull/${{ github.event.pull_request.number }}/head:pr_ref\n          git diff --name-only -r base_ref pr_ref > changed_files.txt\n          python3 .github/get_idf_build_apps_args.py -v changed_files.txt idf_build_apps_args.txt\n          echo \"idf_build_apps_args=$(cat idf_build_apps_args.txt)\" >> $GITHUB_OUTPUT\n          echo \"idf_build_apps_args=$(cat idf_build_apps_args.txt)\"\n\n  build:\n    name: Build Apps\n    needs: prepare\n    strategy:\n      fail-fast: false\n      matrix:\n        idf_ver:\n          - \"release-v5.1\"\n          - \"release-v5.2\"\n          - \"release-v5.3\"\n          - \"release-v5.4\"\n          - \"release-v5.5\"\n          - \"latest\"\n        parallel_index: [1,2,3,4,5] # Update --parallel-count below when changing this\n    runs-on: ubuntu-22.04\n    container: espressif/idf:${{ matrix.idf_ver }}\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          submodules: 'true'\n      - name: Install dependencies\n        shell: bash\n        run: |\n          export IDF_PYTHON_CHECK_CONSTRAINTS=yes\n          ${IDF_PATH}/install.sh --enable-ci\n          . ${IDF_PATH}/export.sh\n          pip install --upgrade 'idf-build-apps~=2.12'\n      - name: Build apps\n        shell: bash\n        run: |\n          . ${IDF_PATH}/export.sh\n          export PEDANTIC_FLAGS=\"-DIDF_CI_BUILD -Werror -Werror=deprecated-declarations -Werror=unused-variable -Werror=unused-but-set-variable -Werror=unused-function\"\n          export EXTRA_CFLAGS=\"${PEDANTIC_FLAGS} -Wstrict-prototypes\"\n          export EXTRA_CXXFLAGS=\"${PEDANTIC_FLAGS}\"\n          idf-build-apps build --parallel-index ${{ matrix.parallel_index }} --parallel-count 5 --collect-app-info build_info_${{ matrix.idf_ver }}_${{ matrix.parallel_index }}.json ${{ needs.prepare.outputs.idf_build_apps_args }}\n      - uses: actions/upload-artifact@v4\n        if: github.repository_owner == 'espressif' && needs.prepare.outputs.build_only == '0'\n        with:\n          name: app_binaries_${{ matrix.idf_ver }}_${{ matrix.parallel_index }}\n          path: |\n            */examples/*/build_esp*/bootloader/bootloader.bin\n            */examples/*/build_esp*/partition_table/partition-table.bin\n            */examples/*/build_esp*/*.bin\n            */examples/*/build_esp*/flasher_args.json\n            */examples/*/build_esp*/config/sdkconfig.json\n            */test_app*/**/build_esp*/bootloader/bootloader.bin\n            */test_app*/**/build_esp*/partition_table/partition-table.bin\n            */test_app*/**/build_esp*/*.bin\n            */test_app*/**/build_esp*/flasher_args.json\n            */test_app*/**/build_esp*/config/sdkconfig.json\n            build_info*.json\n\n  build-linux:\n    name: Build Apps for Linux\n    needs: prepare\n    strategy:\n      fail-fast: false\n      matrix:\n        idf_ver:\n          # Not building for 5.1 with linux target due to limited support\n          - \"release-v5.2\"\n          - \"release-v5.3\"\n          - \"release-v5.4\"\n          - \"release-v5.5\"\n          - \"latest\"\n    runs-on: ubuntu-22.04\n    container:\n      image: espressif/idf:${{ matrix.idf_ver }}\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          submodules: 'true'\n      - name: Install dependencies\n        shell: bash\n        run: |\n          export IDF_PYTHON_CHECK_CONSTRAINTS=yes\n          ${IDF_PATH}/install.sh --enable-ci\n          . ${IDF_PATH}/export.sh\n          pip install --upgrade 'idf-build-apps~=2.12'\n      - name: Build apps for Linux\n        shell: bash\n        run: |\n          . ${IDF_PATH}/export.sh\n          export PEDANTIC_FLAGS=\"-DIDF_CI_BUILD -Werror -Werror=deprecated-declarations -Werror=unused-variable -Werror=unused-but-set-variable -Werror=unused-function\"\n          export EXTRA_CFLAGS=\"${PEDANTIC_FLAGS} -Wstrict-prototypes\"\n          export EXTRA_CXXFLAGS=\"${PEDANTIC_FLAGS}\"\n          idf-build-apps build --target linux --collect-app-info build_info_linux_${{ matrix.idf_ver }}_${{ matrix.parallel_index }}.json ${{ needs.prepare.outputs.idf_build_apps_args }}\n      - uses: actions/upload-artifact@v4\n        if: github.repository_owner == 'espressif' && needs.prepare.outputs.build_only == '0'\n        with:\n          name: app_binaries_${{ matrix.idf_ver }}_linux\n          path: |\n            */examples/*/build_linux*/*.elf\n            */examples/*/build_linux*/config/sdkconfig.json\n            */test_app*/**/build_linux*/*.elf\n            */test_app*/**/build_linux*/config/sdkconfig.json\n            */host_test/**/build_linux*/*.elf\n            */host_test/**/build_linux*/config/sdkconfig.json\n            build_info*.json\n\n  run-target:\n    name: Run apps on target\n    if: github.repository_owner == 'espressif' && needs.prepare.outputs.build_only != '1'\n    needs: [build]\n    strategy:\n      fail-fast: false\n      matrix:\n        idf_ver:\n          - \"release-v5.1\"\n          - \"release-v5.2\"\n          - \"release-v5.3\"\n          - \"release-v5.4\"\n          - \"release-v5.5\"\n          - \"latest\"\n        runner:\n          - runs-on: \"esp32\"\n            marker: \"generic\"\n            target: \"esp32\"\n            runner-labels: [self-hosted, linux, docker, \"esp32\"]\n            pytest_args: \"\"\n          - runs-on: \"esp32s2\"\n            marker: \"generic\"\n            target: \"esp32s2\"\n            runner-labels: [self-hosted, linux, docker, \"esp32s2\"]\n            pytest_args: \"\"\n          - runs-on: \"esp32s3\"\n            marker: \"generic\"\n            target: \"esp32s3\"\n            runner-labels: [self-hosted, linux, docker, \"esp32s3\"]\n            pytest_args: \"\"\n          - runs-on: \"ESP32-ETHERNET-KIT\"\n            marker: \"ethernet\"\n            target: \"esp32\"\n            runner-labels: [self-hosted, linux, docker, \"ESP32-ETHERNET-KIT\"]\n            pytest_args: \"\"\n          - runs-on: \"spi_nand_flash\"\n            marker: \"spi_nand_flash\"\n            target: \"esp32\"\n            runner-labels: [self-hosted, linux, docker, \"spi_nand_flash\"]\n            pytest_args: \"\"\n          - runs-on: \"qemu\"\n            marker: \"qemu\"\n            target: [\"esp32s3\", \"esp32c3\"]\n            runner-labels: [self-hosted, linux, docker]\n            pytest_args: \"--embedded-services idf,qemu\"\n    env:\n      TEST_RESULT_NAME: test_results_${{ matrix.runner.target }}_${{ matrix.runner.marker }}_${{ matrix.idf_ver }}\n      TEST_RESULT_FILE: test_results_${{ matrix.runner.target }}_${{ matrix.runner.marker }}_${{ matrix.idf_ver }}.xml\n    runs-on: ${{ matrix.runner.runner-labels }}\n    container:\n      image: python:3.11-bookworm\n      options: --privileged # Privileged mode has access to serial ports\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/download-artifact@v4\n        with:\n          pattern: app_binaries_${{ matrix.idf_ver }}_*\n          merge-multiple: true\n      - name: Install Python packages\n        env:\n          PIP_EXTRA_INDEX_URL: \"https://dl.espressif.com/pypi/\"\n        run: |\n          pip install --prefer-binary cryptography pytest-embedded pytest-embedded-qemu pytest-embedded-serial-esp pytest-embedded-idf pytest-custom_exit_code idf-ci\n      - name: Setup QEMU\n        if: matrix.runner.marker == 'qemu'\n        run: |\n          . .github/setup_qemu.sh\n          echo \"PATH=$PATH\" >> $GITHUB_ENV\n      - name: Run apps\n        run: |\n          python3 .github/get_pytest_args.py --target=${{ matrix.runner.target }} -v 'build_info*.json' pytest-args.txt\n          cat pytest-args.txt\n          pytest --suppress-no-test-exit-code $(cat pytest-args.txt) --ignore-glob '*/managed_components/*' --ignore=.github --junit-xml=${{ env.TEST_RESULT_FILE }} --target=${{ matrix.runner.target }} -m ${{ matrix.runner.marker }} --build-dir=build_${{ matrix.runner.target }} ${{ matrix.runner.pytest_args }}\n      - name: Upload test results\n        uses: actions/upload-artifact@v4\n        if: always()\n        with:\n          name: ${{ env.TEST_RESULT_NAME }}\n          path: ${{ env.TEST_RESULT_FILE }}\n\n  run-target-linux:\n    name: Run apps on Linux target\n    if: github.repository_owner == 'espressif' && needs.prepare.outputs.build_only != '1'\n    needs: [build-linux]\n    strategy:\n      fail-fast: false\n      matrix:\n        idf_ver:\n          # - \"release-v5.1\" # Not testing for 5.1 with linux target due to limited support\n          - \"release-v5.2\"\n          - \"release-v5.3\"\n          - \"release-v5.4\"\n          - \"release-v5.5\"\n          - \"latest\"\n        runner:\n          - runs-on: \"linux\"\n            marker: \"host_test\"\n            target: \"linux\"\n            pytest_args: \"--embedded-services idf\"\n        exclude:\n          - idf_ver: \"release-v5.2\" # Bug with Unity IDF test apps\n            runner:\n              target: \"linux\"\n    env:\n      TEST_RESULT_NAME: test_results_${{ matrix.runner.target }}_${{ matrix.runner.marker }}_${{ matrix.idf_ver }}\n      TEST_RESULT_FILE: test_results_${{ matrix.runner.target }}_${{ matrix.runner.marker }}_${{ matrix.idf_ver }}.xml\n    runs-on: ubuntu-latest\n    container:\n      image: python:3.14-slim-trixie # Newer Debian base to support newer glibc for Linux apps\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/download-artifact@v4\n        with:\n          pattern: app_binaries_${{ matrix.idf_ver }}_*\n          merge-multiple: true\n      - name: Install Python packages\n        env:\n          PIP_EXTRA_INDEX_URL: \"https://dl.espressif.com/pypi/\"\n        run: |\n          pip install --prefer-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf pytest-custom_exit_code idf-ci\n      - name: Make .elf files executable\n        if: matrix.runner.target == 'linux'\n        continue-on-error: true\n        shell: bash\n        run: |\n          chmod +x */examples/*/build_linux*/*.elf || echo \"No example .elf files found\"\n          shopt -s globstar\n          chmod +x */test_app*/**/build_linux*/*.elf || echo \"No test_app .elf files found\"\n          chmod +x */host_test/**/build_linux*/*.elf || echo \"No host_test .elf files found\"\n      - name: Run apps\n        shell: bash\n        run: |\n          python3 .github/get_pytest_args.py --target=${{ matrix.runner.target }} -v 'build_info*.json' pytest-args.txt\n          cat pytest-args.txt\n          pytest --suppress-no-test-exit-code $(cat pytest-args.txt) --ignore-glob '*/managed_components/*' --ignore=.github --junit-xml=${{ env.TEST_RESULT_FILE }} --target=${{ matrix.runner.target }} -m ${{ matrix.runner.marker }} --build-dir=build_${{ matrix.runner.target }} ${{ matrix.runner.pytest_args }}\n      - name: Upload test results\n        uses: actions/upload-artifact@v4\n        if: always()\n        with:\n          name: ${{ env.TEST_RESULT_NAME }}\n          path: ${{ env.TEST_RESULT_FILE }}\n\n  publish-results:\n    name: Publish Test results\n    needs:\n      - run-target\n      - run-target-linux\n    if: github.repository_owner == 'espressif' && always() && github.event_name == 'pull_request' && needs.prepare.outputs.build_only == '0'\n    runs-on: ubuntu-22.04\n    permissions:\n      checks: write\n      pull-requests: write\n    steps:\n      - name: Download Test results\n        uses: actions/download-artifact@v4\n        with:\n          pattern: test_results_*\n          path: test_results\n      - name: Publish Test Results\n        uses: EnricoMi/publish-unit-test-result-action@v2\n        with:\n          files: test_results/**/*.xml\n"
  },
  {
    "path": ".github/workflows/clang-tidy.yml",
    "content": "name: Run clang-tidy\n\non:\n  pull_request:\n    types: [opened, reopened, synchronize]\n  push:\n    branches:\n      - master\n\npermissions:\n  contents: read\n  security-events: write\n\njobs:\n  build:\n    name: Run clang-tidy\n    runs-on: ubuntu-24.04\n    container: espressif/idf:latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          submodules: 'true'\n      - name: Install esp-clang\n        run: |\n          ${IDF_PATH}/tools/idf_tools.py --non-interactive install esp-clang\n      - name: Install clang-tidy-sarif\n        run: |\n          curl -sSL https://github.com/psastras/sarif-rs/releases/download/clang-tidy-sarif-v0.8.0/clang-tidy-sarif-x86_64-unknown-linux-gnu -o clang-tidy-sarif\n          chmod +x clang-tidy-sarif\n      - name: Install pyclang\n        shell: bash\n        run: |\n          . ${IDF_PATH}/export.sh\n          pip install pyclang~=0.2.0\n      - name: Run code analysis\n        shell: bash\n        env:\n          IDF_TOOLCHAIN: clang\n          IDF_TARGET: esp32\n        working-directory: .github/clang-tidy/test_app\n        run: |\n          . ${IDF_PATH}/export.sh\n          idf.py reconfigure\n          idf.py clang-check @build/clang_check_args --run-clang-tidy-py run-clang-tidy\n          cp warnings.txt ${GITHUB_WORKSPACE}/warnings.txt\n      - name: Convert clang-tidy results into SARIF output\n        run: |\n          export PATH=$PWD:$PATH\n          ./clang-tidy-sarif -o results.sarif.raw -i warnings.txt\n          # Remove warnings which recommend using functions not supported in newlib.\n          python3 $GITHUB_WORKSPACE/.github/filter_sarif.py -o results.sarif \\\n            --include-prefix ${GITHUB_WORKSPACE}/ \\\n            --exclude-text-contains memset_s \\\n            --exclude-text-contains memmove_s \\\n            --exclude-text-contains memcpy_s \\\n            --exclude-text-contains fprintf_s \\\n            --exclude-text-contains snprintf_s \\\n            --exclude-text-contains strncpy_s \\\n            --exclude-text-contains sscanf_s \\\n            results.sarif.raw\n      - uses: actions/upload-artifact@v4\n        with:\n          path: |\n            warnings.txt\n            results.sarif\n            results.sarif.raw\n      - name: Upload SARIF file\n        uses: github/codeql-action/upload-sarif@v4\n        with:\n          sarif_file: results.sarif\n          category: clang-tidy\n"
  },
  {
    "path": ".github/workflows/deploy_gh_pages.yml",
    "content": "name: Build and Deploy Programming Guides\n\non:\n  push:\n    branches: [master]\n  pull_request:\n    branches: [master]\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\n# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages\npermissions:\n  contents: read\n  pages: write\n  id-token: write\n\nconcurrency:\n  group: \"pages\"\n  cancel-in-progress: false\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout 🛎️\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - name: Setup mdBook 📥\n        uses: peaceiris/actions-mdbook@v2\n        with:\n          mdbook-version: \"latest\"\n\n      - name: Install doxygen tools 🧱\n        run: |-\n          sudo apt-get install -y doxygen\n          pip install esp-doxybook\n\n      - name: Build docs 🔧\n        run: |\n          version=\"latest\"\n          if [[ \"${{ github.event_name }}\" == \"pull_request\" ]]; then\n          version=\"pr-preview-${{ github.event.pull_request.number }}\"\n          fi\n          python3 ./.github/build_docs.py --version \"$version\" --output-dir \"docs_build_output\"\n\n      - name: Check Links 🔍\n        uses: lycheeverse/lychee-action@v2\n        with:\n          # Check links in docs_build_output\n          args: >-\n            --no-progress\n            --include-fragments\n            --root-dir docs_build_output\n            --exclude-path '.*/404\\.html$'\n            docs_build_output/**/*.html\n          # Fail the action if broken links are found\n          fail: true\n\n      # Create directory structure for GitHub Pages with \"version prefix\"\n      - name: Prepare files for deployment 📁\n        if: github.event_name == 'push' && github.ref == 'refs/heads/master'\n        run: |\n          version=\"latest\"\n          mkdir -p \"gh-pages/$version\"\n          cp -r docs_build_output/* \"gh-pages/$version/\"\n\n      - name: Upload Pages artifact 📤\n        if: github.event_name == 'push' && github.ref == 'refs/heads/master'\n        uses: actions/upload-pages-artifact@v3\n        with:\n          path: gh-pages\n\n  deploy:\n    if: github.event_name == 'push' && github.ref == 'refs/heads/master'\n    needs: build\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }}latest/\n    runs-on: ubuntu-latest\n    steps:\n      - name: Setup Pages 📥\n        uses: actions/configure-pages@v5\n      - name: Deploy to GitHub Pages 🚀\n        id: deployment\n        uses: actions/deploy-pages@v4\n"
  },
  {
    "path": ".github/workflows/issue_comment.yml",
    "content": "name: Sync issue comments to JIRA\n\npermissions:\n  issues: write\n  pull-requests: write\n\n# This workflow will be triggered when new issue comment is created (including PR comments)\non: issue_comment\n\n# Limit to single concurrent run for workflows which can create Jira issues.\n# Same concurrency group is used in new_issues.yml\nconcurrency: jira_issues\n\njobs:\n  sync_issue_comments_to_jira:\n    name: Sync Issue Comments to Jira\n    runs-on: ubuntu-latest\n    if: ${{ github.repository_owner == 'espressif' }}\n    steps:\n      - uses: actions/checkout@v4\n      - name: Sync issue comments to JIRA\n        uses: espressif/github-actions/sync_issues_to_jira@master\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          JIRA_PASS: ${{ secrets.JIRA_PASS }}\n          JIRA_PROJECT: IEC\n          JIRA_URL: ${{ secrets.JIRA_URL }}\n          JIRA_USER: ${{ secrets.JIRA_USER }}\n"
  },
  {
    "path": ".github/workflows/new_issues.yml",
    "content": "name: Sync issues to Jira\n\npermissions:\n  issues: write\n\n# This workflow will be triggered when a new issue is opened\non: issues\n\n# Limit to single concurrent run for workflows which can create Jira issues.\n# Same concurrency group is used in issue_comment.yml\nconcurrency: jira_issues\n\njobs:\n  sync_issues_to_jira:\n    name: Sync issues to Jira\n    runs-on: ubuntu-latest\n    if: ${{ github.repository_owner == 'espressif' }}\n    steps:\n      - uses: actions/checkout@v4\n      - name: Sync GitHub issues to Jira project\n        uses: espressif/github-actions/sync_issues_to_jira@master\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          JIRA_PASS: ${{ secrets.JIRA_PASS }}\n          JIRA_PROJECT: IEC\n          JIRA_URL: ${{ secrets.JIRA_URL }}\n          JIRA_USER: ${{ secrets.JIRA_USER }}\n"
  },
  {
    "path": ".github/workflows/new_prs.yml",
    "content": "name: Sync remain PRs to Jira\n\npermissions:\n  pull-requests: write\n\n# This workflow will be triggered every hour, to sync remaining PRs (i.e. PRs with zero comment) to Jira project\n# Note that, PRs can also get synced when new PR comment is created\non:\n  schedule:\n    - cron: \"0 * * * *\"\n\n# Limit to single concurrent run for workflows which can create Jira issues.\n# Same concurrency group is used in issue_comment.yml\nconcurrency: jira_issues\n\njobs:\n  sync_prs_to_jira:\n    name: Sync PRs to Jira\n    runs-on: ubuntu-latest\n    if: ${{ github.repository_owner == 'espressif' }}\n    steps:\n      - uses: actions/checkout@v4\n      - name: Sync PRs to Jira project\n        uses: espressif/github-actions/sync_issues_to_jira@master\n        with:\n          cron_job: true\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          JIRA_PASS: ${{ secrets.JIRA_PASS }}\n          JIRA_PROJECT: IEC\n          JIRA_URL: ${{ secrets.JIRA_URL }}\n          JIRA_USER: ${{ secrets.JIRA_USER }}\n"
  },
  {
    "path": ".github/workflows/pre-commit.yml",
    "content": "name: pre-commit\n\non:\n  pull_request:\n    types: [opened, reopened, synchronize]\n\njobs:\n  pre-commit:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v4\n    - uses: actions/setup-python@v5\n    - uses: pre-commit/action@v3.0.1\n"
  },
  {
    "path": ".github/workflows/test_sbom.yml",
    "content": "name: Run SBOM manifests validation test\n\non:\n  pull_request:\n    types: [opened, reopened, synchronize]\n\njobs:\n  test_sbom:\n    name: Run SBOM manifests validation test\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n      - name: Validate SBOM manifests\n        run: |\n          git config --global safe.directory $(pwd)\n          pip install esp-idf-sbom\n          python3 -m esp_idf_sbom manifest validate\n"
  },
  {
    "path": ".github/workflows/upload_component.yml",
    "content": "name: Push components to Espressif Component Service\n\non:\n  # For pull requests: perform upload with \"--dry-run\" argument,\n  # i.e. validate that the component passes all checks for being uploaded.\n  pull_request:\n\n  # For pushes to master: actually upload the components to the registry.\n  push:\n    branches:\n      - master\n\njobs:\n  upload_components:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          submodules: 'recursive'\n      - run: |\n          echo \"${{ ( github.ref_name != 'master' || github.repository_owner != 'espressif' ) && 'Checking' || 'Uploading' }} components\"\n      - name: Upload components to component service\n        uses: espressif/upload-components-ci-action@v2\n        with:\n          components: |\n            argtable3\n            bdc_motor\n            catch2\n            cbor\n            ccomp_timer\n            cjson\n            coap\n            coremark\n            dhara\n            eigen\n            esp_daylight\n            esp_cli_commands\n            esp_delta_ota\n            esp_encrypted_img\n            esp_flash_dispatcher\n            esp_ext_part_tables\n            esp_gcov\n            esp_isotp\n            esp_lcd_qemu_rgb\n            esp_linenoise\n            esp_jpeg\n            esp_schedule\n            esp_cli\n            esp_serial_slave_link\n            esp_sysview\n            expat\n            fmt\n            freetype\n            iqmath\n            jsmn\n            json_generator\n            json_parser\n            led_strip\n            libsodium\n            network_provisioning\n            nghttp\n            onewire_bus\n            pcap\n            pid_ctrl\n            qrcode\n            quirc\n            sh2lib\n            spi_nand_flash\n            spi_nand_flash_fatfs\n            supertinycron\n            thorvg\n            touch_element\n            unit-test-app\n            zlib\n            libpng\n            libjpeg-turbo\n          namespace: \"espressif\"\n          # API token will only be available in the master branch in the main repository.\n          # However, dry-run doesn't require a valid token.\n          api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}\n          dry_run: ${{ github.ref_name != 'master' || github.repository_owner != 'espressif' }}\n"
  },
  {
    "path": ".github/workflows/vulnerability_scan.yml",
    "content": "name: Vulnerability scan\n\non:\n  schedule:\n    - cron: '0 0 * * *'\n  workflow_dispatch:\n\n\njobs:\n  vulnerability-scan:\n    name: Vulnerability scan\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v4\n        with:\n          submodules: recursive\n\n      - name: Vulnerability scan\n        env:\n          SBOM_CHECK_LOCAL_DB: ${{ vars.SBOM_CHECK_LOCAL_DB }}\n          SBOM_MATTERMOST_WEBHOOK: ${{ secrets.SBOM_MATTERMOST_WEBHOOK }}\n          NVDAPIKEY: ${{ secrets.NVDAPIKEY }}\n        uses: espressif/esp-idf-sbom-action@master\n"
  },
  {
    "path": ".gitignore",
    "content": "**/dist/**\n**/build*/**\n**/__pycache__/**\nsdkconfig\nsdkconfig.old\ndependencies.lock\n**/managed_components/**\n.vscode/\n.cache\n.DS_Store\nwarnings.txt\n# Ignore artifacts for documentation build\ndoxygen_output/\n**/docs/book/\ndocs_build_output/\npytest-args.txt\nbuild_info*.json"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"libsodium/libsodium\"]\n\tpath = libsodium/libsodium\n\turl = https://github.com/jedisct1/libsodium.git\n\n[submodule \"cbor/tinycbor\"]\n\tpath = cbor/tinycbor\n\turl = https://github.com/intel/tinycbor.git\n\n[submodule \"nghttp/nghttp2\"]\n\tpath = nghttp/nghttp2\n\turl = https://github.com/nghttp2/nghttp2.git\n\n[submodule \"expat/expat\"]\n\tpath = expat/expat\n\turl = https://github.com/libexpat/libexpat.git\n\n[submodule \"coap/libcoap\"]\n\tpath = coap/libcoap\n\turl = https://github.com/obgm/libcoap.git\n\n[submodule \"eigen/eigen\"]\n\tpath = eigen/eigen\n\turl = https://gitlab.com/libeigen/eigen.git\n\n[submodule \"fmt/fmt\"]\n\tpath = fmt/fmt\n\turl = https://github.com/fmtlib/fmt.git\n\n[submodule \"esp_delta_ota/detools\"]\n\tpath = esp_delta_ota/detools\n\turl = https://github.com/eerimoq/detools.git\n\n[submodule \"quirc/quirc\"]\n\tpath = quirc/quirc\n\turl = https://github.com/dlbeer/quirc.git\n\n[submodule \"zlib/zlib\"]\n\tpath = zlib/zlib\n\turl = https://github.com/madler/zlib.git\n\n[submodule \"libpng/libpng\"]\n\tpath = libpng/libpng\n\turl = https://github.com/glennrp/libpng.git\n\n[submodule \"coremark/coremark\"]\n\tpath = coremark/coremark\n\turl = https://github.com/eembc/coremark.git\n\n[submodule \"freetype/freetype\"]\n\tpath = freetype/freetype\n\turl = https://github.com/freetype/freetype.git\n\n[submodule \"catch2/Catch2\"]\n\tpath = catch2/Catch2\n\turl = https://github.com/catchorg/Catch2.git\n\n[submodule \"dhara/dhara\"]\n\tpath = dhara/dhara\n\turl = https://github.com/dlbeer/dhara.git\n\n[submodule \"supertinycron/supertinycron\"]\n\tpath = supertinycron/supertinycron\n\turl = https://github.com/exander77/supertinycron.git\n\n[submodule \"thorvg/thorvg\"]\n\tpath = thorvg/thorvg\n\turl = https://github.com/thorvg/thorvg\n\n[submodule \"libjpeg-turbo/libjpeg-turbo\"]\n\tpath = libjpeg-turbo/libjpeg-turbo\n\turl = https://github.com/libjpeg-turbo/libjpeg-turbo.git\n\n[submodule \"argtable3/argtable3\"]\n\tpath = argtable3/argtable3\n\turl = https://github.com/argtable/argtable3.git\n\n[submodule \"esp_isotp/isotp-c\"]\n\tpath = esp_isotp/isotp-c\n\turl = https://github.com/SimonCahill/isotp-c.git\n\n[submodule \"cjson/cJSON\"]\n\tpath = cjson/cJSON\n\turl = https://github.com/DaveGamble/cJSON.git\n"
  },
  {
    "path": ".idf_build_apps.toml",
    "content": "recursive = true\nexclude = [\n    \".github\",\n]\nmanifest_file = [\n    \"argtable3/.build-test-rules.yml\",\n    \"bdc_motor/.build-test-rules.yml\",\n    \"ccomp_timer/.build-test-rules.yml\",\n    \"coremark/.build-test-rules.yml\",\n    \"esp_daylight/.build-test-rules.yml\",\n    \"esp_delta_ota/.build-test-rules.yml\",\n    \"esp_cli_commands/.build-test-rules.yml\",\n    \"esp_encrypted_img/.build-test-rules.yml\",\n    \"esp_flash_dispatcher/.build-test-rules.yml\",\n    \"esp_gcov/.build-test-rules.yml\",\n    \"esp_jpeg/.build-test-rules.yml\",\n    \"esp_linenoise/.build-test-rules.yml\",\n    \"esp_schedule/.build-test-rules.yml\",\n    \"esp_cli/.build-test-rules.yml\",\n    \"esp_ext_part_tables/.build-test-rules.yml\",\n    \"esp_serial_slave_link/.build-test-rules.yml\",\n    \"esp_sysview/.build-test-rules.yml\",\n    \"expat/.build-test-rules.yml\",\n    \"iqmath/.build-test-rules.yml\",\n    \"esp_isotp/.build-test-rules.yml\",\n    \"jsmn/.build-test-rules.yml\",\n    \"json_generator/.build-test-rules.yml\",\n    \"json_parser/.build-test-rules.yml\",\n    \"libpng/.build-test-rules.yml\",\n    \"libsodium/.build-test-rules.yml\",\n    \"onewire_bus/.build-test-rules.yml\",\n    \"pcap/.build-test-rules.yml\",\n    \"pid_ctrl/.build-test-rules.yml\",\n    \"qrcode/.build-test-rules.yml\",\n    \"quirc/.build-test-rules.yml\",\n    \"thorvg/.build-test-rules.yml\",\n    \"touch_element/.build-test-rules.yml\",\n    \"zlib/.build-test-rules.yml\",\n    \"libjpeg-turbo/.build-test-rules.yml\",\n    \".build-test-rules.yml\",\n]\ncheck_warnings = true\n\n# build related options\nbuild_dir = \"build_@t_@w\"\nconfig_rules = [\n    'sdkconfig.ci=default',\n    'sdkconfig.ci.*=',\n]\nignore_warning_file = \".ignore_build_warnings.txt\"\n"
  },
  {
    "path": ".ignore_build_warnings.txt",
    "content": "DeprecationWarning: pkg_resources is deprecated as an API\nWARNING: The following Kconfig variables were used in \"if\" clauses\nWarning: Deprecated: Option '--flash_mode' is deprecated. Use '--flash-mode' instead.\nWarning: Deprecated: Option '--flash_freq' is deprecated. Use '--flash-freq' instead.\nWarning: Deprecated: Option '--flash_size' is deprecated. Use '--flash-size' instead.\n"
  },
  {
    "path": ".pre-commit-config.yaml",
    "content": "repos:\n-   repo: https://github.com/igrr/astyle_py.git\n    rev: v1.1.0\n    hooks:\n    -   id: astyle_py\n        args: ['--style=otbs', '--attach-namespaces', '--attach-classes', '--indent=spaces=4', '--convert-tabs', '--align-pointer=name', '--align-reference=name', '--keep-one-line-statements', '--pad-header', '--pad-oper']\n        exclude: 'network_provisioning/proto-c'\n-   repo: https://github.com/codespell-project/codespell\n    rev: v2.4.1\n    hooks:\n    -   id: codespell\n-   repo: local\n    hooks:\n    -   id: consistency_check\n        name: Repo consistency checks\n        language: python\n        entry: python .github/consistency_check.py\n        pass_filenames: false\n        additional_dependencies:\n            - \"toml; python_version < '3.11'\"\n            - pyyaml\n-   repo: https://github.com/espressif/esp-idf-kconfig.git\n    rev: v2.5.0\n    hooks:\n    -   id: check-kconfig-files\n    -   id: check-deprecated-kconfig-options\n"
  },
  {
    "path": "README.md",
    "content": "[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit)\n[![Build and Run Apps](https://github.com/espressif/idf-extra-components/actions/workflows/build_and_run_apps.yml/badge.svg?branch=master)](https://github.com/espressif/idf-extra-components/actions/workflows/build_and_run_apps.yml)\n[![Clang-Tidy](https://github.com/espressif/idf-extra-components/actions/workflows/clang-tidy.yml/badge.svg?branch=master)](https://github.com/espressif/idf-extra-components/security/code-scanning?query=is%3Aopen+branch%3Amaster)\n\n# ESP-IDF Extra Components\n\nThis repository is used to maintain various extra components for [ESP-IDF](https://github.com/espressif/esp-idf). These components can be installed from [ESP Component Registry](https://components.espressif.com/).\n\nMany of the components in this repository are wrappers around third-party libraries, such as zlib, libpng, etc. There are also various components developed by Espressif which don't currently fit into another repository (like [esp-protocols](https://github.com/espressif/esp-protocols), [esp-usb](https://github.com/espressif/esp-usb), [esp-iot-solution](https://github.com/espressif/esp-iot-solution), etc).\n\n## Related Projects\n\n- [ESP-IDF](https://github.com/espressif/esp-idf)\n- [ESP Component Registry](https://components.espressif.com/)\n- [IDF Component Manager](https://github.com/espressif/idf-component-manager)\n- [ESP IOT Solution](https://github.com/espressif/esp-iot-solution)\n- [ESP Protocols](https://github.com/espressif/esp-protocols)\n- [ESP USB](https://github.com/espressif/esp-usb)\n\n## Contribution\n\nWe welcome contributions to idf-extra-components repository!\n\nYou can contribute by fixing bugs, adding features, adding documentation or reporting an [issue](https://github.com/espressif/idf-extra-components/issues). We accept contributions via [Github Pull Requests](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests).\n\nBefore reporting an issue, make sure you've searched for a similar one that was already created.\n\n### Adding New Components\n\nPlease note that this repository is intended for components maintained by Espressif developers. If you don't work at Espressif and you'd like to publish a component to the ESP Component Registry, please set up a separate repository for your component. You can find more information about this in the [IDF Component Manager documentation](https://docs.espressif.com/projects/idf-component-manager/en/latest/). You can also check out the [talk about developing and publishing components](https://youtu.be/D86gQ4knUnc) from Espressif DevCon 2023. Feel free to [open an issue](https://github.com/espressif/idf-component-manager/issues) if you encounter any problem.\n"
  },
  {
    "path": "argtable3/.build-test-rules.yml",
    "content": "argtable3/test_apps/argtable_unit_tests:\n  disable:\n    - if: IDF_TARGET not in [\"esp32\", \"esp32c3\"]\n      reason: \"Sufficient to test on one Xtensa and one RISC-V target\"\n\nargtable3/test_apps/console_compat:\n  disable:\n    - if: IDF_TARGET not in [\"esp32\", \"esp32c3\"]\n      reason: \"Sufficient to test on one Xtensa and one RISC-V target\"\n"
  },
  {
    "path": "argtable3/CMakeLists.txt",
    "content": "# This creates a virtual include file with an \"argtable3\" subdirectory where\n# \"/argtable3/src/argtable3.h\" is copied. the virtual directory is then used as\n# the include folder. This is so we can keep including argtable3 header as follow:\n# #include \"argtable3/argtable3.h\"\nset(VIRTUAL_INCLUDE_DIR \"${CMAKE_BINARY_DIR}/virtual_include\")\nfile(MAKE_DIRECTORY \"${VIRTUAL_INCLUDE_DIR}/argtable3\")\nfile(COPY \"${COMPONENT_PATH}/argtable3/src/argtable3.h\"\n     DESTINATION \"${VIRTUAL_INCLUDE_DIR}/argtable3\")\n\n# list of C files under argtable3 source directory\nfile(GLOB iec_argtable3_srcs\n    \"${COMPONENT_PATH}/argtable3/src/*.c\"\n)\n\nidf_component_register(\n    SRCS ${iec_argtable3_srcs}\n    INCLUDE_DIRS \"${VIRTUAL_INCLUDE_DIR}\"\n)\n\n# Check if console component is in the build and has argtable3 sources.\n# If so, exclude console's argtable3 sources from compilation and make console\n# link against this managed argtable3 component instead.\nidf_build_get_property(build_components BUILD_COMPONENTS)\n\nif(\"console\" IN_LIST build_components)\n    # Get console component directory\n    idf_component_get_property(console_dir console COMPONENT_DIR)\n\n    # Check if console still has argtable3 sources (future-proofing)\n    if(EXISTS \"${console_dir}/argtable3\")\n\n        # List of argtable3 source files in console\n        file(GLOB console_argtable3_srcs\n            \"${console_dir}/argtable3/*.c\"\n        )\n\n        # Exclude these files from compilation by marking them as header-only\n        set_source_files_properties(${console_argtable3_srcs}\n            DIRECTORY ${console_dir}\n            PROPERTIES HEADER_FILE_ONLY ON)\n\n        # Make console link against this managed argtable3 component\n        idf_component_add_link_dependency(FROM console)\n    endif()\nendif()\n\ntarget_compile_definitions(${COMPONENT_LIB} PRIVATE\n        ARG_ENABLE_LOG=0\n        ARG_REPLACE_GETOPT=0\n)\n"
  },
  {
    "path": "argtable3/idf_component.yml",
    "content": "version: \"3.3.1~1\"\ndescription: \"Argtable3 - GNU-style command-line option parsing C library\"\nurl: https://github.com/espressif/idf-extra-components/tree/master/argtable3\ndocumentation: https://www.argtable.org/docs/\ndependencies:\n  idf: \">=5.1\"\nsbom:\n  manifests:\n    - path: sbom_argtable3.yml\n      dest: argtable3"
  },
  {
    "path": "argtable3/sbom_argtable3.yml",
    "content": "name: argtable3\nversion: 3.3.1\nsupplier: 'Organization: argtable'\ndescription: GNU-style command-line option parsing C library\nurl: https://github.com/argtable/argtable3/\nhash: b50c6c81f25eef8af51141678b333c55b661414d"
  },
  {
    "path": "argtable3/test_apps/argtable_unit_tests/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(argtable3_test)\n"
  },
  {
    "path": "argtable3/test_apps/argtable_unit_tests/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"test_argtable3.c\" \"test_main.c\"\n                    PRIV_INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES unity\n                    WHOLE_ARCHIVE)\n"
  },
  {
    "path": "argtable3/test_apps/argtable_unit_tests/main/idf_component.yml",
    "content": "dependencies:\n  espressif/argtable3:\n    version: \"*\"\n    override_path: \"../../..\"\n"
  },
  {
    "path": "argtable3/test_apps/argtable_unit_tests/main/test_argtable3.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <string.h>\n#include \"unity.h\"\n#include \"argtable3/argtable3.h\"\n\n/* helper macros */\n#define ARG_TABLE_FREE(tbl) arg_freetable((tbl), sizeof(tbl)/sizeof(tbl[0]))\n#define PARSE_ARGS(tbl, argc, argv) arg_parse((int)(argc), (char**)(argv), (void**)tbl)\n\n/*\n===================== ARG TYPES ===================== */\n\nTEST_CASE(\"argument constructors create valid structs\", \"[argtable3]\")\n{\n    arg_rem_t *argRem = arg_rem(NULL, \"comment\");\n    TEST_ASSERT_NOT_NULL(argRem);\n    free(argRem);\n\n    arg_lit_t *argLit0 = arg_lit0(\"v\", \"verbose\", \"Enable verbose\");\n    TEST_ASSERT_NOT_NULL(argLit0);\n    free(argLit0);\n\n    arg_lit_t *argLit1 = arg_lit1(\"f\", \"force\", \"Force operation\");\n    TEST_ASSERT_NOT_NULL(argLit1);\n    free(argLit1);\n\n\n    arg_int_t *argInt0 = arg_int0(\"i\", \"int\", \"<n>\", \"Optional int\");\n    TEST_ASSERT_NOT_NULL(argInt0);\n    free(argInt0);\n\n    arg_int_t *argInt1 = arg_int1(\"i\", \"int\", \"<n>\", \"Required int\");\n    TEST_ASSERT_NOT_NULL(argInt1);\n    free(argInt1);\n\n    arg_int_t *argIntn = arg_intn(\"i\", \"int\", \"<n>\", 0, 3, \"Multiple ints\");\n    TEST_ASSERT_NOT_NULL(argIntn);\n    free(argIntn);\n\n    arg_str_t *argStr0 = arg_str0(\"s\", \"str\", \"<str>\", \"Optional string\");\n    TEST_ASSERT_NOT_NULL(argStr0);\n    free(argStr0);\n\n    arg_str_t *argStr1 = arg_str1(\"s\", \"str\", \"<str>\", \"Required string\");\n    TEST_ASSERT_NOT_NULL(argStr1);\n    free(argStr1);\n\n    arg_str_t *argStrn = arg_strn(\"s\", \"str\", \"<str>\", 1, 3, \"Multi string\");\n    TEST_ASSERT_NOT_NULL(argStrn);\n    free(argStrn);\n\n    arg_file_t *argFile0 = arg_file0(\"f\", \"file\", \"<file>\", \"Optional file\");\n    TEST_ASSERT_NOT_NULL(argFile0);\n    free(argFile0);\n\n    arg_file_t *argFile1 = arg_file1(\"f\", \"file\", \"<file>\", \"Required file\");\n    TEST_ASSERT_NOT_NULL(argFile1);\n    free(argFile1);\n\n    arg_file_t *argFilen = arg_filen(\"f\", \"file\", \"<file>\", 1, 3, \"Multi file\");\n    TEST_ASSERT_NOT_NULL(argFilen);\n    free(argFilen);\n\n    arg_dbl_t *argDbl0 = arg_dbl0(\"d\", \"double\", \"<d>\", \"Optional double\");\n    TEST_ASSERT_NOT_NULL(argDbl0);\n    free(argDbl0);\n\n    arg_dbl_t *argDbl1 = arg_dbl1(\"d\", \"double\", \"<d>\", \"Required double\");\n    TEST_ASSERT_NOT_NULL(argDbl1);\n    free(argDbl1);\n\n    arg_dbl_t *argDbln = arg_dbln(\"d\", \"double\", \"<d>\", 1, 2, \"Multi double\");\n    TEST_ASSERT_NOT_NULL(argDbln);\n    free(argDbln);\n\n    arg_date_t *argDate0 = arg_date0(\"t\", \"time\", \"<date>\", \"%Y-%m-%d\", \"Optional date\");\n    TEST_ASSERT_NOT_NULL(argDate0);\n    free(argDate0);\n\n    arg_date_t *argDate1 = arg_date1(\"t\", \"time\", \"<date>\", \"%Y-%m-%d\", \"Required date\");\n    TEST_ASSERT_NOT_NULL(argDate1);\n    free(argDate1);\n\n    arg_rex_t *argRex0 = arg_rex0(\"r\", \"regex\", \"<expr>\", \"^[a-z]+$\", 0, \"Regex\");\n    TEST_ASSERT_NOT_NULL(argRex0);\n    free(argRex0);\n\n    arg_rex_t *argRex1 = arg_rex1(\"r\", \"regex\", \"<expr>\", \"^[a-z]+$\", 0, \"Regex\");\n    TEST_ASSERT_NOT_NULL(argRex1);\n    free(argRex1);\n\n    arg_end_t *argEnd = arg_end(5);\n    TEST_ASSERT_NOT_NULL(argEnd);\n    free(argEnd);\n\n}\n\nTEST_CASE(\"arg_int: parses optional integer\", \"[argtable3]\")\n{\n    char *argv[] = {\"prog\", \"-n\", \"100\"};\n    int argc = sizeof(argv) / sizeof(argv[0]);\n\n    struct arg_int *n = arg_int0(\"n\", \"number\", \"<n>\", \"An integer value\");\n    struct arg_end *end = arg_end(10);\n    void *argtable[] = {n, end};\n\n    TEST_ASSERT_EQUAL_INT(0, PARSE_ARGS(argtable, argc, argv));\n    TEST_ASSERT_EQUAL_INT(100, n->ival[0]);\n\n    ARG_TABLE_FREE(argtable);\n}\n\nTEST_CASE(\"arg_dbl: parses optional double\", \"[argtable3]\")\n{\n    char *argv[] = {\"prog\", \"-d\", \"3.1415\"};\n    int argc = sizeof(argv) / sizeof(argv[0]);\n\n    struct arg_dbl *d = arg_dbl0(\"d\", \"double\", \"<d>\", \"A double value\");\n    struct arg_end *end = arg_end(10);\n    void *argtable[] = {d, end};\n\n    TEST_ASSERT_EQUAL_INT(0, PARSE_ARGS(argtable, argc, argv));\n    TEST_ASSERT_FLOAT_WITHIN(0.0001, 3.1415, d->dval[0]);\n\n    ARG_TABLE_FREE(argtable);\n}\n\nTEST_CASE(\"arg_lit: parses literal flags\", \"[argtable3]\")\n{\n    char *argv[] = {\"prog\", \"-v\"};\n    int argc = sizeof(argv) / sizeof(argv[0]);\n\n    struct arg_lit *v = arg_lit0(\"v\", \"verbose\", \"Enable verbose output\");\n    struct arg_end *end = arg_end(10);\n    void *argtable[] = {v, end};\n\n    TEST_ASSERT_EQUAL_INT(0, PARSE_ARGS(argtable, argc, argv));\n    TEST_ASSERT_EQUAL_INT(1, v->count);\n\n    ARG_TABLE_FREE(argtable);\n}\n\nTEST_CASE(\"arg_str: parses string argument\", \"[argtable3]\")\n{\n    char *argv[] = {\"prog\", \"-s\", \"hello\"};\n    int argc = sizeof(argv) / sizeof(argv[0]);\n\n    struct arg_str *s = arg_str0(\"s\", \"string\", \"<str>\", \"A string\");\n    struct arg_end *end = arg_end(10);\n    void *argtable[] = {s, end};\n\n    TEST_ASSERT_EQUAL_INT(0, PARSE_ARGS(argtable, argc, argv));\n    TEST_ASSERT_EQUAL_STRING(\"hello\", s->sval[0]);\n\n    ARG_TABLE_FREE(argtable);\n}\n\nTEST_CASE(\"arg_file: parses file paths\", \"[argtable3]\")\n{\n    char *argv[] = {\"prog\", \"-f\", \"/tmp/test.txt\"};\n    int argc = sizeof(argv) / sizeof(argv[0]);\n\n    struct arg_file *f = arg_file0(\"f\", \"file\", \"<file>\", \"A file path\");\n    struct arg_end *end = arg_end(10);\n    void *argtable[] = {f, end};\n\n    TEST_ASSERT_EQUAL_INT(0, PARSE_ARGS(argtable, argc, argv));\n    TEST_ASSERT_EQUAL_STRING(\"/tmp/test.txt\", f->filename[0]);\n\n    ARG_TABLE_FREE(argtable);\n}\n\nTEST_CASE(\"arg_rex: validates regex input\", \"[argtable3]\")\n{\n    char *argv[] = {\"prog\", \"-r\", \"abc123\"};\n    int argc = sizeof(argv) / sizeof(argv[0]);\n\n    struct arg_rex *r = arg_rex0(\"r\", \"regex\", \"[a-z]+[0-9]+\", \"<re>\", 0, \"Regex\");\n    struct arg_end *end = arg_end(10);\n    void *argtable[] = {r, end};\n\n    TEST_ASSERT_EQUAL_INT(0, PARSE_ARGS(argtable, argc, argv));\n    TEST_ASSERT_EQUAL_STRING(\"abc123\", r->sval[0]);\n\n    ARG_TABLE_FREE(argtable);\n}\n\nTEST_CASE(\"arg_date: parses date-time string\", \"[argtable3]\")\n{\n    char *argv[] = {\"prog\", \"-t\", \"2025-06-27 12:00:00\"};\n    int argc = sizeof(argv) / sizeof(argv[0]);\n\n    struct arg_date *dt = arg_date0(\"t\", \"time\", \"%Y-%m-%d %H:%M:%S\", \"<date>\", \"DateTime\");\n    struct arg_end *end = arg_end(10);\n    void *argtable[] = {dt, end};\n\n    TEST_ASSERT_EQUAL_INT(0, PARSE_ARGS(argtable, argc, argv));\n    TEST_ASSERT_EQUAL_INT(2025 - 1900, dt->tmval[0].tm_year);\n    TEST_ASSERT_EQUAL_INT(5, dt->tmval[0].tm_mon);\n    TEST_ASSERT_EQUAL_INT(27, dt->tmval[0].tm_mday);\n    TEST_ASSERT_EQUAL_INT(12, dt->tmval[0].tm_hour);\n\n    ARG_TABLE_FREE(argtable);\n}\n\n/* ===================== API Tests ===================== */\n\nTEST_CASE(\"arg_print_syntax, glossary, and GNU glossary\", \"[argtable3]\")\n{\n    struct arg_lit *verbose = arg_lit0(\"v\", \"verbose\", \"Enable verbose output\");\n    struct arg_str *name = arg_str1(\"n\", \"name\", \"<name>\", \"Name is required\");\n    struct arg_end *end = arg_end(20);\n    void *argtable[] = {verbose, name, end};\n\n    char buf[256] = {0};\n    FILE *f = fmemopen(buf, sizeof(buf), \"w\");\n    TEST_ASSERT_NOT_NULL(f);\n\n    arg_print_syntaxv(f, argtable, \"\\n\");\n    fflush(f);\n    TEST_ASSERT_NOT_NULL(strstr(buf, \"[-v|--verbose]\"));\n    TEST_ASSERT_NOT_NULL(strstr(buf, \"-n|--name=<name>\"));\n\n    arg_print_glossary(f, argtable, \"%s %s\\n\");\n    fflush(f);\n    TEST_ASSERT_NOT_NULL(strstr(buf, \"-v, --verbose Enable verbose output\"));\n    TEST_ASSERT_NOT_NULL(strstr(buf, \"-n, --name=<name> Name is required\"));\n    fclose(f);\n\n    ARG_TABLE_FREE(argtable);\n}\n\nTEST_CASE(\"arg_print_errors prints expected message\", \"[argtable3]\")\n{\n    char *argv[] = {\"prog\"};\n    int argc = sizeof(argv) / sizeof(argv[0]);\n\n    struct arg_int *num = arg_int1(\"n\", NULL, \"<num>\", \"Required number\");\n    struct arg_end *end = arg_end(10);\n    void *argtable[] = {num, end};\n\n    int errors = arg_parse(argc, (char **)argv, argtable);\n    TEST_ASSERT_GREATER_THAN(0, errors);\n\n    char buf[256] = {0};\n    FILE *f = fmemopen(buf, sizeof(buf), \"w\");\n    TEST_ASSERT_NOT_NULL(f);\n    arg_print_errors(f, end, argv[0]);\n    fclose(f);\n    printf(\"%s\\n\", buf);\n    TEST_ASSERT_NOT_NULL(strstr(buf, \"missing option\"));\n\n    ARG_TABLE_FREE(argtable);\n}\n\nTEST_CASE(\"arg_print_option and arg_print_option_ds output\", \"[argtable3]\")\n{\n    char buf[128] = {0};\n    FILE *f = fmemopen(buf, sizeof(buf), \"w\");\n    TEST_ASSERT_NOT_NULL(f);\n    arg_print_option(f, \"f\", \"file\", \"<file>\", \"\\n\");\n    fclose(f);\n    TEST_ASSERT_NOT_NULL(strstr(buf, \"-f|--file=<file>\"));\n}\n\nTEST_CASE(\"returns errors for invalid input\", \"[argtable3]\")\n{\n    char *argv[] = {\"prog\", \"-i\", \"NaN\"};\n    int argc = sizeof(argv) / sizeof(argv[0]);\n\n    struct arg_int *i = arg_int1(\"i\", \"int\", \"<n>\", \"An integer\");\n    struct arg_end *end = arg_end(10);\n    void *argtable[] = {i, end};\n\n    int nerrors = PARSE_ARGS(argtable, argc, argv);\n    TEST_ASSERT_GREATER_THAN(0, nerrors);\n\n    char buf[128] = {0};\n    FILE *f = fmemopen(buf, sizeof(buf), \"w\");\n    TEST_ASSERT_NOT_NULL(f);\n    arg_print_errors(f, end, argv[0]);\n    fclose(f);\n    TEST_ASSERT_NOT_NULL(strstr(buf, \"invalid argument\"));\n\n    ARG_TABLE_FREE(argtable);\n}\n\nTEST_CASE(\"arg_parse, arg_nullcheck, arg_freetable basic flow\", \"[argtable3]\")\n{\n    char *argv[] = {\"prog\", \"-n\", \"123\"};\n    int argc = sizeof(argv) / sizeof(argv[0]);\n\n    struct arg_int *num = arg_int1(\"n\", NULL, \"<num>\", \"Required number\");\n    struct arg_end *end = arg_end(10);\n    void *argtable[] = {num, end};\n\n    TEST_ASSERT(0 == arg_nullcheck(argtable));\n    TEST_ASSERT_EQUAL_INT(0, arg_parse(argc, (char **)argv, argtable));\n    TEST_ASSERT_EQUAL_INT(123, num->ival[0]);\n\n    ARG_TABLE_FREE(argtable);\n}\n\nTEST_CASE(\"arg_parse: success and error cases\", \"[argtable3]\")\n{\n    // Success case\n    char *argv_success[] = {\"prog\", \"-n\", \"42\", \"--name\", \"ESP32\"};\n    int argc_success = sizeof(argv_success) / sizeof(argv_success[0]);\n\n    struct arg_int *num = arg_int1(\"n\", \"number\", \"<n>\", \"A required number\");\n    struct arg_str *name = arg_str0(NULL, \"name\", \"<name>\", \"An optional name\");\n    struct arg_end *end = arg_end(10);\n    void *argtable_success[] = {num, name, end};\n\n    int rc_success = arg_parse(argc_success, (char **)argv_success, argtable_success);\n    TEST_ASSERT_EQUAL_INT(0, rc_success);\n    TEST_ASSERT_EQUAL_INT(42, num->ival[0]);\n    TEST_ASSERT_EQUAL_STRING(\"ESP32\", name->sval[0]);\n\n    ARG_TABLE_FREE(argtable_success);\n\n    // Error case: missing required argument\n    char *argv_fail[] = {\"prog\", \"--name\", \"ESP32\"};\n    int argc_fail = sizeof(argv_fail) / sizeof(argv_fail[0]);\n\n    num = arg_int1(\"n\", \"number\", \"<n>\", \"A required number\");\n    name = arg_str0(NULL, \"name\", \"<name>\", \"An optional name\");\n    end = arg_end(10);\n    void *argtable_fail[] = {num, name, end};\n\n    int rc_fail = arg_parse(argc_fail, argv_fail, argtable_fail);\n    TEST_ASSERT_GREATER_THAN(0, rc_fail);\n\n    char buf[256] = {0};\n    FILE *f = fmemopen(buf, sizeof(buf), \"w\");\n    TEST_ASSERT_NOT_NULL(f);\n    arg_print_errors(f, end, argv_fail[0]);\n    fclose(f);\n    TEST_ASSERT_NOT_NULL(strstr(buf, \"missing option\"));\n\n    ARG_TABLE_FREE(argtable_fail);\n}\n"
  },
  {
    "path": "argtable3/test_apps/argtable_unit_tests/main/test_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"unity.h\"\n#include \"unity_test_runner.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_newlib.h\"\n#include \"unity_test_utils_memory.h\"\n\nvoid setUp(void)\n{\n    unity_utils_record_free_mem();\n}\n\nvoid tearDown(void)\n{\n    esp_reent_cleanup();    //clean up some of the newlib's lazy allocations\n    unity_utils_evaluate_leaks_direct(0);\n}\n\nvoid app_main(void)\n{\n    printf(\"Running argtable3 component tests\\n\");\n    unity_run_menu();\n}\n"
  },
  {
    "path": "argtable3/test_apps/argtable_unit_tests/pytest_argtable3.py",
    "content": "import pytest\nfrom pytest_embedded import Dut\n\n\n@pytest.mark.generic\ndef test_argtable3(dut: Dut) -> None:\n    dut.run_all_single_board_cases()\n"
  },
  {
    "path": "argtable3/test_apps/argtable_unit_tests/sdkconfig.defaults",
    "content": "CONFIG_ESP_TASK_WDT_EN=n"
  },
  {
    "path": "argtable3/test_apps/console_compat/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(console_compat)\n\nidf_build_get_property(python PYTHON)\nadd_custom_target(check_argtable_path ALL\n    COMMAND ${python} ${CMAKE_CURRENT_SOURCE_DIR}/check_argtable_path.py\n    ${CMAKE_CURRENT_BINARY_DIR}/console_compat.elf\n    ${CMAKE_CURRENT_SOURCE_DIR}/../../..\n    $ENV{IDF_PATH}\n    \"${_CMAKE_TOOLCHAIN_PREFIX}strings\"\n    DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/console_compat.elf\n)\n"
  },
  {
    "path": "argtable3/test_apps/console_compat/README.md",
    "content": "This test app verifies that if IDF's console component (which also contains argtable3 source) is built alongside argtable3 component, then the argtable3 code from this component is used.\n"
  },
  {
    "path": "argtable3/test_apps/console_compat/check_argtable_path.py",
    "content": "import argparse\nimport subprocess\nimport sys\nimport os\nimport re\n\n\ndef main():\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\"elf_file\", type=str, help=\"The ELF file to check\")\n    parser.add_argument(\"iec_path\", type=str, help=\"The path to the idf-extra-components directory\")\n    parser.add_argument(\"idf_path\", type=str, help=\"The path to the esp-idf directory\")\n    parser.add_argument(\"strings_program\", type=str, help=\"The program to use to extract strings from the ELF file (e.g. 'strings')\")\n    args = parser.parse_args()\n\n\n    # look for any files from argtable3 directory in 'strings app.elf'\n    # This is more generic and works regardless of which argtable3 functions are used\n    # Matches both IEC path (/argtable3/src/arg_*.c) and IDF path (/argtable3/arg_*.c)\n    strings_output = subprocess.check_output([args.strings_program, args.elf_file], encoding=\"utf-8\")\n    lines_with_argtable = [line for line in strings_output.splitlines() if re.search(r'/argtable3/(src/)?arg_\\w+\\.c', line)]\n\n    found_iec_path = False\n    found_idf_path = False\n    iec_files = []\n    idf_files = []\n\n    for line in lines_with_argtable:\n        if os.path.abspath(args.iec_path) in line:\n            found_iec_path = True\n            iec_files.append(line.strip())\n        if os.path.abspath(args.idf_path) in line:\n            found_idf_path = True\n            idf_files.append(line.strip())\n\n    print(\"Found argtable3 files from IEC:\", file=sys.stderr)\n    for f in iec_files:\n        print(f\"  {f}\", file=sys.stderr)\n    \n    print(\"Found argtable3 files from IDF:\", file=sys.stderr)\n    for f in idf_files:\n        print(f\"  {f}\", file=sys.stderr)\n\n    print(f\"\\nSummary - IDF files: {len(idf_files)}, IEC files: {len(iec_files)}\", file=sys.stderr)\n    if found_idf_path or not found_iec_path:\n        print(\"Error: argtable3 files were found in IDF or not found in IEC\", file=sys.stderr)\n        raise SystemExit(1)\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "argtable3/test_apps/console_compat/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"test_main.c\"\n                    PRIV_REQUIRES console)\n"
  },
  {
    "path": "argtable3/test_apps/console_compat/main/idf_component.yml",
    "content": "dependencies:\n  espressif/argtable3:\n    version: \"*\"\n    override_path: \"../../..\"\n"
  },
  {
    "path": "argtable3/test_apps/console_compat/main/test_main.c",
    "content": "#include \"esp_console.h\"\n\nvoid app_main(void)\n{\n    // call a function of console component which uses argtable3\n    esp_console_register_help_command();\n\n    // in CMakeLists.txt, we'll check the map file to make sure\n    // that the correct version of argtable3 functions was linked.\n}\n"
  },
  {
    "path": "bdc_motor/.build-test-rules.yml",
    "content": "bdc_motor/test_apps:\n  disable:\n    - if: SOC_MCPWM_SUPPORTED != 1\n      reason: Only MCPWM backend is implemented\n"
  },
  {
    "path": "bdc_motor/CHANGELOG.md",
    "content": "# Changelog\n\n## 0.2.0\n\n- Clean up the component dependency, don't depend on the `driver` component directly\n\n## 0.1.0\n\n- Initial version\n"
  },
  {
    "path": "bdc_motor/CMakeLists.txt",
    "content": "set(srcs \"src/bdc_motor.c\")\n\nif(CONFIG_SOC_MCPWM_SUPPORTED)\n    list(APPEND srcs \"src/bdc_motor_mcpwm_impl.c\")\nendif()\n\nif(\"${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}\" VERSION_GREATER_EQUAL \"5.3\")\n    set(priv_requires \"esp_driver_mcpwm\")\nelse()\n    set(priv_requires \"driver\")\nendif()\n\nidf_component_register(SRCS ${srcs}\n                       INCLUDE_DIRS \"include\" \"interface\"\n                       PRIV_REQUIRES ${priv_requires})\n"
  },
  {
    "path": "bdc_motor/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "bdc_motor/README.md",
    "content": "# Brushed DC Motor Control\n\n[![Component Registry](https://components.espressif.com/components/espressif/bdc_motor/badge.svg)](https://components.espressif.com/components/espressif/bdc_motor)\n\nThis directory contains an implementation for Brushed DC Motor by different peripherals. Currently only MCPWM is supported as the BDC motor backend.\n\nTo learn more about how to use this component, please check API Documentation from header file [bdc_motor.h](./include/bdc_motor.h).\n"
  },
  {
    "path": "bdc_motor/idf_component.yml",
    "content": "version: \"0.2.1\"\ndescription: Brushed DC Motor Control Driver\nurl: https://github.com/espressif/idf-extra-components/tree/master/bdc_motor\nrepository: https://github.com/espressif/idf-extra-components.git\nissues: https://github.com/espressif/idf-extra-components/issues\ndependencies:\n  idf: \">=5.0\"\n"
  },
  {
    "path": "bdc_motor/include/bdc_motor.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdint.h>\n#include \"esp_err.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief Brushed DC Motor handle\n */\ntypedef struct bdc_motor_t *bdc_motor_handle_t;\n\n/**\n * @brief Enable BDC motor\n *\n * @param motor: BDC Motor handle\n *\n * @return\n *      - ESP_OK: Enable motor successfully\n *      - ESP_ERR_INVALID_ARG: Enable motor failed because of invalid parameters\n *      - ESP_FAIL: Enable motor failed because other error occurred\n */\nesp_err_t bdc_motor_enable(bdc_motor_handle_t motor);\n\n/**\n * @brief Disable BDC motor\n *\n * @param motor: BDC Motor handle\n *\n * @return\n *      - ESP_OK: Disable motor successfully\n *      - ESP_ERR_INVALID_ARG: Disable motor failed because of invalid parameters\n *      - ESP_FAIL: Disable motor failed because other error occurred\n */\nesp_err_t bdc_motor_disable(bdc_motor_handle_t motor);\n\n/**\n * @brief Set speed for bdc motor\n *\n * @param motor: BDC Motor handle\n * @param speed: BDC speed\n *\n * @return\n *      - ESP_OK: Set motor speed successfully\n *      - ESP_ERR_INVALID_ARG: Set motor speed failed because of invalid parameters\n *      - ESP_FAIL: Set motor speed failed because other error occurred\n */\nesp_err_t bdc_motor_set_speed(bdc_motor_handle_t motor, uint32_t speed);\n\n/**\n * @brief Forward BDC motor\n *\n * @param motor: BDC Motor handle\n *\n * @return\n *      - ESP_OK: Forward motor successfully\n *      - ESP_FAIL: Forward motor failed because some other error occurred\n */\nesp_err_t bdc_motor_forward(bdc_motor_handle_t motor);\n\n/**\n * @brief Reverse BDC Motor\n *\n * @param strip: BDC Motor handle\n *\n * @return\n *      - ESP_OK: Reverse motor successfully\n *      - ESP_FAIL: Reverse motor failed because some other error occurred\n */\nesp_err_t bdc_motor_reverse(bdc_motor_handle_t motor);\n\n/**\n * @brief Stop motor in a coast way (a.k.a Fast Decay)\n *\n * @param motor: BDC Motor handle\n *\n * @return\n *      - ESP_OK: Stop motor successfully\n *      - ESP_FAIL: Stop motor failed because some other error occurred\n */\nesp_err_t bdc_motor_coast(bdc_motor_handle_t motor);\n\n/**\n * @brief Stop motor in a brake way (a.k.a Slow Decay)\n *\n * @param motor: BDC Motor handle\n *\n * @return\n *      - ESP_OK: Stop motor successfully\n *      - ESP_FAIL: Stop motor failed because some other error occurred\n */\nesp_err_t bdc_motor_brake(bdc_motor_handle_t motor);\n\n/**\n * @brief Free BDC Motor resources\n *\n * @param strip: BDC Motor handle\n *\n * @return\n *      - ESP_OK: Free resources successfully\n *      - ESP_FAIL: Free resources failed because error occurred\n */\nesp_err_t bdc_motor_del(bdc_motor_handle_t motor);\n\n/**\n * @brief BDC Motor Configuration\n */\ntypedef struct {\n    uint32_t pwma_gpio_num; /*!< BDC Motor PWM A gpio number */\n    uint32_t pwmb_gpio_num; /*!< BDC Motor PWM B gpio number */\n    uint32_t pwm_freq_hz;   /*!< PWM frequency, in Hz */\n} bdc_motor_config_t;\n\n/**\n * @brief BDC Motor MCPWM specific configuration\n */\ntypedef struct {\n    int group_id;           /*!< MCPWM group number */\n    uint32_t resolution_hz; /*!< MCPWM timer resolution */\n} bdc_motor_mcpwm_config_t;\n\n/**\n * @brief Create BDC Motor based on MCPWM peripheral\n *\n * @param motor_config: BDC Motor configuration\n * @param mcpwm_config: MCPWM specific configuration\n * @param ret_motor Returned BDC Motor handle\n * @return\n *      - ESP_OK: Create BDC Motor handle successfully\n *      - ESP_ERR_INVALID_ARG: Create BDC Motor handle failed because of invalid argument\n *      - ESP_ERR_NO_MEM: Create BDC Motor handle failed because of out of memory\n *      - ESP_FAIL: Create BDC Motor handle failed because some other error\n */\nesp_err_t bdc_motor_new_mcpwm_device(const bdc_motor_config_t *motor_config, const bdc_motor_mcpwm_config_t *mcpwm_config, bdc_motor_handle_t *ret_motor);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "bdc_motor/interface/bdc_motor_interface.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdint.h>\n#include \"esp_err.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct bdc_motor_t bdc_motor_t; /*!< Type of BDC motor */\n\n/**\n * @brief BDC motor interface definition\n */\nstruct bdc_motor_t {\n    /**\n     * @brief Enable BDC motor\n     *\n     * @param motor: BDC Motor handle\n     *\n     * @return\n     *      - ESP_OK: Enable motor successfully\n     *      - ESP_ERR_INVALID_ARG: Enable motor failed because of invalid parameters\n     *      - ESP_FAIL: Enable motor failed because other error occurred\n     */\n    esp_err_t (*enable)(bdc_motor_t *motor);\n\n    /**\n     * @brief Disable BDC motor\n     *\n     * @param motor: BDC Motor handle\n     *\n     * @return\n     *      - ESP_OK: Disable motor successfully\n     *      - ESP_ERR_INVALID_ARG: Disable motor failed because of invalid parameters\n     *      - ESP_FAIL: Disable motor failed because other error occurred\n     */\n    esp_err_t (*disable)(bdc_motor_t *motor);\n\n    /**\n     * @brief Set speed for bdc motor\n     *\n     * @param motor: BDC Motor handle\n     * @param speed: BDC speed\n     *\n     * @return\n     *      - ESP_OK: Set motor speed successfully\n     *      - ESP_ERR_INVALID_ARG: Set motor speed failed because of invalid parameters\n     *      - ESP_FAIL: Set motor speed failed because other error occurred\n     */\n    esp_err_t (*set_speed)(bdc_motor_t *motor, uint32_t speed);\n\n    /**\n     * @brief Forward BDC motor\n     *\n     * @param motor: BDC Motor handle\n     *\n     * @return\n     *      - ESP_OK: Forward motor successfully\n     *      - ESP_FAIL: Forward motor failed because some other error occurred\n     */\n    esp_err_t (*forward)(bdc_motor_t *motor);\n\n    /**\n     * @brief Reverse BDC Motor\n     *\n     * @param motor: BDC Motor handle\n     *\n     * @return\n     *      - ESP_OK: Reverse motor successfully\n     *      - ESP_FAIL: Reverse motor failed because some other error occurred\n     */\n    esp_err_t (*reverse)(bdc_motor_t *motor);\n\n    /**\n     * @brief Stop motor in a coast way (a.k.a Fast Decay)\n     *\n     * @param motor: BDC Motor handle\n     *\n     * @return\n     *      - ESP_OK: Stop motor successfully\n     *      - ESP_FAIL: Stop motor failed because some other error occurred\n     */\n    esp_err_t (*coast)(bdc_motor_t *motor);\n\n    /**\n     * @brief Stop motor in a brake way (a.k.a Slow Decay)\n     *\n     * @param motor: BDC Motor handle\n     *\n     * @return\n     *      - ESP_OK: Stop motor successfully\n     *      - ESP_FAIL: Stop motor failed because some other error occurred\n     */\n    esp_err_t (*brake)(bdc_motor_t *motor);\n\n    /**\n     * @brief Free BDC Motor handle resources\n     *\n     * @param motor: BDC Motor handle\n     *\n     * @return\n     *      - ESP_OK: Free resources successfully\n     *      - ESP_FAIL: Free resources failed because error occurred\n     */\n    esp_err_t (*del)(bdc_motor_t *motor);\n};\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "bdc_motor/src/bdc_motor.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include <stdlib.h>\n#include <string.h>\n#include <sys/cdefs.h>\n#include \"esp_log.h\"\n#include \"esp_check.h\"\n#include \"bdc_motor.h\"\n#include \"bdc_motor_interface.h\"\n\nstatic const char *TAG = \"bdc_motor\";\n\nesp_err_t bdc_motor_enable(bdc_motor_handle_t motor)\n{\n    ESP_RETURN_ON_FALSE(motor, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    return motor->enable(motor);\n}\n\nesp_err_t bdc_motor_disable(bdc_motor_handle_t motor)\n{\n    ESP_RETURN_ON_FALSE(motor, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    return motor->disable(motor);\n}\n\nesp_err_t bdc_motor_set_speed(bdc_motor_handle_t motor, uint32_t speed)\n{\n    ESP_RETURN_ON_FALSE(motor, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    return motor->set_speed(motor, speed);\n}\n\nesp_err_t bdc_motor_forward(bdc_motor_handle_t motor)\n{\n    ESP_RETURN_ON_FALSE(motor, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    return motor->forward(motor);\n}\n\nesp_err_t bdc_motor_reverse(bdc_motor_handle_t motor)\n{\n    ESP_RETURN_ON_FALSE(motor, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    return motor->reverse(motor);\n}\n\nesp_err_t bdc_motor_coast(bdc_motor_handle_t motor)\n{\n    ESP_RETURN_ON_FALSE(motor, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    return motor->coast(motor);\n}\n\nesp_err_t bdc_motor_brake(bdc_motor_handle_t motor)\n{\n    ESP_RETURN_ON_FALSE(motor, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    return motor->brake(motor);\n}\n\nesp_err_t bdc_motor_del(bdc_motor_handle_t motor)\n{\n    ESP_RETURN_ON_FALSE(motor, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    return motor->del(motor);\n}\n"
  },
  {
    "path": "bdc_motor/src/bdc_motor_mcpwm_impl.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include <stdlib.h>\n#include <string.h>\n#include <sys/cdefs.h>\n#include \"esp_log.h\"\n#include \"esp_check.h\"\n#include \"driver/mcpwm_prelude.h\"\n#include \"bdc_motor.h\"\n#include \"bdc_motor_interface.h\"\n\nstatic const char *TAG = \"bdc_motor_mcpwm\";\n\ntypedef struct {\n    bdc_motor_t base;\n    mcpwm_timer_handle_t timer;\n    mcpwm_oper_handle_t operator;\n    mcpwm_cmpr_handle_t cmpa;\n    mcpwm_cmpr_handle_t cmpb;\n    mcpwm_gen_handle_t gena;\n    mcpwm_gen_handle_t genb;\n} bdc_motor_mcpwm_obj;\n\nstatic esp_err_t bdc_motor_mcpwm_set_speed(bdc_motor_t *motor, uint32_t speed)\n{\n    bdc_motor_mcpwm_obj *mcpwm_motor = __containerof(motor, bdc_motor_mcpwm_obj, base);\n    ESP_RETURN_ON_ERROR(mcpwm_comparator_set_compare_value(mcpwm_motor->cmpa, speed), TAG, \"set compare value failed\");\n    ESP_RETURN_ON_ERROR(mcpwm_comparator_set_compare_value(mcpwm_motor->cmpb, speed), TAG, \"set compare value failed\");\n    return ESP_OK;\n}\n\nstatic esp_err_t bdc_motor_mcpwm_enable(bdc_motor_t *motor)\n{\n    bdc_motor_mcpwm_obj *mcpwm_motor = __containerof(motor, bdc_motor_mcpwm_obj, base);\n    ESP_RETURN_ON_ERROR(mcpwm_timer_enable(mcpwm_motor->timer), TAG, \"enable timer failed\");\n    ESP_RETURN_ON_ERROR(mcpwm_timer_start_stop(mcpwm_motor->timer, MCPWM_TIMER_START_NO_STOP), TAG, \"start timer failed\");\n    return ESP_OK;\n}\n\nstatic esp_err_t bdc_motor_mcpwm_disable(bdc_motor_t *motor)\n{\n    bdc_motor_mcpwm_obj *mcpwm_motor = __containerof(motor, bdc_motor_mcpwm_obj, base);\n    ESP_RETURN_ON_ERROR(mcpwm_timer_start_stop(mcpwm_motor->timer, MCPWM_TIMER_STOP_EMPTY), TAG, \"stop timer failed\");\n    ESP_RETURN_ON_ERROR(mcpwm_timer_disable(mcpwm_motor->timer), TAG, \"disable timer failed\");\n    return ESP_OK;\n}\n\nstatic esp_err_t bdc_motor_mcpwm_forward(bdc_motor_t *motor)\n{\n    bdc_motor_mcpwm_obj *mcpwm_motor = __containerof(motor, bdc_motor_mcpwm_obj, base);\n    ESP_RETURN_ON_ERROR(mcpwm_generator_set_force_level(mcpwm_motor->gena, -1, true), TAG, \"disable force level for gena failed\");\n    ESP_RETURN_ON_ERROR(mcpwm_generator_set_force_level(mcpwm_motor->genb, 0, true), TAG, \"set force level for genb failed\");\n    return ESP_OK;\n}\n\nstatic esp_err_t bdc_motor_mcpwm_reverse(bdc_motor_t *motor)\n{\n    bdc_motor_mcpwm_obj *mcpwm_motor = __containerof(motor, bdc_motor_mcpwm_obj, base);\n    ESP_RETURN_ON_ERROR(mcpwm_generator_set_force_level(mcpwm_motor->genb, -1, true), TAG, \"disable force level for genb failed\");\n    ESP_RETURN_ON_ERROR(mcpwm_generator_set_force_level(mcpwm_motor->gena, 0, true), TAG, \"set force level for gena failed\");\n    return ESP_OK;\n}\n\nstatic esp_err_t bdc_motor_mcpwm_coast(bdc_motor_t *motor)\n{\n    bdc_motor_mcpwm_obj *mcpwm_motor = __containerof(motor, bdc_motor_mcpwm_obj, base);\n    ESP_RETURN_ON_ERROR(mcpwm_generator_set_force_level(mcpwm_motor->gena, 0, true), TAG, \"set force level for gena failed\");\n    ESP_RETURN_ON_ERROR(mcpwm_generator_set_force_level(mcpwm_motor->genb, 0, true), TAG, \"set force level for genb failed\");\n    return ESP_OK;\n}\n\nstatic esp_err_t bdc_motor_mcpwm_brake(bdc_motor_t *motor)\n{\n    bdc_motor_mcpwm_obj *mcpwm_motor = __containerof(motor, bdc_motor_mcpwm_obj, base);\n    ESP_RETURN_ON_ERROR(mcpwm_generator_set_force_level(mcpwm_motor->gena, 1, true), TAG, \"set force level for gena failed\");\n    ESP_RETURN_ON_ERROR(mcpwm_generator_set_force_level(mcpwm_motor->genb, 1, true), TAG, \"set force level for genb failed\");\n    return ESP_OK;\n}\n\nstatic esp_err_t bdc_motor_mcpwm_del(bdc_motor_t *motor)\n{\n    bdc_motor_mcpwm_obj *mcpwm_motor = __containerof(motor, bdc_motor_mcpwm_obj, base);\n    mcpwm_del_generator(mcpwm_motor->gena);\n    mcpwm_del_generator(mcpwm_motor->genb);\n    mcpwm_del_comparator(mcpwm_motor->cmpa);\n    mcpwm_del_comparator(mcpwm_motor->cmpb);\n    mcpwm_del_operator(mcpwm_motor->operator);\n    mcpwm_del_timer(mcpwm_motor->timer);\n    free(mcpwm_motor);\n    return ESP_OK;\n}\n\nesp_err_t bdc_motor_new_mcpwm_device(const bdc_motor_config_t *motor_config, const bdc_motor_mcpwm_config_t *mcpwm_config, bdc_motor_handle_t *ret_motor)\n{\n    bdc_motor_mcpwm_obj *mcpwm_motor = NULL;\n    esp_err_t ret = ESP_OK;\n    ESP_GOTO_ON_FALSE(motor_config && mcpwm_config && ret_motor, ESP_ERR_INVALID_ARG, err, TAG, \"invalid argument\");\n    mcpwm_motor = calloc(1, sizeof(bdc_motor_mcpwm_obj));\n    ESP_GOTO_ON_FALSE(mcpwm_motor, ESP_ERR_NO_MEM, err, TAG, \"no mem for rmt motor\");\n\n    // mcpwm timer\n    mcpwm_timer_config_t timer_config = {\n        .group_id = mcpwm_config->group_id,\n        .clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,\n        .resolution_hz = mcpwm_config->resolution_hz,\n        .period_ticks = mcpwm_config->resolution_hz / motor_config->pwm_freq_hz,\n        .count_mode = MCPWM_TIMER_COUNT_MODE_UP,\n    };\n    ESP_GOTO_ON_ERROR(mcpwm_new_timer(&timer_config, &mcpwm_motor->timer), err, TAG, \"create MCPWM timer failed\");\n\n    mcpwm_operator_config_t operator_config = {\n        .group_id = mcpwm_config->group_id,\n    };\n    ESP_GOTO_ON_ERROR(mcpwm_new_operator(&operator_config, &mcpwm_motor->operator), err, TAG, \"create MCPWM operator failed\");\n\n    ESP_GOTO_ON_ERROR(mcpwm_operator_connect_timer(mcpwm_motor->operator, mcpwm_motor->timer), err, TAG, \"connect timer and operator failed\");\n\n    mcpwm_comparator_config_t comparator_config = {\n        .flags.update_cmp_on_tez = true,\n    };\n    ESP_GOTO_ON_ERROR(mcpwm_new_comparator(mcpwm_motor->operator, &comparator_config, &mcpwm_motor->cmpa), err, TAG, \"create comparator failed\");\n    ESP_GOTO_ON_ERROR(mcpwm_new_comparator(mcpwm_motor->operator, &comparator_config, &mcpwm_motor->cmpb), err, TAG, \"create comparator failed\");\n\n    // set the initial compare value for both comparators\n    mcpwm_comparator_set_compare_value(mcpwm_motor->cmpa, 0);\n    mcpwm_comparator_set_compare_value(mcpwm_motor->cmpb, 0);\n\n    mcpwm_generator_config_t generator_config = {\n        .gen_gpio_num = motor_config->pwma_gpio_num,\n    };\n    ESP_GOTO_ON_ERROR(mcpwm_new_generator(mcpwm_motor->operator, &generator_config, &mcpwm_motor->gena), err, TAG, \"create generator failed\");\n    generator_config.gen_gpio_num = motor_config->pwmb_gpio_num;\n    ESP_GOTO_ON_ERROR(mcpwm_new_generator(mcpwm_motor->operator, &generator_config, &mcpwm_motor->genb), err, TAG, \"create generator failed\");\n\n    mcpwm_generator_set_action_on_timer_event(mcpwm_motor->gena,\n            MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH));\n    mcpwm_generator_set_action_on_compare_event(mcpwm_motor->gena,\n            MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, mcpwm_motor->cmpa, MCPWM_GEN_ACTION_LOW));\n    mcpwm_generator_set_action_on_timer_event(mcpwm_motor->genb,\n            MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH));\n    mcpwm_generator_set_action_on_compare_event(mcpwm_motor->genb,\n            MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, mcpwm_motor->cmpb, MCPWM_GEN_ACTION_LOW));\n\n    mcpwm_motor->base.enable = bdc_motor_mcpwm_enable;\n    mcpwm_motor->base.disable = bdc_motor_mcpwm_disable;\n    mcpwm_motor->base.forward = bdc_motor_mcpwm_forward;\n    mcpwm_motor->base.reverse = bdc_motor_mcpwm_reverse;\n    mcpwm_motor->base.coast = bdc_motor_mcpwm_coast;\n    mcpwm_motor->base.brake = bdc_motor_mcpwm_brake;\n    mcpwm_motor->base.set_speed = bdc_motor_mcpwm_set_speed;\n    mcpwm_motor->base.del = bdc_motor_mcpwm_del;\n    *ret_motor = &mcpwm_motor->base;\n    return ESP_OK;\n\nerr:\n    if (mcpwm_motor) {\n        if (mcpwm_motor->gena) {\n            mcpwm_del_generator(mcpwm_motor->gena);\n        }\n        if (mcpwm_motor->genb) {\n            mcpwm_del_generator(mcpwm_motor->genb);\n        }\n        if (mcpwm_motor->cmpa) {\n            mcpwm_del_comparator(mcpwm_motor->cmpa);\n        }\n        if (mcpwm_motor->cmpb) {\n            mcpwm_del_comparator(mcpwm_motor->cmpb);\n        }\n        if (mcpwm_motor->operator) {\n            mcpwm_del_operator(mcpwm_motor->operator);\n        }\n        if (mcpwm_motor->timer) {\n            mcpwm_del_timer(mcpwm_motor->timer);\n        }\n        free(mcpwm_motor);\n    }\n    return ret;\n}\n"
  },
  {
    "path": "bdc_motor/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(bdc_motor_test)\n"
  },
  {
    "path": "bdc_motor/test_apps/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"bdc_motor_test.c\"\n                    INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES unity)\n"
  },
  {
    "path": "bdc_motor/test_apps/main/bdc_motor_test.c",
    "content": "#include <stdio.h>\n\nvoid app_main(void)\n{\n\n}\n"
  },
  {
    "path": "bdc_motor/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/bdc_motor:\n    version: \"*\"\n    override_path: \"../../\"\n"
  },
  {
    "path": "catch2/CMakeLists.txt",
    "content": "idf_component_register(SRCS cmd_catch2.cpp\n                       INCLUDE_DIRS include)\n\nset(CATCH_CONFIG_NO_POSIX_SIGNALS 1 CACHE BOOL OFF FORCE)\nadd_subdirectory(Catch2)\n\ntarget_link_libraries(${COMPONENT_LIB} PUBLIC Catch2::Catch2)\nget_target_property(catch_target Catch2::Catch2 ALIASED_TARGET)\n\n# Silence a warning in catch_exception_translator_registry.cpp\ntarget_compile_options(${catch_target} PRIVATE -Wno-unused-function)\n\n# Link to pthreads to avoid issues with STL headers\nidf_build_get_property(target IDF_TARGET)\nif(NOT target STREQUAL \"linux\")\n    target_link_libraries(${catch_target} PUBLIC idf::pthread)\n    # Work around a linking dependency issue in ESP-IDF\n    target_link_libraries(${COMPONENT_LIB} PUBLIC \"-Wl,-u getentropy\")\nendif()\n\n# If console component is present in the build, include the console\n# command feature. \nidf_build_get_property(build_components BUILD_COMPONENTS)\nif(\"console\" IN_LIST build_components)\n    target_compile_definitions(${COMPONENT_LIB} PRIVATE WITH_CONSOLE)\n    target_link_libraries(${COMPONENT_LIB} PUBLIC idf::console)\nendif()\n"
  },
  {
    "path": "catch2/LICENSE.txt",
    "content": "Boost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby granted, free of charge, to any person or organization\nobtaining a copy of the software and accompanying documentation covered by\nthis license (the \"Software\") to use, reproduce, display, distribute,\nexecute, and transmit the Software, and to prepare derivative works of the\nSoftware, and to permit third-parties to whom the Software is furnished to\ndo so, all subject to the following:\n\nThe copyright notices in the Software and this entire statement, including\nthe above license grant, this restriction and the following disclaimer,\nmust be included in all copies of the Software, in whole or in part, and\nall derivative works of the Software, unless such copies or derivative\nworks are solely in the form of machine-executable object code generated by\na source language processor.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\nSHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\nFOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "catch2/README.md",
    "content": "# Catch2 unit testing library\n\nThis component is an ESP-IDF wrapper around [Catch2 unit testing library](https://github.com/catchorg/Catch2).\n\nTests written using this component can be executed both on real hardware and on the host.\n\n## Using Catch2 in ESP-IDF\n\n### Example\n\nTo get started with Catch2 quickly, use the example provided along with this component:\n\n```bash\nidf.py create-project-from-example \"espressif/catch:catch2-test\"\ncd catch2-test\nidf.py set-target esp32\nidf.py build flash monitor\n```\n\nThe example can also be used on host (Linux):\n```bash\nidf.py --preview set-target linux\nidf.py build monitor\n```\n\n### Writing tests\n\nTests and assertions are written as usual for Catch2, refer to the [official documentation](https://github.com/catchorg/Catch2/tree/devel/docs) for more details. Here is a simple example:\n\n```c++\n#include <catch2/catch_test_macros.hpp>\n\nTEST_CASE(\"Test case 1\")\n{\n    REQUIRE(1 == 1);\n}\n```\n\nTo ensure the test cases are linked into the application, use `WHOLE_ARCHIVE` argument when calling `idf_component_register()` in CMake. For example:\n\n```cmake\nidf_component_register(SRCS \"test_main.cpp\"\n                            \"test_cases.cpp\"\n                       INCLUDE_DIRS \".\"\n                       WHOLE_ARCHIVE)\n\n```\n\n### Enabling C++ exceptions\n\nCatch2 relies on C++ exceptions for assertion handling. To get most benefits out of Catch2, it is recommended to have exceptions enabled in the project (`CONFIG_COMPILER_CXX_EXCEPTIONS=y`).\n\n### Stack size\n\nCatch2 uses significant amount of stack space — around 8kB, plus the stack space used by the test cases themselves. Therefore it is necessary to increase the stack size of the `main` task using the `CONFIG_ESP_MAIN_TASK_STACK_SIZE` option, or to invoke Catch from a new task with sufficient stack size. It is also recommended to keep `CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK` or `CONFIG_ESP_SYSTEM_HW_STACK_GUARD` options enabled to detect stack overflows.\n\n### Invoking the test runner\n\nCatch2 test framework can implement the application entry point (`main(int, char**)`) which calls the test runner. This functionality is typically used via the `CATCH_CONFIG_MAIN` macro. However ESP-IDF applications use `app_main(void)` function as an entry point, so the approach with `CATCH_CONFIG_MAIN` doesn't work.\n\n\nInstead, invoke Catch2 in your `app_main` as follows:\n\n```c++\n#include <catch2/catch_session.hpp>\n\nextern \"C\" void app_main(void)\n{\n    // prepare command line arguments to Catch2\n    const int argc = 1;\n    const char* argv[2] = {\"target_test_main\", NULL};\n\n    // run the tests\n    int result = Catch::Session().run(argc, argv);\n    // ... handle the result\n```\n\n### Integration with ESP-IDF `console` component\n\nThis component provides a function to register an ESP-IDF console command to invoke Catch2 test cases:\n```c++\nesp_err_t register_catch2(const char* cmd_name);\n```\n\nThis function registers a command with the specified name (for example, \"test\") with ESP-IDF `console` component. The command passes all the arguments to Catch2 test runner. This makes it possible to invoke tests from an interactive console running on an ESP chip.\n\nTo try this functionality, use `catch2-console` example:\n\n```bash\nidf.py create-project-from-example \"espressif/catch:catch2-console\"\ncd catch2-console\nidf.py set-target esp32\nidf.py build flash monitor\n```\n"
  },
  {
    "path": "catch2/cmd_catch2.cpp",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: BSL-1.0\n * Note: same license as Catch2\n */\n#include \"esp_err.h\"\n#if WITH_CONSOLE\n#include \"Catch2/src/catch2/catch_config.hpp\"\n#include \"esp_console.h\"\n#include \"catch2/catch_session.hpp\"\n#include \"cmd_catch2.h\"\n\nstatic int cmd_catch2(int argc, char **argv)\n{\n    static auto session = Catch::Session();\n    Catch::ConfigData configData;\n    session.useConfigData(configData);\n    return session.run(argc, argv);\n}\n\nextern \"C\" esp_err_t register_catch2(const char *cmd_name)\n{\n    esp_console_cmd_t cmd = {};\n    cmd.command = cmd_name,\n    cmd.help = \"Run tests\";\n    cmd.func = &cmd_catch2;\n    return esp_console_cmd_register(&cmd);\n}\n\n#else // WITH_CONSOLE\n// Defined to avoid ranlib warning on macOS\n// (the table of contents is empty (no object file members in the library define global symbols))\nextern \"C\" esp_err_t register_catch2(const char *cmd_name)\n{\n    return ESP_OK;\n}\n#endif // WITH_CONSOLE\n"
  },
  {
    "path": "catch2/examples/catch2-console/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\n\nproject(catch2-console)\n\n"
  },
  {
    "path": "catch2/examples/catch2-console/README.md",
    "content": "# Catch2 console example\n\nThis example shows how to combine Catch2 test framework with ESP-IDF `console` component.\n\nIn this example, you can execute test cases from an interactive console on an ESP chip.\n\n## Using the example\n\nTo run the example, build and flash the project as usual. For example, with an ESP32 chip:\n\n```bash\nidf.py set-target esp32\nidf.py build flash monitor\n```\n\nIn the console, use `test` command to invoke Catch2. `test` accepts the same command line arguments as Catch2 tests on the host:\n\n- `test -h` — prints command line argument reference\n- `test --list-tests` — lists all the registered tests\n- `test` — runs all the registered tests\n- `test <test name|pattern|tags>` — runs specific tests\n\n[See Catch2 documentation](https://github.com/catchorg/Catch2/blob/devel/docs/command-line.md) for the complete command line argument reference.\n"
  },
  {
    "path": "catch2/examples/catch2-console/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"test_main.cpp\"\n                            \"test_cases.cpp\"\n                       INCLUDE_DIRS \".\"\n                       WHOLE_ARCHIVE\n                       PRIV_REQUIRES console)\n"
  },
  {
    "path": "catch2/examples/catch2-console/main/idf_component.yml",
    "content": "dependencies:\n  espressif/catch2:\n    version: \"*\"\n    override_path: \"../../../\"\n"
  },
  {
    "path": "catch2/examples/catch2-console/main/test_cases.cpp",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n#include <catch2/catch_test_macros.hpp>\n\nTEST_CASE(\"Test case 1\")\n{\n    REQUIRE(1 == 1);\n}\n"
  },
  {
    "path": "catch2/examples/catch2-console/main/test_main.cpp",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n#include <stdio.h>\n#include <string.h>\n#include \"esp_console.h\"\n#include \"cmd_catch2.h\"\n\n#if SOC_USB_SERIAL_JTAG_SUPPORTED\n#if !CONFIG_ESP_CONSOLE_SECONDARY_NONE\n#warning \"A secondary serial console is not useful when using the console component. Please disable it in menuconfig.\"\n#endif\n#endif\n\nextern \"C\" void app_main(void)\n{\n    esp_console_repl_t *repl = NULL;\n    esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();\n    repl_config.prompt = \"catch2>\";\n    repl_config.task_stack_size = 10000;\n\n    /* Register commands */\n    esp_console_register_help_command();\n    register_catch2(\"test\");\n\n#if defined(CONFIG_ESP_CONSOLE_UART_DEFAULT) || defined(CONFIG_ESP_CONSOLE_UART_CUSTOM)\n    esp_console_dev_uart_config_t hw_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();\n    ESP_ERROR_CHECK(esp_console_new_repl_uart(&hw_config, &repl_config, &repl));\n\n#elif defined(CONFIG_ESP_CONSOLE_USB_CDC)\n    esp_console_dev_usb_cdc_config_t hw_config = ESP_CONSOLE_DEV_CDC_CONFIG_DEFAULT();\n    ESP_ERROR_CHECK(esp_console_new_repl_usb_cdc(&hw_config, &repl_config, &repl));\n\n#elif defined(CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG)\n    esp_console_dev_usb_serial_jtag_config_t hw_config = ESP_CONSOLE_DEV_USB_SERIAL_JTAG_CONFIG_DEFAULT();\n    ESP_ERROR_CHECK(esp_console_new_repl_usb_serial_jtag(&hw_config, &repl_config, &repl));\n\n#else\n#error Unsupported console type\n#endif\n\n    ESP_ERROR_CHECK(esp_console_start_repl(repl));\n}\n"
  },
  {
    "path": "catch2/examples/catch2-console/pytest_catch2_console.py",
    "content": "# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\n\nimport pytest\nfrom pytest_embedded import Dut\n\n\n@pytest.mark.generic\ndef test_catch2_console_example(dut: Dut) -> None:\n    dut.expect_exact('Type \\'help\\' to get the list of commands.')\n    dut.write('test -?\\n')\n    dut.expect_exact('For more detailed usage please see the project docs')\n    dut.write('test\\n')\n    dut.expect_exact('All tests passed')\n    dut.expect_exact('1 assertion in 1 test case')\n\n\n"
  },
  {
    "path": "catch2/examples/catch2-console/sdkconfig.defaults",
    "content": "CONFIG_COMPILER_CXX_EXCEPTIONS=y\nCONFIG_ESP_CONSOLE_SECONDARY_NONE=y\n"
  },
  {
    "path": "catch2/examples/catch2-test/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\n\nproject(catch2-test)\n\n"
  },
  {
    "path": "catch2/examples/catch2-test/README.md",
    "content": "# Catch2 example\n\nThis example should help you get started with Catch2 test framework.\n\n## Using the example\n\nTo run the example on an ESP32, build and flash the project as usual:\n\n```bash\nidf.py set-target esp32\nidf.py build flash monitor\n```\n\nThe example can also be used on Linux host:\n```bash\nidf.py --preview set-target linux\nidf.py build monitor\n```\n\n## Example structure\n\n- [main/idf_component.yml](main/idf_component.yml) adds a dependency on `espressif/catch2` component.\n- [main/CMakeLists.txt](main/CMakeLists.txt) specifies the source files and registers the `main` component with `WHOLE_ARCHIVE` option enabled.\n- [main/test_main.cpp](main/test_main.cpp) implements the application entry point which calls the test runner.\n- [main/test_cases.cpp](main/test_cases.cpp) implements one trivial test case.\n- [sdkconfig.defaults](sdkconfig.defaults) sets the options required to run the example: enables C++ exceptions and increases the size of the `main` task stack.\n\n## Expected output\n\n```\nRandomness seeded to: 3499211612\n===============================================================================\nAll tests passed (1 assertion in 1 test case)\n\nTest passed.\n```\n"
  },
  {
    "path": "catch2/examples/catch2-test/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"test_main.cpp\"\n                            \"test_cases.cpp\"\n                       INCLUDE_DIRS \".\"\n                       WHOLE_ARCHIVE)\n"
  },
  {
    "path": "catch2/examples/catch2-test/main/idf_component.yml",
    "content": "dependencies:\n  espressif/catch2:\n    version: \"*\"\n    override_path: \"../../../\"\n"
  },
  {
    "path": "catch2/examples/catch2-test/main/test_cases.cpp",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n#include <catch2/catch_test_macros.hpp>\n\nTEST_CASE(\"Test case 1\")\n{\n    REQUIRE(1 == 1);\n}\n"
  },
  {
    "path": "catch2/examples/catch2-test/main/test_main.cpp",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n#include <stdio.h>\n#include <catch2/catch_session.hpp>\n\nextern \"C\" void app_main(void)\n{\n    int argc = 1;\n    const char *argv[2] = {\n        \"target_test_main\",\n        NULL\n    };\n\n    auto result = Catch::Session().run(argc, argv);\n    if (result != 0) {\n        printf(\"Test failed with result %d\\n\", result);\n    } else {\n        printf(\"Test passed.\\n\");\n    }\n}\n"
  },
  {
    "path": "catch2/examples/catch2-test/pytest_catch2.py",
    "content": "# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\n\nimport pytest\nfrom pytest_embedded import Dut\n\n\n@pytest.mark.generic\ndef test_catch2_example(dut: Dut) -> None:\n    dut.expect_exact('All tests passed')\n    dut.expect_exact('1 assertion in 1 test case')\n\n"
  },
  {
    "path": "catch2/examples/catch2-test/sdkconfig.defaults",
    "content": "CONFIG_COMPILER_CXX_EXCEPTIONS=y\nCONFIG_ESP_MAIN_TASK_STACK_SIZE=10000\n"
  },
  {
    "path": "catch2/idf_component.yml",
    "content": "version: \"3.7.0\"\ndescription: A modern, C++-native, test framework for unit-tests, TDD and BDD - using C++14, C++17 and later\nurl: https://github.com/espressif/idf-extra-components/tree/master/catch2\nrepository: https://github.com/espressif/idf-extra-components.git\nissues: https://github.com/espressif/idf-extra-components/issues\ndocumentation: https://github.com/catchorg/Catch2/tree/devel/docs\ndependencies:\n  # Mostly because in older IDF versions there was no WHOLE_ARCHIVE component property,\n  # so linking all the test cases in a component was a bit hard.\n  idf: \">=5.0.0\"\nsbom:\n  manifests:\n    - path: sbom_catch2.yml\n      dest: Catch2\n"
  },
  {
    "path": "catch2/include/cmd_catch2.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: BSL-1.0\n */\n#pragma once\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include \"esp_err.h\"\n\n/**\n * @brief Register a command to run Catch2 tests.\n *\n * @param cmd_name  Name of the command to use. For example, \"test\".\n * @return esp_err_t  ESP_OK on success, otherwise an error code.\n */\nesp_err_t register_catch2(const char *cmd_name);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "catch2/sbom_catch2.yml",
    "content": "name: catch2\nversion: 3.7.0\ncpe: cpe:2.3:a:catchorg:catch2:{}:*:*:*:*:*:*:*\nsupplier: 'Organization: catchorg <https://github.com/catchorg>'\ndescription: A modern, C++-native, test framework for unit-tests, TDD and BDD - using C++14, C++17 and later\nurl: https://github.com/catchorg/Catch2\nhash: 31588bb4f56b638dd5afc28d3ebff9b9dcefb88d\n"
  },
  {
    "path": "cbor/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"tinycbor/src/cborencoder_close_container_checked.c\"\n                            \"tinycbor/src/cborencoder.c\"\n                            \"tinycbor/src/cborencoder_float.c\"\n                            \"tinycbor/src/cborerrorstrings.c\"\n                            \"tinycbor/src/cborparser_dup_string.c\"\n                            \"tinycbor/src/cborparser.c\"\n                            \"tinycbor/src/cborparser_float.c\"\n                            \"tinycbor/src/cborpretty_stdio.c\"\n                            \"tinycbor/src/cborpretty.c\"\n                            \"tinycbor/src/cbortojson.c\"\n                            \"tinycbor/src/cborvalidation.c\"\n                            \"tinycbor/src/open_memstream.c\"\n                    INCLUDE_DIRS \"tinycbor/src\")\n\n# for open_memstream.c\nset_source_files_properties(tinycbor/src/open_memstream.c PROPERTIES\n                            COMPILE_DEFINITIONS \"__linux__\")\n\n# Fix unreachable macro redefinition issue between ESP-IDF toolchain and tinycbor\n# by force-including a header that resolves the conflict\ntarget_compile_options(${COMPONENT_LIB} PRIVATE\n                       \"SHELL:-include \\\"${CMAKE_CURRENT_SOURCE_DIR}/port/include/unreachable_fix.h\\\"\")\n"
  },
  {
    "path": "cbor/examples/cbor/CMakeLists.txt",
    "content": "# The following lines of boilerplate have to be in your project's\n# CMakeLists in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(cbor)\n"
  },
  {
    "path": "cbor/examples/cbor/README.md",
    "content": "# CBOR Example\n\n## Overview\n\nThe [CBOR](https://en.wikipedia.org/wiki/CBOR)(Concise Binary Object Representation) is a binary data serialization format which is similar to JSON but with smaller footprint. This example will illustrate how to encode and decode CBOR data using the APIs provided by [tinycbor](https://github.com/intel/tinycbor).\n\nFor detailed information about how CBOR encoding and decoding works, please refer to [REF7049](https://tools.ietf.org/html/rfc7049) or [cbor.io](http://cbor.io/);\n\n## How to use example\n\n### Hardware Required\n\nThis example should be able to run on any commonly available ESP32 development board.\n\n### Build and Flash\n\nRun `idf.py -p PORT flash monitor` to build and flash the project.\n\n(To exit the serial monitor, type ``Ctrl-]``.)\n\nSee the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.\n\n## Example Output\n\n```bash\nI (320) example: encoded buffer size 67\nI (320) example: convert CBOR to JSON\n[{\"chip\":\"esp32\",\"unicore\":false,\"ip\":[192,168,1,100]},3.1400001049041748,\"simple(99)\",\"2019-07-10 09:00:00+0000\",\"undefined\"]\nI (340) example: decode CBOR manually\nArray[\n  Map{\n    chip\n    esp32\n    unicore\n    false\n    ip\n    Array[\n      192\n      168\n      1\n      100\n    ]\n  }\n  3.14\n  simple(99)\n  2019-07-10 09:00:00+0000\n  undefined\n]\n```\n\n## Troubleshooting\n\nFor more API usage, please refer to [tinycbor API](https://intel.github.io/tinycbor/current/).\n\n(For any technical queries, please open an [issue](https://github.com/espressif/idf-extra-components/issues) on GitHub. We will get back to you as soon as possible.)\n"
  },
  {
    "path": "cbor/examples/cbor/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"cbor_example_main.c\"\n                       INCLUDE_DIRS \"\")\n"
  },
  {
    "path": "cbor/examples/cbor/main/cbor_example_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n/* CBOR Example\n\n   This example code is in the Public Domain (or CC0 licensed, at your option.)\n\n   Unless required by applicable law or agreed to in writing, this\n   software is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n   CONDITIONS OF ANY KIND, either express or implied.\n*/\n#include <stdio.h>\n#include <stdlib.h>\n#include \"esp_log.h\"\n#include \"cbor.h\"\n#include \"cborjson.h\"\n\nstatic const char *TAG = \"example\";\n\n#define CBOR_CHECK(a, str, goto_tag, ret_value, ...)                              \\\n    do                                                                            \\\n    {                                                                             \\\n        if ((a) != CborNoError)                                                   \\\n        {                                                                         \\\n            ESP_LOGE(TAG, \"%s(%d): \" str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \\\n            ret = ret_value;                                                      \\\n            goto goto_tag;                                                        \\\n        }                                                                         \\\n    } while (0)\n\nstatic void indent(int nestingLevel)\n{\n    while (nestingLevel--) {\n        printf(\"  \");\n    }\n}\n\nstatic void dumpbytes(const uint8_t *buf, size_t len)\n{\n    while (len--) {\n        printf(\"%02X \", *buf++);\n    }\n}\n\n/**\n * Decode CBOR data manually\n */\nstatic CborError example_dump_cbor_buffer(CborValue *it, int nestingLevel)\n{\n    CborError ret = CborNoError;\n    while (!cbor_value_at_end(it)) {\n        CborType type = cbor_value_get_type(it);\n\n        indent(nestingLevel);\n        switch (type) {\n        case CborArrayType: {\n            CborValue recursed;\n            assert(cbor_value_is_container(it));\n            puts(\"Array[\");\n            ret = cbor_value_enter_container(it, &recursed);\n            CBOR_CHECK(ret, \"enter container failed\", err, ret);\n            ret = example_dump_cbor_buffer(&recursed, nestingLevel + 1);\n            CBOR_CHECK(ret, \"recursive dump failed\", err, ret);\n            ret = cbor_value_leave_container(it, &recursed);\n            CBOR_CHECK(ret, \"leave container failed\", err, ret);\n            indent(nestingLevel);\n            puts(\"]\");\n            continue;\n        }\n        case CborMapType: {\n            CborValue recursed;\n            assert(cbor_value_is_container(it));\n            puts(\"Map{\");\n            ret = cbor_value_enter_container(it, &recursed);\n            CBOR_CHECK(ret, \"enter container failed\", err, ret);\n            ret = example_dump_cbor_buffer(&recursed, nestingLevel + 1);\n            CBOR_CHECK(ret, \"recursive dump failed\", err, ret);\n            ret = cbor_value_leave_container(it, &recursed);\n            CBOR_CHECK(ret, \"leave container failed\", err, ret);\n            indent(nestingLevel);\n            puts(\"}\");\n            continue;\n        }\n        case CborIntegerType: {\n            int64_t val;\n            ret = cbor_value_get_int64(it, &val);\n            CBOR_CHECK(ret, \"parse int64 failed\", err, ret);\n            printf(\"%lld\\n\", (long long)val);\n            break;\n        }\n        case CborByteStringType: {\n            uint8_t *buf;\n            size_t n;\n            ret = cbor_value_dup_byte_string(it, &buf, &n, it);\n            CBOR_CHECK(ret, \"parse byte string failed\", err, ret);\n            dumpbytes(buf, n);\n            puts(\"\");\n            free(buf);\n            continue;\n        }\n        case CborTextStringType: {\n            char *buf;\n            size_t n;\n            ret = cbor_value_dup_text_string(it, &buf, &n, it);\n            CBOR_CHECK(ret, \"parse text string failed\", err, ret);\n            puts(buf);\n            free(buf);\n            continue;\n        }\n        case CborTagType: {\n            CborTag tag;\n            ret = cbor_value_get_tag(it, &tag);\n            CBOR_CHECK(ret, \"parse tag failed\", err, ret);\n            printf(\"Tag(%lld)\\n\", (long long)tag);\n            break;\n        }\n        case CborSimpleType: {\n            uint8_t type;\n            ret = cbor_value_get_simple_type(it, &type);\n            CBOR_CHECK(ret, \"parse simple type failed\", err, ret);\n            printf(\"simple(%u)\\n\", type);\n            break;\n        }\n        case CborNullType:\n            puts(\"null\");\n            break;\n        case CborUndefinedType:\n            puts(\"undefined\");\n            break;\n        case CborBooleanType: {\n            bool val;\n            ret = cbor_value_get_boolean(it, &val);\n            CBOR_CHECK(ret, \"parse boolean type failed\", err, ret);\n            puts(val ? \"true\" : \"false\");\n            break;\n        }\n        case CborHalfFloatType: {\n            uint16_t val;\n            ret = cbor_value_get_half_float(it, &val);\n            CBOR_CHECK(ret, \"parse half float type failed\", err, ret);\n            printf(\"__f16(%04x)\\n\", val);\n            break;\n        }\n        case CborFloatType: {\n            float val;\n            ret = cbor_value_get_float(it, &val);\n            CBOR_CHECK(ret, \"parse float type failed\", err, ret);\n            printf(\"%g\\n\", val);\n            break;\n        }\n        case CborDoubleType: {\n            double val;\n            ret = cbor_value_get_double(it, &val);\n            CBOR_CHECK(ret, \"parse double float type failed\", err, ret);\n            printf(\"%g\\n\", val);\n            break;\n        }\n        case CborInvalidType: {\n            ret = CborErrorUnknownType;\n            CBOR_CHECK(ret, \"unknown cbor type\", err, ret);\n            break;\n        }\n        }\n\n        ret = cbor_value_advance_fixed(it);\n        CBOR_CHECK(ret, \"fix value failed\", err, ret);\n    }\n    return CborNoError;\nerr:\n    return ret;\n}\n\n\nvoid app_main(void)\n{\n    CborEncoder root_encoder;\n    CborParser root_parser;\n    CborValue it;\n    uint8_t buf[100];\n\n    // Initialize the outermost cbor encoder\n    cbor_encoder_init(&root_encoder, buf, sizeof(buf), 0);\n\n    // Create an array containing several items\n    CborEncoder array_encoder;\n    CborEncoder map_encoder;\n    cbor_encoder_create_array(&root_encoder, &array_encoder, 5); // [\n    // 1. Create a map containing several pairs\n    cbor_encoder_create_map(&array_encoder, &map_encoder, 3); // {\n    // chip:esp32\n    cbor_encode_text_stringz(&map_encoder, \"chip\");\n    cbor_encode_text_stringz(&map_encoder, \"esp32\");\n    // unicore:false\n    cbor_encode_text_stringz(&map_encoder, \"unicore\");\n    cbor_encode_boolean(&map_encoder, false);\n    // ip:[192,168,1,100]\n    cbor_encode_text_stringz(&map_encoder, \"ip\");\n    CborEncoder array2;\n    cbor_encoder_create_array(&map_encoder, &array2, 4); // [\n    // Encode several numbers\n    cbor_encode_uint(&array2, 192);\n    cbor_encode_uint(&array2, 168);\n    cbor_encode_uint(&array2, 1);\n    cbor_encode_uint(&array2, 100);\n    cbor_encoder_close_container(&map_encoder, &array2);        // ]\n    cbor_encoder_close_container(&array_encoder, &map_encoder); // }\n    // 2. Encode float number\n    cbor_encode_float(&array_encoder, 3.14);\n    // 3. Encode simple value\n    cbor_encode_simple_value(&array_encoder, 99);\n    // 4. Encode a string\n    cbor_encode_text_stringz(&array_encoder, \"2019-07-10 09:00:00+0000\");\n    // 5. Encode a undefined value\n    cbor_encode_undefined(&array_encoder);\n    cbor_encoder_close_container(&root_encoder, &array_encoder); // ]\n\n    // If error happened when encoding, then this value should be meaningless\n    ESP_LOGI(TAG, \"encoded buffer size %d\", cbor_encoder_get_buffer_size(&root_encoder, buf));\n\n    // Initialize the cbor parser and the value iterator\n    cbor_parser_init(buf, sizeof(buf), 0, &root_parser, &it);\n\n    ESP_LOGI(TAG, \"convert CBOR to JSON\");\n    // Dump the values in JSON format\n    cbor_value_to_json(stdout, &it, 0);\n    puts(\"\");\n\n    ESP_LOGI(TAG, \"decode CBOR manually\");\n    // Decode CBOR data manually\n    example_dump_cbor_buffer(&it, 0);\n}\n"
  },
  {
    "path": "cbor/examples/cbor/main/idf_component.yml",
    "content": "## IDF Component Manager Manifest File\nversion: \"1.0.0\"\ndescription: CBOR Example\ndependencies:\n  espressif/cbor:\n    version: '0.*'\n    override_path: '../../../'\n"
  },
  {
    "path": "cbor/examples/cbor/pytest_cbor.py",
    "content": "# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nfrom __future__ import unicode_literals\n\nimport textwrap\n\nimport pytest\nfrom pytest_embedded import Dut\n\n\n@pytest.mark.generic\ndef test_examples_cbor(dut: Dut) -> None:\n\n    dut.expect(r'example: encoded buffer size \\d+')\n    dut.expect('example: convert CBOR to JSON')\n    parsed_info = dut.expect(r'\\[\\{\"chip\":\"(\\w+)\",\"unicore\":(\\w+),\"ip\":\\[(\\d+),(\\d+),(\\d+),(\\d+)\\]\\},'\n                             r'3.1400001049041748'\n                             r',\"simple\\(99\\)\",\"2019-07-10 09:00:00\\+0000\",\"undefined\"\\]')\n    dut.expect('example: decode CBOR manually')\n\n    dut.expect(textwrap.dedent(r'''\n                                Array\\[\\s*\n                                  Map{{\\s*\n                                    chip\\s*\n                                    {}\\s*\n                                    unicore\\s*\n                                    {}\\s*\n                                    ip\\s*\n                                    Array\\[\\s*\n                                      {}\\s*\n                                      {}\\s*\n                                      {}\\s*\n                                      {}\\s*\n                                    \\]\\s*\n                                  }}\\s*\n                                  3.14\\s*\n                                  simple\\(99\\)\\s*\n                                  2019-07-10 09:00:00\\+0000\\s*\n                                  undefined\\s*\n                                \\]'''.format(parsed_info[1].decode(), parsed_info[2].decode(), parsed_info[3].decode(),\n                                             parsed_info[4].decode(), parsed_info[5].decode(),parsed_info[6].decode())).replace('{', r'\\{').replace('}', r'\\}'))\n"
  },
  {
    "path": "cbor/examples/cbor/sdkconfig.defaults",
    "content": "# This example is not supported with newlib nano:\n#   - First 64-bit integers are not supported in newlib nano\n#   - There is also issue with `PRIu8` format specifier with newlib nano (observed on ESP32-C2, see IDFCI-1375)\nCONFIG_NEWLIB_NANO_FORMAT=n\n"
  },
  {
    "path": "cbor/idf_component.yml",
    "content": "version: \"0.6.1~4\"\r\ndescription: \"CBOR: Concise Binary Object Representation Library\"\r\nurl: https://github.com/espressif/idf-extra-components/tree/master/cbor\r\ndependencies:\r\n  idf: \">=5.0\"\r\n"
  },
  {
    "path": "cbor/port/include/unreachable_fix.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n\n#ifndef CBOR_UNREACHABLE_FIX_H\n#define CBOR_UNREACHABLE_FIX_H\n\n/* This header fixes the unreachable macro redefinition issue between\n   ESP-IDF toolchain and tinycbor library */\n\n/* Force include stddef.h first to get the ESP-IDF definition */\n#include <stddef.h>\n\n/* Now undefine it so tinycbor can define its own version */\n#ifdef unreachable\n#undef unreachable\n#endif\n\n#endif /* CBOR_UNREACHABLE_FIX_H */\n"
  },
  {
    "path": "ccomp_timer/.build-test-rules.yml",
    "content": "ccomp_timer/test_apps:\n  enable:\n    - if: IDF_TARGET in [\"esp32\", \"esp32s2\", \"esp32c3\"]\n      reason: \"Testing on these targets is sufficient (xtensa, risc-v, single/dual core).\"\n"
  },
  {
    "path": "ccomp_timer/CHANGELOG.md",
    "content": "## 1.0.0\n\n- Move the cache compensated timer from `esp-idf/tools/unit-test-app/components` to component registry.\n"
  },
  {
    "path": "ccomp_timer/CMakeLists.txt",
    "content": "idf_build_get_property(arch IDF_TARGET_ARCH)\n\nset(srcs \"ccomp_timer.c\")\n\nif(CONFIG_IDF_TARGET_ARCH_RISCV)\n    list(APPEND srcs \"ccomp_timer_impl_riscv.c\")\nendif()\n\nif(CONFIG_IDF_TARGET_ARCH_XTENSA)\n    list(APPEND srcs \"ccomp_timer_impl_xtensa.c\")\nendif()\n\nif(\"${arch}\" STREQUAL \"xtensa\")\n    set(priv_requires perfmon driver)\nelse()\n    set(priv_requires driver)\nendif()\n\nidf_component_register(SRCS ${srcs}\n                       INCLUDE_DIRS include\n                       PRIV_INCLUDE_DIRS private_include\n                       PRIV_REQUIRES \"${priv_requires}\")\n"
  },
  {
    "path": "ccomp_timer/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "ccomp_timer/README.md",
    "content": "# Cache Compensated Timer\n\n[![Component Registry](https://components.espressif.com/components/espressif/ccomp_timer/badge.svg)](https://components.espressif.com/components/espressif/ccomp_timer)\n\nThe **Cache Compensated Timer** is a timer that tries to account for instruction and data stall cycles caused by cache misses. It is useful for measuring the time spent in a function or a block of code.\n\nOn Xtensa targets (e.g. ESP32), the timer is built on top of the debug module's performance monitor counter.\n\nDue to hardware limitations, on RISC-V targets this driver falls back to using the CPU's cycle counter, which actually **doesn't** account for the cache misses. To achieve a measurement that is independent of cache misses you could place the code is to be measured into IRAM.\n"
  },
  {
    "path": "ccomp_timer/ccomp_timer.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"ccomp_timer.h\"\n\n#include \"ccomp_timer_impl.h\"\n\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"freertos/semphr.h\"\n\n#include \"esp_log.h\"\n#include \"esp_intr_alloc.h\"\n\n\nesp_err_t ccomp_timer_start(void)\n{\n    esp_err_t err = ESP_OK;\n\n    ccomp_timer_impl_lock();\n    if (ccomp_timer_impl_is_init()) {\n        if (ccomp_timer_impl_is_active()) {\n            err = ESP_ERR_INVALID_STATE;\n        }\n    } else {\n        err = ccomp_timer_impl_init();\n    }\n    ccomp_timer_impl_unlock();\n\n    if (err != ESP_OK) {\n        goto fail;\n    }\n\n    err = ccomp_timer_impl_reset();\n\n    if (err != ESP_OK) {\n        goto fail;\n    }\n\n    err = ccomp_timer_impl_start();\n\n    if (err == ESP_OK) {\n        return ESP_OK;\n    }\n\nfail:\n    return err;\n}\n\nint64_t IRAM_ATTR ccomp_timer_stop(void)\n{\n    esp_err_t err = ESP_OK;\n    ccomp_timer_impl_lock();\n    if (!ccomp_timer_impl_is_active()) {\n        err = ESP_ERR_INVALID_STATE;\n    }\n    ccomp_timer_impl_unlock();\n\n    if (err != ESP_OK) {\n        goto fail;\n    }\n\n    err = ccomp_timer_impl_stop();\n    if (err != ESP_OK) {\n        goto fail;\n    }\n\n    int64_t t = ccomp_timer_get_time();\n\n    err = ccomp_timer_impl_deinit();\n\n    if (err == ESP_OK && t != -1) {\n        return t;\n    }\n\nfail:\n    return -1;\n}\n\nint64_t IRAM_ATTR ccomp_timer_get_time(void)\n{\n    return ccomp_timer_impl_get_time();\n}\n"
  },
  {
    "path": "ccomp_timer/ccomp_timer_impl_riscv.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdint.h>\n#include \"freertos/portmacro.h\"\n#include \"esp_freertos_hooks.h\"\n#include \"soc/soc_caps.h\"\n#include \"esp_rom_sys.h\"\n#include \"esp_cpu.h\"\n#include \"esp_private/esp_clk.h\"\n\ntypedef enum {\n    PERF_TIMER_UNINIT = 0,  // timer has not been initialized yet\n    PERF_TIMER_IDLE,        // timer has been initialized but is not tracking elapsed time\n    PERF_TIMER_ACTIVE       // timer is tracking elapsed time\n} ccomp_timer_state_t;\n\ntypedef struct {\n    uint32_t last_ccount;      // last CCOUNT value, updated every os tick\n    ccomp_timer_state_t state; // state of the timer\n    int64_t ccount;            // accumulated processors cycles during the time when timer is active\n} ccomp_timer_status_t;\n\n// Each core has its independent timer\nccomp_timer_status_t s_status[SOC_CPU_CORES_NUM];\n\nstatic portMUX_TYPE s_lock = portMUX_INITIALIZER_UNLOCKED;\n\nstatic void IRAM_ATTR update_ccount(void)\n{\n    if (s_status[esp_cpu_get_core_id()].state == PERF_TIMER_ACTIVE) {\n        int64_t new_ccount = esp_cpu_get_cycle_count();\n        if (new_ccount > s_status[esp_cpu_get_core_id()].last_ccount) {\n            s_status[esp_cpu_get_core_id()].ccount += new_ccount - s_status[esp_cpu_get_core_id()].last_ccount;\n        } else {\n            // CCOUNT has wrapped around\n            s_status[esp_cpu_get_core_id()].ccount += new_ccount + (UINT32_MAX - s_status[esp_cpu_get_core_id()].last_ccount);\n        }\n        s_status[esp_cpu_get_core_id()].last_ccount = new_ccount;\n    }\n}\n\nesp_err_t ccomp_timer_impl_init(void)\n{\n    s_status[esp_cpu_get_core_id()].state = PERF_TIMER_IDLE;\n    return ESP_OK;\n}\n\nesp_err_t ccomp_timer_impl_deinit(void)\n{\n    s_status[esp_cpu_get_core_id()].state = PERF_TIMER_UNINIT;\n    return ESP_OK;\n}\n\nesp_err_t ccomp_timer_impl_start(void)\n{\n    s_status[esp_cpu_get_core_id()].state = PERF_TIMER_ACTIVE;\n    s_status[esp_cpu_get_core_id()].last_ccount = esp_cpu_get_cycle_count();\n    // Update elapsed cycles every OS tick\n    esp_register_freertos_tick_hook_for_cpu(update_ccount, esp_cpu_get_core_id());\n    return ESP_OK;\n}\n\nesp_err_t IRAM_ATTR ccomp_timer_impl_stop(void)\n{\n    esp_deregister_freertos_tick_hook_for_cpu(update_ccount, esp_cpu_get_core_id());\n    update_ccount();\n    s_status[esp_cpu_get_core_id()].state = PERF_TIMER_IDLE;\n    return ESP_OK;\n}\n\nint64_t IRAM_ATTR ccomp_timer_impl_get_time(void)\n{\n    update_ccount();\n    int64_t cycles = s_status[esp_cpu_get_core_id()].ccount;\n    return (cycles * 1000000) / esp_clk_cpu_freq();\n}\n\nesp_err_t ccomp_timer_impl_reset(void)\n{\n    s_status[esp_cpu_get_core_id()].ccount = 0;\n    s_status[esp_cpu_get_core_id()].last_ccount = 0;\n    return ESP_OK;\n}\n\nbool ccomp_timer_impl_is_init(void)\n{\n    return s_status[esp_cpu_get_core_id()].state != PERF_TIMER_UNINIT;\n}\n\nbool IRAM_ATTR ccomp_timer_impl_is_active(void)\n{\n    return s_status[esp_cpu_get_core_id()].state == PERF_TIMER_ACTIVE;\n}\n\nvoid IRAM_ATTR ccomp_timer_impl_lock(void)\n{\n    portENTER_CRITICAL(&s_lock);\n}\n\nvoid IRAM_ATTR ccomp_timer_impl_unlock(void)\n{\n    portEXIT_CRITICAL(&s_lock);\n}\n"
  },
  {
    "path": "ccomp_timer/ccomp_timer_impl_xtensa.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdint.h>\n#include <string.h>\n\n#include \"ccomp_timer_impl.h\"\n#include \"esp_intr_alloc.h\"\n#include \"esp_log.h\"\n#include \"esp_attr.h\"\n#include \"eri.h\"\n#include \"freertos/FreeRTOS.h\"\n#include \"esp_freertos_hooks.h\"\n#include \"perfmon.h\"\n#include \"xtensa/core-macros.h\"\n#include \"xtensa/xt_perf_consts.h\"\n#include \"xtensa-debug-module.h\"\n#include \"esp_private/esp_clk.h\"\n\n#define D_STALL_COUNTER_ID 0\n#define I_STALL_COUNTER_ID 1\n\ntypedef enum {\n    PERF_TIMER_UNINIT = 0,              // timer has not been initialized yet\n    PERF_TIMER_IDLE,                    // timer has been initialized but is not tracking elapsed time\n    PERF_TIMER_ACTIVE                   // timer is tracking elapsed time\n} ccomp_timer_state_t;\n\ntypedef struct {\n    int i_ovfl;                         // number of times instruction stall counter has overflowed\n    int d_ovfl;                         // number of times data stall counter has overflowed\n    uint32_t last_ccount;               // last CCOUNT value, updated every os tick\n    ccomp_timer_state_t state;          // state of the timer\n    intr_handle_t intr_handle;          // handle to allocated handler for perfmon counter overflows, so that it can be freed during deinit\n    int64_t ccount;                     // accumulated processors cycles during the time when timer is active\n} ccomp_timer_status_t;\n\n// Each core has its independent timer\nccomp_timer_status_t s_status[] = {\n    (ccomp_timer_status_t)\n    {\n        .i_ovfl = 0,\n        .d_ovfl = 0,\n        .ccount = 0,\n        .last_ccount = 0,\n        .state = PERF_TIMER_UNINIT,\n        .intr_handle = NULL,\n    },\n    (ccomp_timer_status_t)\n    {\n        .i_ovfl = 0,\n        .d_ovfl = 0,\n        .ccount = 0,\n        .last_ccount = 0,\n        .state = PERF_TIMER_UNINIT,\n        .intr_handle = NULL\n    }\n};\n\nstatic portMUX_TYPE s_lock = portMUX_INITIALIZER_UNLOCKED;\n\nstatic void IRAM_ATTR update_ccount(void)\n{\n    if (s_status[xPortGetCoreID()].state == PERF_TIMER_ACTIVE) {\n        int64_t new_ccount = xthal_get_ccount();\n        if (new_ccount > s_status[xPortGetCoreID()].last_ccount) {\n            s_status[xPortGetCoreID()].ccount += new_ccount - s_status[xPortGetCoreID()].last_ccount;\n        } else {\n            // CCOUNT has wrapped around\n            s_status[xPortGetCoreID()].ccount += new_ccount + (UINT32_MAX - s_status[xPortGetCoreID()].last_ccount);\n        }\n        s_status[xPortGetCoreID()].last_ccount = new_ccount;\n    }\n}\n\nstatic void inline update_overflow(int id, int *cnt)\n{\n    uint32_t pmstat = eri_read(ERI_PERFMON_PMSTAT0 + id * sizeof(int32_t));\n    if (pmstat & PMSTAT_OVFL) {\n        *cnt += 1;\n        // Clear overflow and PerfMonInt asserted bits. The only valid bits in PMSTAT is the ones we're trying to clear. So it should be\n        // ok to just modify the whole register.\n        eri_write(ERI_PERFMON_PMSTAT0 + id, ~0x0);\n    }\n}\n\nstatic void IRAM_ATTR perf_counter_overflow_handler(void *args)\n{\n    update_overflow(D_STALL_COUNTER_ID, &s_status[xPortGetCoreID()].d_ovfl);\n    update_overflow(I_STALL_COUNTER_ID, &s_status[xPortGetCoreID()].i_ovfl);\n}\n\nstatic void set_perfmon_interrupt(bool enable)\n{\n    uint32_t d_pmctrl = eri_read(ERI_PERFMON_PMCTRL0 + D_STALL_COUNTER_ID * sizeof(int32_t));\n    uint32_t i_pmctrl = eri_read(ERI_PERFMON_PMCTRL0 + I_STALL_COUNTER_ID * sizeof(int32_t));\n\n    if (enable) {\n        d_pmctrl |= PMCTRL_INTEN;\n        i_pmctrl |= PMCTRL_INTEN;\n    } else {\n        d_pmctrl &= ~PMCTRL_INTEN;\n        i_pmctrl &= ~PMCTRL_INTEN;\n    }\n\n    eri_write(ERI_PERFMON_PMCTRL0 + D_STALL_COUNTER_ID * sizeof(int32_t), d_pmctrl);\n    eri_write(ERI_PERFMON_PMCTRL0 + I_STALL_COUNTER_ID * sizeof(int32_t), i_pmctrl);\n}\n\n\nesp_err_t ccomp_timer_impl_init(void)\n{\n    // Keep track of how many times each counter has overflowed.\n    esp_err_t err = esp_intr_alloc(ETS_INTERNAL_PROFILING_INTR_SOURCE, 0,\n                                   perf_counter_overflow_handler, NULL, &s_status[xPortGetCoreID()].intr_handle);\n\n    if (err != ESP_OK) {\n        return err;\n    }\n\n    xtensa_perfmon_init(D_STALL_COUNTER_ID,\n                        XTPERF_CNT_D_STALL,\n                        XTPERF_MASK_D_STALL_BUSY, 0, -1);\n    xtensa_perfmon_init(I_STALL_COUNTER_ID,\n                        XTPERF_CNT_I_STALL,\n                        XTPERF_MASK_I_STALL_BUSY, 0, -1);\n\n    set_perfmon_interrupt(true);\n    s_status[xPortGetCoreID()].state = PERF_TIMER_IDLE;\n    return ESP_OK;\n}\n\nesp_err_t ccomp_timer_impl_deinit(void)\n{\n    set_perfmon_interrupt(false);\n\n    esp_err_t err = esp_intr_free(s_status[xPortGetCoreID()].intr_handle);\n\n    if (err != ESP_OK) {\n        return err;\n    }\n\n    s_status[xPortGetCoreID()].intr_handle = NULL;\n    s_status[xPortGetCoreID()].state = PERF_TIMER_UNINIT;\n    return ESP_OK;\n}\n\nesp_err_t ccomp_timer_impl_start(void)\n{\n    s_status[xPortGetCoreID()].state = PERF_TIMER_ACTIVE;\n    s_status[xPortGetCoreID()].last_ccount = xthal_get_ccount();\n    // Update elapsed cycles every OS tick\n    esp_register_freertos_tick_hook_for_cpu(update_ccount, xPortGetCoreID());\n    xtensa_perfmon_start();\n    return ESP_OK;\n}\n\nesp_err_t IRAM_ATTR ccomp_timer_impl_stop(void)\n{\n    xtensa_perfmon_stop();\n    esp_deregister_freertos_tick_hook_for_cpu(update_ccount, xPortGetCoreID());\n    update_ccount();\n    s_status[xPortGetCoreID()].state = PERF_TIMER_IDLE;\n    return ESP_OK;\n}\n\nint64_t IRAM_ATTR ccomp_timer_impl_get_time(void)\n{\n    update_ccount();\n    int64_t d_stalls = xtensa_perfmon_value(D_STALL_COUNTER_ID) +\n                       s_status[xPortGetCoreID()].d_ovfl * (1 << sizeof(int32_t));\n    int64_t i_stalls = xtensa_perfmon_value(I_STALL_COUNTER_ID) +\n                       s_status[xPortGetCoreID()].i_ovfl * (1 << sizeof(int32_t));\n    int64_t stalls = d_stalls + i_stalls;\n    int64_t cycles = s_status[xPortGetCoreID()].ccount;\n    return ((cycles - stalls) * 1000000) / esp_clk_cpu_freq();\n}\n\nesp_err_t ccomp_timer_impl_reset(void)\n{\n    xtensa_perfmon_reset(D_STALL_COUNTER_ID);\n    xtensa_perfmon_reset(I_STALL_COUNTER_ID);\n    s_status[xPortGetCoreID()].d_ovfl = 0;\n    s_status[xPortGetCoreID()].i_ovfl = 0;\n    s_status[xPortGetCoreID()].ccount = 0;\n    s_status[xPortGetCoreID()].last_ccount = 0;\n    return ESP_OK;\n}\n\nbool ccomp_timer_impl_is_init(void)\n{\n    return s_status[xPortGetCoreID()].state != PERF_TIMER_UNINIT;\n}\n\nbool IRAM_ATTR ccomp_timer_impl_is_active(void)\n{\n    return s_status[xPortGetCoreID()].state == PERF_TIMER_ACTIVE;\n}\n\nvoid IRAM_ATTR ccomp_timer_impl_lock(void)\n{\n    portENTER_CRITICAL(&s_lock);\n}\n\nvoid IRAM_ATTR ccomp_timer_impl_unlock(void)\n{\n    portEXIT_CRITICAL(&s_lock);\n}\n"
  },
  {
    "path": "ccomp_timer/idf_component.yml",
    "content": "version: \"1.0.0~1\"\ndescription: Cache Compensated Timer\nurl: https://github.com/espressif/idf-extra-components/tree/master/ccomp_timer\nissues: \"https://github.com/espressif/idf-extra-components/issues\"\ndependencies:\n  idf: \">=5.0\"\n"
  },
  {
    "path": "ccomp_timer/include/ccomp_timer.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include <stdint.h>\n#include \"esp_err.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief Start the timer on the current core.\n *\n * @return\n *  - ESP_OK: Success\n *  - ESP_ERR_INVALID_STATE: The timer has already been started previously.\n *  - Others: Fail\n */\nesp_err_t ccomp_timer_start(void);\n\n/**\n * @brief Stop the timer on the current core.\n *\n * @note Returns -1 if an error has occurred and stopping the timer failed.\n *\n * @return The time elapsed from the last ccomp_timer_start call on the current\n *         core.\n */\nint64_t ccomp_timer_stop(void);\n\n/**\n * Return the current timer value on the current core without stopping the timer.\n *\n * @note Returns -1 if an error has occurred and stopping the timer failed.\n *\n * @note If called while timer is active i.e. between ccomp_timer_start and ccomp_timer_stop,\n * this function returns the elapsed time from ccomp_timer_start. Once ccomp_timer_stop\n * has been called, the timer becomes inactive and stops keeping time. As a result, if this function gets\n * called after esp_cccomp_timer_stop, this function will return the same value as when the timer was stopped.\n *\n * @return The elapsed time from the last ccomp_timer_start call on the current\n *          core.\n */\nint64_t ccomp_timer_get_time(void);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "ccomp_timer/private_include/ccomp_timer_impl.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <stdbool.h>\n#include \"esp_err.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief Initialize the underlying implementation for cache compensated timer. This might involve\n * setting up architecture-specific event counters and or allocating interrupts that handle events for those counters.\n * @return\n *  - ESP_OK: Success\n *  - ESP_ERR_INVALID_STATE: The timer has already been started previously.\n *  - Others: Fail\n */\nesp_err_t ccomp_timer_impl_init(void);\n\n/**\n * @brief Deinitialize the underlying implementation for cache compensated timer. This should restore\n * the state of the program to before ccomp_timer_impl_init.\n * @return\n *  - ESP_OK: Success\n *  - ESP_ERR_INVALID_STATE: The timer has already been started previously.\n *  - Others: Fail\n */\nesp_err_t ccomp_timer_impl_deinit(void);\n\n/**\n * @brief Make the underlying implementation start keeping time.\n *\n * @return\n *  - ESP_OK: Success\n *  - Others: Fail\n */\nesp_err_t ccomp_timer_impl_start(void);\n\n/**\n * @brief Make the underlying implementation stop keeping time.\n *\n * @return\n *  - ESP_OK: Success\n *  - Others: Fail\n */\nesp_err_t ccomp_timer_impl_stop(void);\n\n/**\n * @brief Reset the timer to its initial state.\n *\n * @return\n *  - ESP_OK: Success\n *  - Others: Fail\n */\nesp_err_t ccomp_timer_impl_reset(void);\n\n/**\n * @brief Get the elapsed time kept track of by the underlying implementation in microseconds.\n *\n * @return The elapsed time in microseconds. Set to -1 if the operation is unsuccessful.\n */\nint64_t ccomp_timer_impl_get_time(void);\n\n/**\n * @brief Obtain an internal critical section used in the implementation. Should be treated\n * as a spinlock.\n */\nvoid ccomp_timer_impl_lock(void);\n\n/**\n * @brief Start the performance timer on the current core.\n */\nvoid ccomp_timer_impl_unlock(void);\n\n/**\n * @brief Check if timer has been initialized.\n *\n * @return\n *  - true: the timer has been initialized using ccomp_timer_impl_init\n *  - false: the timer has not been initialized, or ccomp_timer_impl_deinit has been called recently\n */\nbool ccomp_timer_impl_is_init(void);\n\n/**\n * @brief Check if timer is keeping time.\n *\n * @return\n *  - true: the timer is keeping track of elapsed time from ccomp_timer_impl_start\n *  - false: the timer is not keeping track of elapsed time since ccomp_timer_impl_start has not yet been called or ccomp_timer_impl_stop has been called recently\n */\nbool ccomp_timer_impl_is_active(void);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "ccomp_timer/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(ccomp_timer_test)\n"
  },
  {
    "path": "ccomp_timer/test_apps/main/CMakeLists.txt",
    "content": "idf_build_get_property(arch IDF_TARGET_ARCH)\n\nset(priv_requires esp_timer unity)\nif(\"${arch}\" STREQUAL \"xtensa\")\n    list(APPEND priv_requires perfmon)\nendif()\n\nidf_component_register(SRCS \"ccomp_timer_test.c\"\n                            \"ccomp_timer_test_api.c\"\n                            \"ccomp_timer_test_data.c\"\n                            \"ccomp_timer_test_inst.c\"\n                       PRIV_INCLUDE_DIRS \".\"\n                       PRIV_REQUIRES ${priv_requires}\n                       WHOLE_ARCHIVE)\n"
  },
  {
    "path": "ccomp_timer/test_apps/main/ccomp_timer_test.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"unity.h\"\n#include \"unity_test_runner.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_newlib.h\"\n#include \"unity_test_utils_memory.h\"\n\nvoid setUp(void)\n{\n    unity_utils_record_free_mem();\n}\n\nvoid tearDown(void)\n{\n    esp_reent_cleanup();    //clean up some of the newlib's lazy allocations\n    unity_utils_evaluate_leaks_direct(50);\n}\n\nvoid app_main(void)\n{\n    printf(\"Running ccomp_timer component tests\\n\");\n    unity_run_menu();\n}\n"
  },
  {
    "path": "ccomp_timer/test_apps/main/ccomp_timer_test_api.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n#include <stdlib.h>\n#include <stdint.h>\n\n#include \"esp_timer.h\"\n#include \"esp_log.h\"\n#include \"esp_attr.h\"\n#include \"ccomp_timer.h\"\n\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#ifndef CONFIG_FREERTOS_UNICORE\n#include \"esp_ipc.h\"\n#endif\n\n#include \"unity.h\"\n\n#ifndef CONFIG_FREERTOS_UNICORE\nstatic void start_timer(void *param)\n{\n    esp_err_t *err = (esp_err_t *)param;\n    *err = ccomp_timer_start();\n}\n\nstatic void stop_timer(void *param)\n{\n    int64_t *t = (int64_t *)param;\n    *t = ccomp_timer_stop();\n}\n#endif\n\nstatic void computation(void *param)\n{\n    int *l = (int *)param;\n    for (volatile int i = 0, a = 0; i < *l; i++) {\n        a += i;\n    }\n}\n\nTEST_CASE(\"starting and stopping works\", \"[ccomp_timer]\")\n{\n    esp_err_t err;\n    int64_t t;\n\n    /*\n    * Test on the same task\n    */\n    err = ccomp_timer_start();\n    TEST_ASSERT_EQUAL(ESP_OK, err);\n\n    // Start an already started timer\n    err = ccomp_timer_start();\n    TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, err);\n\n    t = ccomp_timer_stop();\n    TEST_ASSERT_GREATER_OR_EQUAL(0, t);\n\n    // Stopping a non started timer\n    t = ccomp_timer_stop();\n    TEST_ASSERT_EQUAL(-1, t);\n\n#ifndef CONFIG_FREERTOS_UNICORE\n    /*\n    * Test on different task on same core\n    */\n    err = ccomp_timer_start();\n    TEST_ASSERT_EQUAL(ESP_OK, err);\n\n    esp_ipc_call_blocking(xPortGetCoreID(), start_timer, &err);\n    TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, err);\n\n    t = ccomp_timer_stop();\n    TEST_ASSERT_GREATER_OR_EQUAL(0, t);\n\n    esp_ipc_call_blocking(xPortGetCoreID(), stop_timer, &t);\n    TEST_ASSERT_EQUAL(-1, t);\n\n    /*\n    * Timer being stopped from another task on the same core\n    */\n    err = ccomp_timer_start();\n    TEST_ASSERT_EQUAL(ESP_OK, err);\n\n    esp_ipc_call_blocking(xPortGetCoreID(), stop_timer, &t);\n    TEST_ASSERT_GREATER_OR_EQUAL(0, t);\n\n    /*\n    * Test on different task on same core\n    */\n    err = ccomp_timer_start();\n    TEST_ASSERT_EQUAL(ESP_OK, err);\n\n    esp_ipc_call_blocking(xPortGetCoreID() == 0 ? 1 : 0, start_timer, &err);\n    TEST_ASSERT_EQUAL(ESP_OK, err);\n\n    t = ccomp_timer_stop();\n    TEST_ASSERT_GREATER_OR_EQUAL(0, t);\n\n    esp_ipc_call_blocking(xPortGetCoreID() == 0 ? 1 : 0, stop_timer, &t);\n    TEST_ASSERT_GREATER_OR_EQUAL(0, t);\n#endif\n}\n\nTEST_CASE(\"getting the time works\", \"[ccomp_timer]\")\n{\n    // Get wall time and start ccomp timer\n    int64_t start = esp_timer_get_time();\n    ccomp_timer_start();\n\n    int64_t t_a = ccomp_timer_get_time();\n\n    int temp = 10000;\n    computation(&temp);\n\n    int64_t t_b = ccomp_timer_get_time();\n\n    // Check that ccomp time after computation is more than\n    // ccomp time before computation.\n    TEST_ASSERT_LESS_THAN(t_b, t_a);\n\n    // Get time diff between wall time and ccomp time\n    int64_t t_1 = ccomp_timer_stop();\n    int64_t t_2 = esp_timer_get_time() - start;\n\n    // The times should at least be in the same ballpark (at least within 10%)\n    float diff = (llabs(t_1 - t_2)) / ((float)t_2);\n    TEST_ASSERT(diff <= 10.0f);\n\n    // Since the timer was already stopped, test that ccomp_timer_get_time\n    // returns the same time as ccomp_timer_stop\n    int64_t t_c = ccomp_timer_get_time();\n    TEST_ASSERT_EQUAL(t_1, t_c);\n}\n\n#ifndef CONFIG_FREERTOS_UNICORE\nTEST_CASE(\"timers for each core counts independently\", \"[ccomp_timer]\")\n{\n    esp_err_t err;\n\n    // Start a timer on this core\n    err = ccomp_timer_start();\n    TEST_ASSERT_EQUAL(ESP_OK, err);\n\n    // Do some work on this core\n    int temp = 10000;\n    computation(&temp);\n\n    // Start a timer on the other core\n    esp_ipc_call_blocking(xPortGetCoreID() == 0 ? 1 : 0, start_timer, &err);\n    TEST_ASSERT_EQUAL(ESP_OK, err);\n\n    // Do some work on other core (less work than this core did)\n    temp = 5000;\n    esp_ipc_call_blocking(xPortGetCoreID() == 0 ? 1 : 0, computation, &temp);\n\n    // Stop timers from both cores\n    int64_t t_1 = ccomp_timer_stop();\n    TEST_ASSERT_GREATER_OR_EQUAL(0, t_1);\n\n    int64_t t_2;\n    esp_ipc_call_blocking(xPortGetCoreID() == 0 ? 1 : 0, stop_timer, &t_2);\n    TEST_ASSERT_GREATER_OR_EQUAL(0, t_2);\n\n    // Since this core did more work, it probably has longer measured time\n    TEST_ASSERT_GREATER_THAN(t_2, t_1);\n}\n#endif\n"
  },
  {
    "path": "ccomp_timer/test_apps/main/ccomp_timer_test_data.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n#include <stdlib.h>\n#include <stdint.h>\n\n#include \"esp_timer.h\"\n#include \"esp_log.h\"\n#include \"esp_attr.h\"\n#include \"ccomp_timer.h\"\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"esp_private/esp_clk.h\"\n\n#include \"unity.h\"\n\n#include \"sdkconfig.h\"\n\n\n#if CONFIG_IDF_TARGET_ESP32\n#define CACHE_WAYS              2\n#define CACHE_LINE_SIZE         32\n#define CACHE_SIZE              (1 << 15)\n#define TEST_SIZE               (CACHE_SIZE / 8)\n#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3\n// Default cache configuration - no override specified on\n#define CACHE_WAYS              8\n#define CACHE_LINE_SIZE         32\n#define CACHE_SIZE              (1 << 13)\n#define TEST_SIZE               (CACHE_SIZE)\n#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6\n#define CACHE_WAYS              8\n#define CACHE_LINE_SIZE         32\n#define CACHE_SIZE              (1 << 14)\n#define TEST_SIZE               (CACHE_SIZE)\n#endif\n\ntypedef struct {\n    uint8_t **accesses;\n    size_t len;\n} ccomp_test_access_t;\n\ntypedef struct {\n    int64_t wall;\n    int64_t ccomp;\n} ccomp_test_time_t;\n\n/* No performance monitor in RISCV for now\n */\n#if !__riscv\n//IDF-5052\n\nstatic const char *TAG = \"test_ccomp_timer\";\n\n#if CONFIG_SPIRAM\nstatic uint8_t *flash_mem;\n#else\nstatic const uint8_t flash_mem[2 * CACHE_SIZE] = {0};\n#endif\n\nstatic IRAM_ATTR void perform_accesses(ccomp_test_access_t *access)\n{\n    volatile int a = 0;\n    for (int i = 0; i < access->len; i++) {\n        a += (int)(*(access->accesses[i]));\n    }\n}\n\nstatic void prepare_cache(const uint8_t *to_cache)\n{\n    volatile int a = 0;\n    for (int i = 0; i < CACHE_SIZE; i++) {\n        a += to_cache[i];\n    }\n}\n\nstatic void prepare_access_pattern(int hit_rate, const uint8_t *cached, ccomp_test_access_t *out)\n{\n    assert(hit_rate <= 100);\n    assert(hit_rate >= 0);\n\n    int misses = (100 - hit_rate) * CACHE_LINE_SIZE;\n    int hits = hit_rate * CACHE_LINE_SIZE;\n\n    uint8_t **accesses = calloc(TEST_SIZE, sizeof(uint8_t *));\n    TEST_ASSERT_NOT_NULL(accesses);\n\n    for (int i = 0, h = 0, i_h = 1, m = -1, i_m = 0; i < TEST_SIZE; i++, h += i_h, m += i_m) {\n        if (i_m) {\n            accesses[i] = (uint8_t *) (cached + CACHE_SIZE + i);\n        } else {\n            accesses[i] = (uint8_t *) (cached + i);\n        }\n\n        if (h >= hits) {\n            h = -1;\n            i_h = 0;\n\n            m = 0;\n            i_m = 1;\n        }\n\n        if (m >= misses) {\n            m = -1;\n            i_m = 0;\n\n            h = 0;\n            i_h = 1;\n        }\n    }\n\n    out->accesses = accesses;\n    out->len = TEST_SIZE;\n}\n\nstatic ccomp_test_time_t perform_test_at_hit_rate(int hit_rate, const uint8_t *mem)\n{\n    ccomp_test_access_t access;\n    prepare_access_pattern(hit_rate, mem, &access);\n\n    prepare_cache(mem);\n\n    int64_t start = esp_timer_get_time();\n    ccomp_timer_start();\n    perform_accesses(&access);\n    ccomp_test_time_t t = {\n        .ccomp = ccomp_timer_stop(),\n        .wall = esp_timer_get_time() - start\n    };\n\n    free(access.accesses);\n\n    return t;\n}\n\nstatic ccomp_test_time_t ccomp_test_ref_time(void)\n{\n#if CONFIG_SPIRAM\n    uint8_t *mem = heap_caps_malloc(2 * CACHE_SIZE, MALLOC_CAP_INTERNAL | MALLOC_CAP_DEFAULT);\n#else\n    uint8_t *mem = heap_caps_malloc(sizeof(flash_mem), MALLOC_CAP_INTERNAL | MALLOC_CAP_DEFAULT);\n#endif\n    TEST_ASSERT_NOT_NULL(mem);\n    ccomp_test_time_t t = perform_test_at_hit_rate(0, mem);\n    free(mem);\n    return t;\n}\n\nTEST_CASE(\"data cache hit rate sweep\", \"[ccomp_timer]\")\n{\n    ccomp_test_time_t t_ref;\n    ccomp_test_time_t t_hr;\n\n#if CONFIG_SPIRAM\n    flash_mem = heap_caps_malloc(2 * CACHE_SIZE, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);\n#endif\n\n    // Perform accesses on RAM. The time recorded here serves as\n    // reference.\n    t_ref = ccomp_test_ref_time();\n\n    ESP_LOGI(TAG, \"Reference Time(us): %lld\", (long long)t_ref.ccomp);\n\n    // Measure time at particular hit rates\n    for (int i = 0; i <= 100; i += 5) {\n        t_hr = perform_test_at_hit_rate(i, flash_mem);\n        float error = (llabs(t_ref.ccomp - t_hr.ccomp) / (float)t_ref.ccomp) * 100.0f;\n\n        ESP_LOGI(TAG, \"Hit Rate(%%): %d    Wall Time(us): %lld    Compensated Time(us): %lld    Error(%%): %f\", i, (long long)t_hr.wall, (long long)t_hr.ccomp, error);\n\n        // Check if the measured time is at least within some percent of the\n        // reference.\n        TEST_ASSERT(error <= 10.0f);\n    }\n\n#if CONFIG_SPIRAM\n    free(flash_mem);\n#endif\n}\n#endif // __riscv\n"
  },
  {
    "path": "ccomp_timer/test_apps/main/ccomp_timer_test_inst.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n#include <stdlib.h>\n#include <stdint.h>\n\n#include \"esp_timer.h\"\n#include \"esp_log.h\"\n#include \"esp_attr.h\"\n#include \"ccomp_timer.h\"\n\n#include \"freertos/FreeRTOS.h\"\n\n#include \"unity.h\"\n\n#include \"sdkconfig.h\"\n\n#if CONFIG_IDF_TARGET_ESP32\n#define CACHE_WAYS              2\n#define CACHE_LINE_SIZE         32\n#define CACHE_SIZE              (1 << 15)\n// Only test half due to lack of memory\n#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3\n// Default cache configuration - no override specified on\n#define CACHE_WAYS              8\n#define CACHE_LINE_SIZE         32\n#define CACHE_SIZE              (1 << 13)\n#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2\n#define CACHE_WAYS              8\n#define CACHE_LINE_SIZE         32\n#define CACHE_SIZE              (1 << 14)\n#endif\n\ntypedef void (*ccomp_test_func_t)(void);\n\nstatic const char *TAG = \"test_ccomp_timer\";\n\ntypedef struct {\n    int64_t wall;\n    int64_t ccomp;\n} ccomp_test_time_t;\n\ntypedef struct {\n    ccomp_test_func_t *funcs;\n    size_t len;\n} ccomp_test_call_t;\n\n#define FUNC()              \\\n    do                      \\\n    {                       \\\n        volatile int a = 0; \\\n        a++;                \\\n    } while (0);\n\n__aligned(CACHE_SIZE / CACHE_WAYS) static void test_func1(void)\n{\n    FUNC();\n}\n\n__aligned(CACHE_SIZE / CACHE_WAYS) static void test_func2(void)\n{\n    FUNC();\n}\n\n__aligned(CACHE_SIZE / CACHE_WAYS) static void test_func3(void)\n{\n    FUNC();\n}\n\n#if TEMPORARY_DISABLED_FOR_TARGETS(ESP32)\n__aligned(CACHE_SIZE / CACHE_WAYS) static void test_func4(void)\n{\n    FUNC();\n}\n\n__aligned(CACHE_SIZE / CACHE_WAYS) static void test_func5(void)\n{\n    FUNC();\n}\n\n__aligned(CACHE_SIZE / CACHE_WAYS) static void test_func6(void)\n{\n    FUNC();\n}\n\n__aligned(CACHE_SIZE / CACHE_WAYS) static void test_func7(void)\n{\n    FUNC();\n}\n\n__aligned(CACHE_SIZE / CACHE_WAYS) static void test_func8(void)\n{\n    FUNC();\n}\n\n__aligned(CACHE_SIZE / CACHE_WAYS) static void test_func9(void)\n{\n    FUNC();\n}\n#endif\n\nstatic void IRAM_ATTR iram_func(void)\n{\n    FUNC();\n}\n\nstatic void IRAM_ATTR perform_calls(ccomp_test_call_t *call)\n{\n    for (int i = 0; i < call->len; i++) {\n        call->funcs[i]();\n    }\n}\n\nstatic void IRAM_ATTR prepare_cache(ccomp_test_call_t *call)\n{\n    perform_calls(call);\n}\n\nstatic void IRAM_ATTR prepare_calls(int hit_rate, ccomp_test_func_t *alts, size_t alts_len, size_t len, ccomp_test_call_t *out)\n{\n    assert(hit_rate <= 100);\n    assert(hit_rate >= 0);\n\n    int misses = (100 - hit_rate);\n    int hits = hit_rate;\n\n    ccomp_test_func_t *funcs = calloc(len, sizeof(ccomp_test_func_t));\n\n    for (int i = 0, h = 0, i_h = 1, m = -1, i_m = 0, l = 0; i < len; i++, h += i_h, m += i_m) {\n        funcs[i] = alts[l % alts_len];\n\n        if (i_m) {\n            l++;\n        }\n\n        if (h >= hits) {\n            h = -1;\n            i_h = 0;\n\n            m = 0;\n            i_m = 1;\n        }\n\n        if (m >= misses) {\n            m = -1;\n            i_m = 0;\n\n            h = 0;\n            i_h = 1;\n        }\n    }\n\n    out->funcs = funcs;\n    out->len = len;\n}\n\nstatic ccomp_test_time_t IRAM_ATTR perform_test_at_hit_rate(int hit_rate)\n{\n    static portMUX_TYPE m = portMUX_INITIALIZER_UNLOCKED;\n    ccomp_test_call_t calls;\n    ccomp_test_func_t alts[] = {test_func1, test_func2, test_func3,\n#if TEMPORARY_DISABLED_FOR_TARGETS(ESP32)\n                                test_func4, test_func5, test_func6, test_func7, test_func8, test_func9,\n#endif\n                               };\n    prepare_calls(hit_rate, alts, sizeof(alts) / sizeof(alts[0]), 10000, &calls);\n\n    ccomp_test_func_t f[] = {test_func1, test_func2};\n    ccomp_test_call_t cache = {\n        .funcs = f,\n        .len = sizeof(f) / sizeof(f[0])\n    };\n\n    portENTER_CRITICAL(&m);\n\n    prepare_cache(&cache);\n\n    int64_t start = esp_timer_get_time();\n    ccomp_timer_start();\n    perform_calls(&calls);\n    ccomp_test_time_t t = {\n        .ccomp = ccomp_timer_stop(),\n        .wall = esp_timer_get_time() - start\n    };\n\n    portEXIT_CRITICAL(&m);\n\n    free(calls.funcs);\n\n    return t;\n}\n\nstatic ccomp_test_time_t ccomp_test_ref_time(void)\n{\n    ccomp_test_call_t calls;\n    ccomp_test_func_t alts[] = {iram_func};\n    prepare_calls(0, alts, 1, 10000, &calls);\n\n    int64_t start = esp_timer_get_time();\n    ccomp_timer_start();\n    perform_calls(&calls);\n    ccomp_test_time_t t = {\n        .ccomp = ccomp_timer_stop(),\n        .wall = esp_timer_get_time() - start\n    };\n\n    free(calls.funcs);\n\n    return t;\n}\n\nTEST_CASE(\"instruction cache hit rate sweep test\", \"[ccomp_timer]\")\n{\n    ccomp_test_time_t t_ref;\n    ccomp_test_time_t t_hr;\n\n    // Perform accesses on RAM. The time recorded here serves as\n    // reference.\n    t_ref = ccomp_test_ref_time();\n\n    ESP_LOGI(TAG, \"Reference Time(us): %lld\", (long long)t_ref.ccomp);\n\n    // Measure time at particular hit rates\n    for (int i = 0; i <= 100; i += 5) {\n        t_hr = perform_test_at_hit_rate(i);\n        float error = (llabs(t_ref.ccomp - t_hr.ccomp) / (float)t_ref.wall) * 100.0f;\n\n        ESP_LOGI(TAG, \"Hit Rate(%%): %d    Wall Time(us): %lld    Compensated Time(us): %lld    Error(%%): %f\", i, (long long)t_hr.wall, (long long)t_hr.ccomp, error);\n\n        // Check if the measured time is at least within some percent of the\n        // reference.\n        TEST_ASSERT(error <= 5.0f);\n    }\n}\n"
  },
  {
    "path": "ccomp_timer/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/ccomp_timer:\n    version: \"*\"\n    override_path: ../../\n"
  },
  {
    "path": "ccomp_timer/test_apps/pytest_ccomp_timer.py",
    "content": "import pytest\n\n\n@pytest.mark.generic\ndef test_ccomp_timer(dut) -> None:\n    dut.run_all_single_board_cases()\n"
  },
  {
    "path": "ccomp_timer/test_apps/sdkconfig.defaults",
    "content": "# This file was generated using idf.py save-defconfig. It can be edited manually.\n# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration\n#\nCONFIG_ESP_TASK_WDT_INIT=n\n"
  },
  {
    "path": "cjson/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"cJSON/cJSON.c\"\n                            \"cJSON/cJSON_Utils.c\"\n                    INCLUDE_DIRS \"cJSON\")\n\ntarget_compile_definitions(${COMPONENT_LIB} PUBLIC\n    CJSON_NESTING_LIMIT=${CONFIG_CJSON_NESTING_LIMIT}\n    CJSON_CIRCULAR_LIMIT=${CONFIG_CJSON_CIRCULAR_LIMIT})\n"
  },
  {
    "path": "cjson/Kconfig",
    "content": "menu \"cJSON\"\n\n    config CJSON_NESTING_LIMIT\n        int \"Maximum nesting depth for JSON parsing\"\n        default 1000\n        help\n            Limits how deeply nested arrays/objects can be before cJSON\n            rejects to parse them. This is to prevent stack overflows.\n            Lower values use less stack, higher values allow deeper nesting.\n\n    config CJSON_CIRCULAR_LIMIT\n        int \"Maximum depth for circular reference detection\"\n        default 10000\n        help\n            Limits the depth for circular reference detection during\n            printing/comparison operations. This prevents infinite loops\n            and stack overflows when processing JSON structures with\n            circular references. Lower values use less stack.\n\nendmenu\n"
  },
  {
    "path": "cjson/idf_component.yml",
    "content": "version: \"1.7.19~2\"\ndescription: \"cJSON: Ultralightweight JSON parser in ANSI C\"\nurl: https://github.com/espressif/idf-extra-components/tree/master/cjson\ndependencies:\n  idf: \">=5.0\"\nsbom:\n  manifests:\n    - path: sbom_cJSON.yml\n      dest: cJSON\n"
  },
  {
    "path": "cjson/sbom_cJSON.yml",
    "content": "name: cJSON\nversion: \"1.7.19\"\ncpe:\n - cpe:2.3:a:cjson_project:cjson:{}:*:*:*:*:*:*:*\n - cpe:2.3:a:davegamble:cjson:{}:*:*:*:*:*:*:*\nsupplier: 'Person: Dave Gamble'\ndescription: \"cJSON: Ultralightweight JSON parser in ANSI C\"\nurl: https://github.com/DaveGamble/cJSON\nhash: b2890c8d76bbb64e710585ebc0a917196b9c67e7\n"
  },
  {
    "path": "coap/CMakeLists.txt",
    "content": "set(include_dirs port/include libcoap/include)\n\nset(srcs\n    \"libcoap/src/coap_address.c\"\n    \"libcoap/src/coap_asn1.c\"\n    \"libcoap/src/coap_async.c\"\n    \"libcoap/src/coap_block.c\"\n    \"libcoap/src/coap_cache.c\"\n    \"libcoap/src/coap_debug.c\"\n    \"libcoap/src/coap_dtls.c\"\n    \"libcoap/src/coap_encode.c\"\n    \"libcoap/src/coap_event.c\"\n    \"libcoap/src/coap_hashkey.c\"\n    \"libcoap/src/coap_io.c\"\n    \"libcoap/src/coap_layers.c\"\n    \"libcoap/src/coap_mbedtls.c\"\n    \"libcoap/src/coap_mem.c\"\n    \"libcoap/src/coap_net.c\"\n    \"libcoap/src/coap_netif.c\"\n    \"libcoap/src/coap_notls.c\"\n    \"libcoap/src/coap_option.c\"\n    \"libcoap/src/coap_oscore.c\"\n    \"libcoap/src/coap_pdu.c\"\n    \"libcoap/src/coap_prng.c\"\n    \"libcoap/src/coap_proxy.c\"\n    \"libcoap/src/coap_resource.c\"\n    \"libcoap/src/coap_session.c\"\n    \"libcoap/src/coap_str.c\"\n    \"libcoap/src/coap_subscribe.c\"\n    \"libcoap/src/coap_tcp.c\"\n    \"libcoap/src/coap_time.c\"\n    \"libcoap/src/coap_threadsafe.c\"\n    \"libcoap/src/coap_uri.c\"\n    \"libcoap/src/coap_ws.c\")\n\nif(CONFIG_COAP_OSCORE_SUPPORT)\n    list(APPEND srcs\n        \"libcoap/src/oscore/oscore.c\"\n        \"libcoap/src/oscore/oscore_cbor.c\"\n        \"libcoap/src/oscore/oscore_context.c\"\n        \"libcoap/src/oscore/oscore_cose.c\"\n        \"libcoap/src/oscore/oscore_crypto.c\")\nendif()\n\nidf_component_register(SRCS \"${srcs}\"\n                    INCLUDE_DIRS \"${include_dirs}\"\n                    REQUIRES lwip mbedtls)\ntarget_compile_options(${COMPONENT_LIB} PRIVATE \"-Wno-format\")\n\n"
  },
  {
    "path": "coap/Kconfig",
    "content": "menu \"CoAP Configuration\"\n    config COAP_MBEDTLS_PSK\n        bool \"Pre-Shared Keys\"\n        default y\n        help\n            If the CoAP information is to be encrypted, the encryption environment\n            can be set up using Pre-Shared keys (PSK) mode.\n\n            - Encrypt using defined Pre-Shared Keys (PSK if uri includes coaps://)\n            - Note: If PKI is set as well, a server will decide which method to use\n                    based on the incoming encryption request. It is up to the client\n                    logic to decide which one to use.\n\n    config COAP_MBEDTLS_PKI\n        bool \"PKI Certificates\"\n        default n\n        help\n            If the CoAP information is to be encrypted, the encryption environment\n            can be set up using Public Key Infrastructure (PKI) mode.\n\n            - Encrypt using defined Public Key Infrastructure (PKI if uri includes coaps://)\n            - Note: If PSK is set as well, a server will decide which method to use\n                    based on the incoming encryption request. It is up to the client\n                    logic to decide which one to use.\n\n    config COAP_DEBUGGING\n        bool \"Enable CoAP debugging\"\n        default n\n        help\n            Enable CoAP debugging functions at compile time for the example code.\n\n            If this option is enabled, call coap_set_log_level()\n            at runtime in order to enable CoAP debug output via the ESP\n            log mechanism.\n\n            Note: The Mbed TLS library logging is controlled by the mbedTLS\n            configuration, but logging level mbedTLS must be set for CoAP\n            to log it.\n\n    choice COAP_DEBUGGING_LEVEL\n        bool \"Set CoAP debugging level\"\n        depends on COAP_DEBUGGING\n        default COAP_LOG_WARNING\n        help\n            Set CoAP debugging level\n\n        config COAP_LOG_EMERG\n            bool \"Emergency\"\n        config COAP_LOG_ALERT\n            bool \"Alert\"\n        config COAP_LOG_CRIT\n            bool \"Critical\"\n        config COAP_LOG_ERROR\n            bool \"Error\"\n        config COAP_LOG_WARNING\n            bool \"Warning\"\n        config COAP_LOG_NOTICE\n            bool \"Notice\"\n        config COAP_LOG_INFO\n            bool \"Info\"\n        config COAP_LOG_DEBUG\n            bool \"Debug\"\n        config COAP_LOG_OSCORE\n            bool \"OSCORE\"\n    endchoice\n\n    config COAP_LOG_DEFAULT_LEVEL\n        int\n        default 0 if !COAP_DEBUGGING\n        default 0 if COAP_LOG_EMERG\n        default 1 if COAP_LOG_ALERT\n        default 2 if COAP_LOG_CRIT\n        default 3 if COAP_LOG_ERROR\n        default 4 if COAP_LOG_WARNING\n        default 5 if COAP_LOG_NOTICE\n        default 6 if COAP_LOG_INFO\n        default 7 if COAP_LOG_DEBUG\n        default 8 if COAP_LOG_OSCORE\n\n    config COAP_TCP_SUPPORT\n        bool \"Enable TCP within CoAP\"\n        default y\n        help\n            Enable TCP functionality for CoAP. This is required if TLS sessions\n            are to be used.\n\n            If this option is disabled, redundant CoAP TCP code is removed.\n\n    config COAP_OSCORE_SUPPORT\n        bool \"Enable OSCORE support within CoAP\"\n        default n\n        help\n            Enable OSCORE (Object Security for Constrained RESTful Environments) functionality for CoAP.\n\n            If this option is disabled, redundant CoAP OSCORE code is removed.\n\n    config COAP_OBSERVE_PERSIST\n        bool \"Enable Server Observe Persist support within CoAP\"\n        default n\n        help\n            Enable Server Observe Persist support for CoAP.\n\n            If this option is disabled, redundant CoAP Observe Persist code is removed.\n\n    config COAP_Q_BLOCK\n        bool \"Enable Q-Block (RFC9177) support in CoAP\"\n        default n\n        help\n            Enable Q-Block (RFC9177) fast block transfers using NON (instead of CON) support for CoAP\n\n    config COAP_ASYNC_SUPPORT\n        bool \"Enable asynchronous separate response support in CoAP\"\n        default y\n        help\n            Enable support for asynchronous separate responses in CoAP\n\n    config COAP_THREAD_SAFE\n        bool \"Enable thread-safe support within CoAP\"\n        default n\n        help\n            Enable thread-safe support for CoAP.\n\n            If this option is disabled, CoAP is not multi-threaded safe\n\n    config COAP_THREAD_RECURSIVE_CHECK\n        bool \"Enable thread-safe recursion checking support within CoAP\"\n        depends on COAP_THREAD_SAFE\n        default n\n        help\n            Enable thread-safe recursion checking support for CoAP.\n\n            If this option is disabled, recursive locking occur in CoAP\n\n    config COAP_WEBSOCKETS\n        bool \"Enable WebSockets support within CoAP\"\n        default n\n        help\n            Enable WebSockets support for CoAP.\n\n            If this option is disabled, redundant CoAP WebSocket code is removed.\n\n    config COAP_CLIENT_SUPPORT\n        bool \"Enable Client functionality within CoAP\"\n        default n\n        help\n            Enable client functionality (ability to make requests and receive\n            responses) for CoAP. If the server is going to act as a proxy, then\n            this needs to be enabled to support the ongoing session going to\n            the next hop.\n\n            If this option is disabled, redundant CoAP client only code is removed.\n            If both this option and COAP_SERVER_SUPPORT are disabled, then both\n            are automatically enabled for backwards compatibility.\n\n    config COAP_SERVER_SUPPORT\n        bool \"Enable Server functionality within CoAP\"\n        default n\n        help\n            Enable server functionality (ability to receive requests and send\n            responses) for CoAP.\n\n            If this option is disabled, redundant CoAP server only code is removed.\n            If both this option and COAP_CLIENT_SUPPORT are disabled, then both\n            are automatically enabled for backwards compatibility.\n\n    config COAP_PROXY_SUPPORT\n        bool \"Enable Proxy functionality within CoAP\"\n        depends on COAP_CLIENT_SUPPORT && COAP_SERVER_SUPPORT\n        default n\n        help\n            Enable Proxy functionality (ability to receive requests, pass\n            them to an upstream server and send back responses to client)\n            for CoAP.\n\n            If this option is disabled, redundant CoAP proxy only code is\n            removed.\n\nendmenu\n"
  },
  {
    "path": "coap/examples/coap_client/CMakeLists.txt",
    "content": "# The following lines of boilerplate have to be in your project's CMakeLists\n# in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main esp_eth)\nproject(coap_client)\n"
  },
  {
    "path": "coap/examples/coap_client/README.md",
    "content": "| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |\n| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |\n\n\n# CoAP client example\n\n(See the README.md file in the upper level esp-idf 'examples' directory for more information\nabout examples.)\n\nThis CoAP client example is very simplified adaptation of one of the\n[libcoap](https://github.com/obgm/libcoap) examples.\n\nCoAP client example will connect your ESP32 device to a CoAP server, send off a GET request and\nfetch the response data from CoAP server.  The client can be extended to PUT / POST / DELETE requests,\nas well as supporting the Observer extensions [RFC7641](https://tools.ietf.org/html/rfc7641).\n\nIf the URI is prefixed with coaps:// instead of coap://, then the CoAP client will attempt to use\nthe DTLS protocol using the defined Pre-Shared Keys(PSK) or Public Key Infrastructure (PKI) which the\nCoAP server needs to know about. If both PSK and PKI are defined, then it is the responsibility\nof the client code to decide (PSK or PKI) which to use.\n\nIf the URI is prefixed with coap+tcp://, then the CoAP will try to use TCP for the communication.\n\nIf the URI is prefixed with coaps+tcp://, then the CoAP will try to use TLS for the communication.\nIf both PSK and PKI are defined, then it is the responsibility of the client code to decide (PSK\nor PKI) which to use.\n\nIf the URI is prefixed with coap+ws://, then the CoAP will try to use WebSockets (over TCP) for\nthe communication, which assumes that CoAP WebSockets is enabled in the build.\n\nIf the URI is prefixed with coaps+ws://, then the CoAP will try to use WebSockets (over TLS) for\nthe communication, which assumes that CoAP WebSockets is enabled in the build.\nIf both PSK and PKI are defined, then it is the responsibility of the client code to decide (PSK\nor PKI) which to use.\n\nThe Constrained Application Protocol (CoAP) is a specialized web transfer protocol for use with\nconstrained nodes and constrained networks in the Internet of Things.\nThe protocol is designed for machine-to-machine (M2M) applications such as smart energy and\nbuilding automation.\n\nPlease refer to [RFC7252](https://www.rfc-editor.org/rfc/pdfrfc/rfc7252.txt.pdf) for more details.\n\n## How to use example\n\n### Configure the project\n\n```\nidf.py menuconfig\n```\n\nExample Connection Configuration  --->\n * Set WiFi SSID\n * Set WiFi Password\nComponent config  --->\n  CoAP Configuration  --->\n    * Set encryption method definition, PSK (default) and/or PKI\n    * Enable CoAP debugging if required\n    * Disable CoAP using TCP if this is not required (TCP needed for TLS or WebSockets)\n    * Disable CoAP server functionality to reduce code size\n    * Enable OSCORE (RFC8613) support if required\n    * Enable WebSockets (RFC8323) support if required\nExample CoAP Client Configuration  --->\n * Set CoAP Target Uri\n * If PSK, Set CoAP Preshared Key to use in connection to the server\n * If PSK, Set CoAP PSK Client identity (username)\n\nNote:\n * For enabled PKI, the certificates are stored in main/certs.\n * For enabled OSCORE, the OSCORE configuration is stored in main/oscore and will be used on\n   every request.\n\n### Build and Flash\n\nBuild the project and flash it to the board, then run monitor tool to view serial output:\n\n```\nidf.py build\nidf.py -p PORT flash monitor\n```\n\n(To exit the serial monitor, type ``Ctrl-]``.)\n\nSee the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.\n\n## Example Output\nPrerequisite: we startup a CoAP server on coap server example,\nor use the default of coap://californium.eclipseprojects.io.\n\nand you could receive data from CoAP server if succeed,\nsuch as the following log:\n\n```\n...\nI (332) wifi: mode : sta (30:ae:a4:04:1b:7c)\nI (1672) wifi: n:11 0, o:1 0, ap:255 255, sta:11 0, prof:1\nI (1672) wifi: state: init -> auth (b0)\nI (1682) wifi: state: auth -> assoc (0)\nI (1692) wifi: state: assoc -> run (10)\nI (1692) wifi: connected with huawei_cw, channel 11\nI (1692) wifi: pm start, type: 1\n\nI (2582) event: sta ip: 192.168.3.89, mask: 255.255.255.0, gw: 192.168.3.1\nI (2582) CoAP_client: Connected to AP\nI (2582) CoAP_client: DNS lookup succeeded. IP=35.185.40.182\nReceived:\n****************************************************************\nCoAP RFC 7252                                  Cf 3.0.0-SNAPSHOT\n****************************************************************\nThis server is using the Eclipse Californium (Cf) CoAP framework\npublished under EPL+EDL: http://www.eclipse.org/californium/\n\n(c) 2014-2020 Institute for Pervasive Computing, ETH Zurich and others\n****************************************************************\n...\n```\n\n## libcoap Documentation\nThis can be found at [libcoap Documentation](https://libcoap.net/documentation.html).\nThe current API is 4.3.4.\n\n## libcoap Specific Issues\nThese can be raised at [libcoap Issues](https://github.com/obgm/libcoap/issues).\n\n## Troubleshooting\n* Please make sure Target Url includes valid `host`, optional `port`,\noptional `path`, and begins with `coap://`, `coaps://`, `coap+tcp://`, `coaps+tcp://`,\n`coap+ws://` or `coaps+ws://`.\n  * Not all hosts support TCP/TLS including coap+tcp://californium.eclipseprojects.io\n  * Not all hosts support WebSockets, which needs to be enabled as an option\n\n* CoAP logging can be enabled by running\n'idf.py menuconfig -> Component config -> CoAP Configuration -> Enable CoAP debugging'\nand setting appropriate log level.  If Mbed TLS logging is required, this needs to be\nconfigured separately under mbedTLS Component Configuration.\n"
  },
  {
    "path": "coap/examples/coap_client/main/CMakeLists.txt",
    "content": "# Embed CA, certificate & key directly into binary\nidf_component_register(SRCS \"coap_client_example_main.c\"\n                    INCLUDE_DIRS \".\"\n                    EMBED_TXTFILES certs/coap_ca.pem certs/coap_client.crt certs/coap_client.key oscore/coap_oscore.conf)\n"
  },
  {
    "path": "coap/examples/coap_client/main/Kconfig.projbuild",
    "content": "menu \"Example CoAP Client Configuration\"\n\n    config EXAMPLE_TARGET_DOMAIN_URI\n        string \"Target Uri\"\n        default \"coaps://californium.eclipseprojects.io\"\n        help\n            Target uri for the example to use. Use coaps:// prefix for encrypted traffic\n            using Pre-Shared Key (PSK) or Public Key Infrastructure (PKI).\n\n    config EXAMPLE_COAP_PSK_KEY\n        string \"Preshared Key (PSK) to used in the connection to the CoAP server\"\n        depends on COAP_MBEDTLS_PSK\n        default \"sesame\"\n        help\n            The Preshared Key to use to encrypt the communicatons. The same key must be\n            used at both ends of the CoAP connection, and the CoaP client must request\n            an URI prefixed with coaps:// instead of coap:// for DTLS to be used.\n\n    config EXAMPLE_COAP_PSK_IDENTITY\n        string \"PSK Client identity (username)\"\n        depends on COAP_MBEDTLS_PSK\n        default \"password\"\n        help\n            The identity (or username) to use to identify to the CoAP server which\n            PSK key to use.\n\nendmenu\n"
  },
  {
    "path": "coap/examples/coap_client/main/certs/coap_ca.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIICDDCCAbKgAwIBAgIIPKO8L7vZoqAwCgYIKoZIzj0EAwIwXDEQMA4GA1UEAxMH\nY2Ytcm9vdDEUMBIGA1UECxMLQ2FsaWZvcm5pdW0xFDASBgNVBAoTC0VjbGlwc2Ug\nSW9UMQ8wDQYDVQQHEwZPdHRhd2ExCzAJBgNVBAYTAkNBMB4XDTIzMTAyNjA4MDgx\nNVoXDTI1MTAyNTA4MDgxNVowWjEOMAwGA1UEAxMFY2YtY2ExFDASBgNVBAsTC0Nh\nbGlmb3JuaXVtMRQwEgYDVQQKEwtFY2xpcHNlIElvVDEPMA0GA1UEBxMGT3R0YXdh\nMQswCQYDVQQGEwJDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLCbJjxIS4hI\nAnRFTlx23gkd4zyFd50zdpTnoUPz19oQ1o1youavC5Go9vrYoWxyx+zpph8T4brB\nC/mZGIgPVMOjYDBeMB0GA1UdDgQWBBSxVzoI1TL87++hsUb9vQwqODzgUTALBgNV\nHQ8EBAMCAQYwDwYDVR0TBAgwBgEB/wIBATAfBgNVHSMEGDAWgBTqNhC1fqOTsHRn\nIVZ9OabfWsxpcTAKBggqhkjOPQQDAgNIADBFAiBSEn3egc31JhhHTVYi5uhl0t4d\newujkEmwzBuruzf/xAIhAK/fXy2tsNoyLitFQ97x6LYV25jKmLKUlhL2mC/PwQdO\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICDDCCAbKgAwIBAgIIPKO8L7vZoqAwCgYIKoZIzj0EAwIwXDEQMA4GA1UEAxMH\nY2Ytcm9vdDEUMBIGA1UECxMLQ2FsaWZvcm5pdW0xFDASBgNVBAoTC0VjbGlwc2Ug\nSW9UMQ8wDQYDVQQHEwZPdHRhd2ExCzAJBgNVBAYTAkNBMB4XDTIzMTAyNjA4MDgx\nNVoXDTI1MTAyNTA4MDgxNVowWjEOMAwGA1UEAxMFY2YtY2ExFDASBgNVBAsTC0Nh\nbGlmb3JuaXVtMRQwEgYDVQQKEwtFY2xpcHNlIElvVDEPMA0GA1UEBxMGT3R0YXdh\nMQswCQYDVQQGEwJDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLCbJjxIS4hI\nAnRFTlx23gkd4zyFd50zdpTnoUPz19oQ1o1youavC5Go9vrYoWxyx+zpph8T4brB\nC/mZGIgPVMOjYDBeMB0GA1UdDgQWBBSxVzoI1TL87++hsUb9vQwqODzgUTALBgNV\nHQ8EBAMCAQYwDwYDVR0TBAgwBgEB/wIBATAfBgNVHSMEGDAWgBTqNhC1fqOTsHRn\nIVZ9OabfWsxpcTAKBggqhkjOPQQDAgNIADBFAiBSEn3egc31JhhHTVYi5uhl0t4d\newujkEmwzBuruzf/xAIhAK/fXy2tsNoyLitFQ97x6LYV25jKmLKUlhL2mC/PwQdO\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "coap/examples/coap_client/main/certs/coap_client.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIB/TCCAaOgAwIBAgIIVNrVgKT9OE8wCgYIKoZIzj0EAwIwWjEOMAwGA1UEAxMF\nY2YtY2ExFDASBgNVBAsTC0NhbGlmb3JuaXVtMRQwEgYDVQQKEwtFY2xpcHNlIElv\nVDEPMA0GA1UEBxMGT3R0YXdhMQswCQYDVQQGEwJDQTAeFw0yMzEwMjYwODA4MjJa\nFw0yNTEwMjUwODA4MjJaMF4xEjAQBgNVBAMTCWNmLWNsaWVudDEUMBIGA1UECxML\nQ2FsaWZvcm5pdW0xFDASBgNVBAoTC0VjbGlwc2UgSW9UMQ8wDQYDVQQHEwZPdHRh\nd2ExCzAJBgNVBAYTAkNBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEQxYO5/M5\nie6+3QPOaAy5MD6CkFILZwIb2rOBCX/EWPaocX1H+eynUnaEEbmqxeN6rnI/pH19\nj4PtsegfHLrzzaNPME0wHQYDVR0OBBYEFKwEDLTJ+5cQoZfbjWN1vJ2ssgK+MAsG\nA1UdDwQEAwIHgDAfBgNVHSMEGDAWgBSxVzoI1TL87++hsUb9vQwqODzgUTAKBggq\nhkjOPQQDAgNIADBFAiA2KCOw3n2AK9Vm8u2u1bQREIEs3tKAU7eFjpNFn929NwIh\nAInhBGoEwS2Xlu5bdZSfWnujoRrEQiIiQpStmLxVcIsH\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "coap/examples/coap_client/main/certs/coap_client.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg59PuAri3l+8cAbNL\nbFFBAwd/h0cESnSD3iZSGyrr7xGhRANCAARDFg7n8zmJ7r7dA85oDLkwPoKQUgtn\nAhvas4EJf8RY9qhxfUf57KdSdoQRuarF43qucj+kfX2Pg+2x6B8cuvPN\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "coap/examples/coap_client/main/coap_client_example_main.c",
    "content": "/* CoAP client Example\n\n   This example code is in the Public Domain (or CC0 licensed, at your option.)\n\n   Unless required by applicable law or agreed to in writing, this\n   software is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n   CONDITIONS OF ANY KIND, either express or implied.\n*/\n\n/*\n * WARNING\n * libcoap is not multi-thread safe, so only this thread must make any coap_*()\n * calls.  Any external (to this thread) data transmitted in/out via libcoap\n * therefore has to be passed in/out by xQueue*() via this thread.\n */\n\n#include <string.h>\n#include <sys/socket.h>\n#include <netdb.h>\n#include <sys/param.h>\n\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"freertos/event_groups.h\"\n\n#include \"esp_log.h\"\n#include \"esp_wifi.h\"\n#include \"esp_event.h\"\n\n#include \"nvs_flash.h\"\n\n#include \"protocol_examples_common.h\"\n\n#include \"coap_config.h\"\n#include \"coap3/coap.h\"\n\n\n#ifndef CONFIG_COAP_CLIENT_SUPPORT\n#error COAP_CLIENT_SUPPORT needs to be enabled\n#endif /* COAP_CLIENT_SUPPORT */\n\n#define COAP_DEFAULT_TIME_SEC 60\n\n/* The examples use simple Pre-Shared-Key configuration that you can set via\n   'idf.py menuconfig'.\n\n   If you'd rather not, just change the below entries to strings with\n   the config you want - ie #define EXAMPLE_COAP_PSK_KEY \"some-agreed-preshared-key\"\n\n   Note: PSK will only be used if the URI is prefixed with coaps://\n   instead of coap:// and the PSK must be one that the server supports\n   (potentially associated with the IDENTITY)\n*/\n#define EXAMPLE_COAP_PSK_KEY CONFIG_EXAMPLE_COAP_PSK_KEY\n#define EXAMPLE_COAP_PSK_IDENTITY CONFIG_EXAMPLE_COAP_PSK_IDENTITY\n\n/* The examples use uri Logging Level that\n   you can set via 'idf.py menuconfig'.\n\n   If you'd rather not, just change the below entry to a value\n   that is between 0 and 7 with\n   the config you want - ie #define EXAMPLE_COAP_LOG_DEFAULT_LEVEL 7\n\n   Caution: Logging is enabled in libcoap only up to level as defined\n   by 'idf.py menuconfig' to reduce code size.\n*/\n#define EXAMPLE_COAP_LOG_DEFAULT_LEVEL CONFIG_COAP_LOG_DEFAULT_LEVEL\n\n/* The examples use uri \"coap://californium.eclipseprojects.io\" that\n   you can set via the project configuration (idf.py menuconfig)\n\n   If you'd rather not, just change the below entries to strings with\n   the config you want - ie #define COAP_DEFAULT_DEMO_URI \"coaps://californium.eclipseprojects.io\"\n*/\n#define COAP_DEFAULT_DEMO_URI CONFIG_EXAMPLE_TARGET_DOMAIN_URI\n\nconst static char *TAG = \"CoAP_client\";\n\nstatic int resp_wait = 1;\nstatic coap_optlist_t *optlist = NULL;\nstatic int wait_ms;\n#ifdef CONFIG_COAP_OSCORE_SUPPORT\ncoap_oscore_conf_t *oscore_conf = NULL;\n#endif /* CONFIG_COAP_OSCORE_SUPPORT */\n\n#ifdef CONFIG_COAP_MBEDTLS_PKI\n/* CA cert, taken from coap_ca.pem\n   Client cert, taken from coap_client.crt\n   Client key, taken from coap_client.key\n\n   The PEM, CRT and KEY file are examples taken from\n   https://github.com/eclipse/californium/tree/master/demo-certs/src/main/resources\n   as the Certificate test (by default) is against the californium server.\n\n   To embed it in the app binary, the PEM, CRT and KEY file is named\n   in the CMakeLists.txt EMBED_TXTFILES definition.\n */\nextern uint8_t ca_pem_start[] asm(\"_binary_coap_ca_pem_start\");\nextern uint8_t ca_pem_end[]   asm(\"_binary_coap_ca_pem_end\");\nextern uint8_t client_crt_start[] asm(\"_binary_coap_client_crt_start\");\nextern uint8_t client_crt_end[]   asm(\"_binary_coap_client_crt_end\");\nextern uint8_t client_key_start[] asm(\"_binary_coap_client_key_start\");\nextern uint8_t client_key_end[]   asm(\"_binary_coap_client_key_end\");\n#endif /* CONFIG_COAP_MBEDTLS_PKI */\n\n#ifdef CONFIG_COAP_OSCORE_SUPPORT\nextern uint8_t oscore_conf_start[] asm(\"_binary_coap_oscore_conf_start\");\nextern uint8_t oscore_conf_end[]   asm(\"_binary_coap_oscore_conf_end\");\n#endif /* CONFIG_COAP_OSCORE_SUPPORT */\n\nstatic coap_response_t\nmessage_handler(coap_session_t *session,\n                const coap_pdu_t *sent,\n                const coap_pdu_t *received,\n                const coap_mid_t mid)\n{\n    const unsigned char *data = NULL;\n    size_t data_len;\n    size_t offset;\n    size_t total;\n    coap_pdu_code_t rcvd_code = coap_pdu_get_code(received);\n\n    if (COAP_RESPONSE_CLASS(rcvd_code) == 2) {\n        if (coap_get_data_large(received, &data_len, &data, &offset, &total)) {\n            if (data_len != total) {\n                printf(\"Unexpected partial data received offset %u, length %u\\n\", offset, data_len);\n            }\n            printf(\"Received:\\n%.*s\\n\", (int)data_len, data);\n            resp_wait = 0;\n        }\n        return COAP_RESPONSE_OK;\n    }\n    printf(\"%d.%02d\", (rcvd_code >> 5), rcvd_code & 0x1F);\n    if (coap_get_data_large(received, &data_len, &data, &offset, &total)) {\n        printf(\": \");\n        while (data_len--) {\n            printf(\"%c\", isprint(*data) ? *data : '.');\n            data++;\n        }\n    }\n    printf(\"\\n\");\n    resp_wait = 0;\n    return COAP_RESPONSE_OK;\n}\n\n#ifdef CONFIG_COAP_MBEDTLS_PKI\n\nstatic int\nverify_cn_callback(const char *cn,\n                   const uint8_t *asn1_public_cert,\n                   size_t asn1_length,\n                   coap_session_t *session,\n                   unsigned depth,\n                   int validated,\n                   void *arg\n                  )\n{\n    coap_log_info(\"CN '%s' presented by server (%s)\\n\",\n                  cn, depth ? \"CA\" : \"Certificate\");\n    return 1;\n}\n#endif /* CONFIG_COAP_MBEDTLS_PKI */\n\nstatic void\ncoap_log_handler (coap_log_t level, const char *message)\n{\n    uint32_t esp_level = ESP_LOG_INFO;\n    const char *cp = strchr(message, '\\n');\n\n    while (cp) {\n        ESP_LOG_LEVEL(esp_level, TAG, \"%.*s\", (int)(cp - message), message);\n        message = cp + 1;\n        cp = strchr(message, '\\n');\n    }\n    if (message[0] != '\\000') {\n        ESP_LOG_LEVEL(esp_level, TAG, \"%s\", message);\n    }\n}\n\n#ifdef CONFIG_COAP_MBEDTLS_PSK\nstatic coap_session_t *\ncoap_start_psk_session(coap_context_t *ctx, coap_address_t *dst_addr, coap_uri_t *uri, coap_proto_t proto)\n{\n    static coap_dtls_cpsk_t dtls_psk;\n    static char client_sni[256];\n\n    memset(client_sni, 0, sizeof(client_sni));\n    memset (&dtls_psk, 0, sizeof(dtls_psk));\n    dtls_psk.version = COAP_DTLS_CPSK_SETUP_VERSION;\n    dtls_psk.validate_ih_call_back = NULL;\n    dtls_psk.ih_call_back_arg = NULL;\n    if (uri->host.length) {\n        memcpy(client_sni, uri->host.s, MIN(uri->host.length, sizeof(client_sni) - 1));\n    } else {\n        memcpy(client_sni, \"localhost\", 9);\n    }\n    dtls_psk.client_sni = client_sni;\n    dtls_psk.psk_info.identity.s = (const uint8_t *)EXAMPLE_COAP_PSK_IDENTITY;\n    dtls_psk.psk_info.identity.length = sizeof(EXAMPLE_COAP_PSK_IDENTITY) - 1;\n    dtls_psk.psk_info.key.s = (const uint8_t *)EXAMPLE_COAP_PSK_KEY;\n    dtls_psk.psk_info.key.length = sizeof(EXAMPLE_COAP_PSK_KEY) - 1;\n#ifdef CONFIG_COAP_OSCORE_SUPPORT\n    return coap_new_client_session_oscore_psk(ctx, NULL, dst_addr, proto,\n            &dtls_psk, oscore_conf);\n#else /* ! CONFIG_COAP_OSCORE_SUPPORT */\n    return coap_new_client_session_psk2(ctx, NULL, dst_addr, proto,\n                                        &dtls_psk);\n#endif /* ! CONFIG_COAP_OSCORE_SUPPORT */\n}\n#endif /* CONFIG_COAP_MBEDTLS_PSK */\n\n#ifdef CONFIG_COAP_MBEDTLS_PKI\nstatic coap_session_t *\ncoap_start_pki_session(coap_context_t *ctx, coap_address_t *dst_addr, coap_uri_t *uri, coap_proto_t proto)\n{\n    unsigned int ca_pem_bytes = ca_pem_end - ca_pem_start;\n    unsigned int client_crt_bytes = client_crt_end - client_crt_start;\n    unsigned int client_key_bytes = client_key_end - client_key_start;\n    static coap_dtls_pki_t dtls_pki;\n    static char client_sni[256];\n\n    memset (&dtls_pki, 0, sizeof(dtls_pki));\n    dtls_pki.version = COAP_DTLS_PKI_SETUP_VERSION;\n    if (ca_pem_bytes) {\n        /*\n         * Add in additional certificate checking.\n         * This list of enabled can be tuned for the specific\n         * requirements - see 'man coap_encryption'.\n         *\n         * Note: A list of root cas file can be setup separately using\n         * coap_context_set_pki_root_cas(), but the below is used to\n         * define what checking actually takes place.\n         */\n        dtls_pki.verify_peer_cert        = 1;\n        dtls_pki.check_common_ca         = 1;\n        dtls_pki.allow_self_signed       = 1;\n        dtls_pki.allow_expired_certs     = 1;\n        dtls_pki.cert_chain_validation   = 1;\n        dtls_pki.cert_chain_verify_depth = 2;\n        dtls_pki.check_cert_revocation   = 1;\n        dtls_pki.allow_no_crl            = 1;\n        dtls_pki.allow_expired_crl       = 1;\n        dtls_pki.allow_bad_md_hash       = 1;\n        dtls_pki.allow_short_rsa_length  = 1;\n        dtls_pki.validate_cn_call_back   = verify_cn_callback;\n        dtls_pki.cn_call_back_arg        = NULL;\n        dtls_pki.validate_sni_call_back  = NULL;\n        dtls_pki.sni_call_back_arg       = NULL;\n        memset(client_sni, 0, sizeof(client_sni));\n        if (uri->host.length) {\n            memcpy(client_sni, uri->host.s, MIN(uri->host.length, sizeof(client_sni)));\n        } else {\n            memcpy(client_sni, \"localhost\", 9);\n        }\n        dtls_pki.client_sni = client_sni;\n    }\n    dtls_pki.pki_key.key_type = COAP_PKI_KEY_PEM_BUF;\n    dtls_pki.pki_key.key.pem_buf.public_cert = client_crt_start;\n    dtls_pki.pki_key.key.pem_buf.public_cert_len = client_crt_bytes;\n    dtls_pki.pki_key.key.pem_buf.private_key = client_key_start;\n    dtls_pki.pki_key.key.pem_buf.private_key_len = client_key_bytes;\n    dtls_pki.pki_key.key.pem_buf.ca_cert = ca_pem_start;\n    dtls_pki.pki_key.key.pem_buf.ca_cert_len = ca_pem_bytes;\n\n#ifdef CONFIG_COAP_OSCORE_SUPPORT\n    return coap_new_client_session_oscore_pki(ctx, NULL, dst_addr, proto,\n            &dtls_pki, oscore_conf);\n#else /* ! CONFIG_COAP_OSCORE_SUPPORT */\n    return coap_new_client_session_pki(ctx, NULL, dst_addr, proto,\n                                       &dtls_pki);\n#endif /* ! CONFIG_COAP_OSCORE_SUPPORT */\n}\n#endif /* CONFIG_COAP_MBEDTLS_PKI */\n\nstatic coap_session_t *\ncoap_start_anon_pki_session(coap_context_t *ctx, coap_address_t *dst_addr, coap_uri_t *uri, coap_proto_t proto)\n{\n    static coap_dtls_pki_t dtls_pki;\n    static char client_sni[256];\n\n    memset (&dtls_pki, 0, sizeof(dtls_pki));\n    dtls_pki.version = COAP_DTLS_PKI_SETUP_VERSION;\n    memset(client_sni, 0, sizeof(client_sni));\n    if (uri->host.length) {\n        memcpy(client_sni, uri->host.s, MIN(uri->host.length, sizeof(client_sni)));\n    } else {\n        memcpy(client_sni, \"localhost\", 9);\n    }\n    dtls_pki.client_sni = client_sni;\n    dtls_pki.pki_key.key_type = COAP_PKI_KEY_PEM;\n    dtls_pki.pki_key.key.pem.public_cert = NULL;\n    dtls_pki.pki_key.key.pem.private_key = NULL;\n    dtls_pki.pki_key.key.pem.ca_file = NULL;\n\n#ifdef CONFIG_COAP_OSCORE_SUPPORT\n    return coap_new_client_session_oscore_pki(ctx, NULL, dst_addr, proto,\n            &dtls_pki, oscore_conf);\n#else /* ! CONFIG_COAP_OSCORE_SUPPORT */\n    return coap_new_client_session_pki(ctx, NULL, dst_addr, proto,\n                                       &dtls_pki);\n#endif /* ! CONFIG_COAP_OSCORE_SUPPORT */\n}\n\nstatic void coap_example_client(void *p)\n{\n    coap_address_t   dst_addr;\n    static coap_uri_t uri;\n    const char       *server_uri = COAP_DEFAULT_DEMO_URI;\n    coap_context_t *ctx = NULL;\n    coap_session_t *session = NULL;\n    coap_pdu_t *request = NULL;\n    unsigned char token[8];\n    size_t tokenlength;\n    coap_addr_info_t *info_list = NULL;\n    coap_proto_t proto;\n    char tmpbuf[INET6_ADDRSTRLEN];\n#define BUFSIZE 40\n    unsigned char uri_path[BUFSIZE];\n#ifdef CONFIG_COAP_OSCORE_SUPPORT\n    coap_str_const_t osc_conf = { 0, 0};\n#endif /* CONFIG_COAP_OSCORE_SUPPORT */\n\n    /* Initialize libcoap library */\n    coap_startup();\n\n    /* Set up the CoAP logging */\n    coap_set_log_handler(coap_log_handler);\n    coap_set_log_level(EXAMPLE_COAP_LOG_DEFAULT_LEVEL);\n\n    /* Set up the CoAP context */\n    ctx = coap_new_context(NULL);\n    if (!ctx) {\n        ESP_LOGE(TAG, \"coap_new_context() failed\");\n        goto clean_up;\n    }\n    coap_context_set_block_mode(ctx,\n                                COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);\n\n    coap_register_response_handler(ctx, message_handler);\n\n    if (coap_split_uri((const uint8_t *)server_uri, strlen(server_uri), &uri) == -1) {\n        ESP_LOGE(TAG, \"CoAP server uri %s error\", server_uri);\n        goto clean_up;\n    }\n\n    info_list = coap_resolve_address_info(&uri.host, uri.port, uri.port,\n                                          uri.port, uri.port,\n                                          0,\n                                          1 << uri.scheme,\n                                          COAP_RESOLVE_TYPE_REMOTE);\n\n    if (info_list == NULL) {\n        ESP_LOGE(TAG, \"failed to resolve address\");\n        goto clean_up;\n    }\n    proto = info_list->proto;\n    memcpy(&dst_addr, &info_list->addr, sizeof(dst_addr));\n    coap_free_address_info(info_list);\n\n    /* Convert provided uri into CoAP options */\n    if (coap_uri_into_options(&uri, &dst_addr, &optlist, 1,\n                              uri_path, sizeof(uri_path)) < 0) {\n        ESP_LOGE(TAG, \"Failed to create options for URI %s\", server_uri);\n        goto clean_up;\n    }\n    /* This is to keep the test suites happy */\n    coap_print_ip_addr(&dst_addr, tmpbuf, sizeof(tmpbuf));\n    ESP_LOGI(TAG, \"DNS lookup succeeded. IP=%s\", tmpbuf);\n\n#ifdef CONFIG_COAP_OSCORE_SUPPORT\n    osc_conf.s = oscore_conf_start;\n    osc_conf.length = oscore_conf_end - oscore_conf_start;\n    oscore_conf = coap_new_oscore_conf(osc_conf,\n                                       NULL,\n                                       NULL, 0);\n#endif /* CONFIG_COAP_OSCORE_SUPPORT */\n\n    /*\n     * Note that if the URI starts with just coap:// (not coaps://) the\n     * session will still be plain text.\n     */\n    if (uri.scheme == COAP_URI_SCHEME_COAPS || uri.scheme == COAP_URI_SCHEME_COAPS_TCP || uri.scheme == COAP_URI_SCHEME_COAPS_WS) {\n#ifndef CONFIG_MBEDTLS_TLS_CLIENT\n        ESP_LOGE(TAG, \"MbedTLS (D)TLS Client Mode not configured\");\n        goto clean_up;\n#endif /* CONFIG_MBEDTLS_TLS_CLIENT */\n\n        /*\n         * Encrypted request.  Client needs to choose whether using PSK (if configured)\n         * or PKI (if configured) or anonymous PKI (where certificates are not defined locally).\n         * This code chooses PSK (if configured), then PKI (if configured) then anonymous\n         * PKI where certificates are not defined locally.\n         */\n#ifdef CONFIG_COAP_MBEDTLS_PSK\n        session = coap_start_psk_session(ctx, &dst_addr, &uri, proto);\n#endif /* CONFIG_COAP_MBEDTLS_PSK */\n#ifdef CONFIG_COAP_MBEDTLS_PKI\n        if (!session) {\n            session = coap_start_pki_session(ctx, &dst_addr, &uri, proto);\n        }\n#endif /*  CONFIG_COAP_MBEDTLS_PKI */\n        if (!session) {\n            session = coap_start_anon_pki_session(ctx, &dst_addr, &uri, proto);\n        }\n    } else {\n#ifdef CONFIG_COAP_OSCORE_SUPPORT\n        session = coap_new_client_session_oscore(ctx, NULL, &dst_addr, proto, oscore_conf);\n#else /* ! CONFIG_COAP_OSCORE_SUPPORT */\n        session = coap_new_client_session(ctx, NULL, &dst_addr, proto);\n#endif /* ! CONFIG_COAP_OSCORE_SUPPORT */\n    }\n    if (!session) {\n        ESP_LOGE(TAG, \"coap_new_client_session() failed\");\n        goto clean_up;\n    }\n#ifdef CONFIG_COAP_WEBSOCKETS\n    if (proto == COAP_PROTO_WS || proto == COAP_PROTO_WSS) {\n        coap_ws_set_host_request(session, &uri.host);\n    }\n#endif /* CONFIG_COAP_WEBSOCKETS */\n\n    while (1) {\n        request = coap_new_pdu(coap_is_mcast(&dst_addr) ? COAP_MESSAGE_NON : COAP_MESSAGE_CON,\n                               COAP_REQUEST_CODE_GET, session);\n        if (!request) {\n            ESP_LOGE(TAG, \"coap_new_pdu() failed\");\n            goto clean_up;\n        }\n        /* Add in an unique token */\n        coap_session_new_token(session, &tokenlength, token);\n        coap_add_token(request, tokenlength, token);\n\n        /*\n         * To make this a POST, you will need to do the following\n         * Change COAP_REQUEST_CODE_GET to COAP_REQUEST_CODE_POST for coap_new_pdu()\n         * Add in here a Content-Type Option based on the format of the POST text.  E.G. for JSON\n         *   u_char buf[4];\n         *   coap_insert_optlist(&optlist,\n         *                       coap_new_optlist(COAP_OPTION_CONTENT_FORMAT,\n         *                                        coap_encode_var_safe (buf, sizeof (buf),\n         *                                                              COAP_MEDIATYPE_APPLICATION_JSON),\n         *                                        buf));\n         * Add in here the POST data of length length. E.G.\n         *   coap_add_data_large_request(session, request length, data, NULL, NULL);\n         */\n\n        coap_add_optlist_pdu(request, &optlist);\n\n        resp_wait = 1;\n        coap_send(session, request);\n\n        wait_ms = COAP_DEFAULT_TIME_SEC * 1000;\n\n        while (resp_wait) {\n            int result = coap_io_process(ctx, wait_ms > 1000 ? 1000 : wait_ms);\n            if (result >= 0) {\n                if (result >= wait_ms) {\n                    ESP_LOGE(TAG, \"No response from server\");\n                    break;\n                } else {\n                    wait_ms -= result;\n                }\n            }\n        }\n        for (int countdown = 10; countdown >= 0; countdown--) {\n            ESP_LOGI(TAG, \"%d... \", countdown);\n            vTaskDelay(1000 / portTICK_PERIOD_MS);\n        }\n        ESP_LOGI(TAG, \"Starting again!\");\n    }\n\nclean_up:\n    if (optlist) {\n        coap_delete_optlist(optlist);\n        optlist = NULL;\n    }\n    if (session) {\n        coap_session_release(session);\n    }\n    if (ctx) {\n        coap_free_context(ctx);\n    }\n    coap_cleanup();\n\n    ESP_LOGI(TAG, \"Finished\");\n    vTaskDelete(NULL);\n}\n\nvoid app_main(void)\n{\n    ESP_ERROR_CHECK( nvs_flash_init() );\n    ESP_ERROR_CHECK(esp_netif_init());\n    ESP_ERROR_CHECK(esp_event_loop_create_default());\n\n    /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.\n     * Read \"Establishing Wi-Fi or Ethernet Connection\" section in\n     * examples/protocols/README.md for more information about this function.\n     */\n    ESP_ERROR_CHECK(example_connect());\n\n    xTaskCreate(coap_example_client, \"coap\", 8 * 1024, NULL, 5, NULL);\n}\n"
  },
  {
    "path": "coap/examples/coap_client/main/idf_component.yml",
    "content": "version: 1.0.0\ndescription: CoAP Client Example\ndependencies:\n  espressif/coap:\n    version: ^4.3.0\n    override_path: ../../../\n  protocol_examples_common:\n    path: ${IDF_PATH}/examples/common_components/protocol_examples_common\n"
  },
  {
    "path": "coap/examples/coap_client/main/oscore/coap_oscore.conf",
    "content": "# https://libcoap.net/doc/reference/develop/man_coap-oscore-conf.html\nmaster_secret,hex,\"0102030405060708090a0b0c0d0e0f10\"\nmaster_salt,hex,\"9e7ca92223786340\"\nsender_id,hex,\"01\"\nrecipient_id,hex,\"02\"\nid_context,hex,\"37cbf3210017a2d3\"\nreplay_window,integer,30\naead_alg,integer,10\nhkdf_alg,integer,-10\nssn_freq,integer,4\nrfc8613_b_2,bool,true\n"
  },
  {
    "path": "coap/examples/coap_client/partitions.csv",
    "content": "# Name,   Type, SubType, Offset,  Size, Flags\n# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap\nnvs,      data, nvs,     ,        0x6000,\nphy_init, data, phy,     ,        0x1000,\nfactory,  app,  factory, ,        1300K,\n"
  },
  {
    "path": "coap/examples/coap_client/pytest_coap_client_example.py",
    "content": "# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pexpect\nimport pytest\nfrom pytest_embedded import Dut\n\n\n@pytest.mark.ethernet\ndef test_coap_example(dut: Dut) -> None:\n    dut.expect('Loaded app from partition at offset', timeout=30)\n    try:\n        dut.expect(r'IPv4 address: (\\d+\\.\\d+\\.\\d+\\.\\d+)[^\\d]', timeout=30)\n    except pexpect.exceptions.TIMEOUT:\n        raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')\n\n    dut.expect('DNS lookup succeeded', timeout=30)\n    dut.expect('Received', timeout=30)\n    dut.expect(r'This server is using the Eclipse Californium \\(Cf\\) CoAP framework', timeout=30)\n    dut.expect(r'published under EPL\\+EDL: http://www\\.eclipse\\.org/californium/', timeout=30)\n    dut.expect('Starting again!', timeout=30)\n"
  },
  {
    "path": "coap/examples/coap_client/sdkconfig.ci",
    "content": "CONFIG_EXAMPLE_CONNECT_ETHERNET=y\nCONFIG_EXAMPLE_CONNECT_WIFI=n\nCONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y\nCONFIG_EXAMPLE_ETH_MDC_GPIO=23\nCONFIG_EXAMPLE_ETH_MDIO_GPIO=18\nCONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5\nCONFIG_EXAMPLE_ETH_PHY_ADDR=1\nCONFIG_COAP_OSCORE_SUPPORT=y\nCONFIG_COAP_OBSERVE_PERSIST=y\nCONFIG_COAP_WEBSOCKETS=y\n"
  },
  {
    "path": "coap/examples/coap_client/sdkconfig.defaults",
    "content": "CONFIG_MBEDTLS_SSL_PROTO_DTLS=y\nCONFIG_MBEDTLS_PSK_MODES=y\nCONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y\nCONFIG_LWIP_NETBUF_RECVINFO=y\nCONFIG_COAP_CLIENT_SUPPORT=y\n\nCONFIG_PARTITION_TABLE_CUSTOM=y\nCONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions.csv\"\nCONFIG_PARTITION_TABLE_FILENAME=\"partitions.csv\"\n"
  },
  {
    "path": "coap/examples/coap_client/sdkconfig.defaults.esp32h2",
    "content": "CONFIG_EXAMPLE_CONNECT_WIFI=n\nCONFIG_EXAMPLE_CONNECT_ETHERNET=y"
  },
  {
    "path": "coap/examples/coap_server/CMakeLists.txt",
    "content": "# The following lines of boilerplate have to be in your project's CMakeLists\n# in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main esp_eth)\nproject(coap_server)\n"
  },
  {
    "path": "coap/examples/coap_server/README.md",
    "content": "| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |\n| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |\n\n\n# CoAP server example\n\n(See the README.md file in the upper level esp-idf 'examples' directory for more information\nabout examples.)\n\nThis CoAP server example is very simplified adaptation of one of the\n[libcoap](https://github.com/obgm/libcoap) examples.\n\nCoAP server example will startup a daemon task, receive requests / data from CoAP client and transmit\ndata to CoAP client.\n\nIf the incoming request requests the use of DTLS (connecting to port 5684), then the CoAP server will\ntry to establish a DTLS session using the previously defined Pre-Shared Key (PSK) - which\nmust be the same as the one that the CoAP client is using, or Public Key Infrastructure (PKI) where\nthe PKI information must match as requested.\n\nThe Constrained Application Protocol (CoAP) is a specialized web transfer protocol for use with\nconstrained nodes and constrained networks in the Internet of Things.\nThe protocol is designed for machine-to-machine (M2M) applications such as smart energy and\nbuilding automation.\n\nPlease refer to [RFC7252](https://www.rfc-editor.org/rfc/pdfrfc/rfc7252.txt.pdf) for more details.\n\n## How to use example\n\n### Configure the project\n\n```\nidf.py menuconfig\n```\n\nExample Connection Configuration  --->\n * Set WiFi SSID\n * Set WiFi Password\nComponent config  --->\n  CoAP Configuration  --->\n    * Set encryption method definition, PSK (default) and/or PKI\n    * Enable CoAP debugging if required\n    * Disable CoAP using TCP if this is not required (TCP needed for TLS or WebSockets)\n    * Disable CoAP client functionality to reduce code size unless this server is a proxy\n    * Enable OSCORE (RFC8613) support if required\n    * Enable WebSockets (RFC8323) support if required\nExample CoAP Server Configuration  --->\n * If PSK, Set CoAP Preshared Key to use for connections to the server\n\nNote:\n * For enabled PKI, the certificates are stored in main/certs.\n * For enabled OSCORE, the OSCORE configuration is stored in main/oscore.\n\n### Build and Flash\n\nBuild the project and flash it to the board, then run monitor tool to view serial output:\n\n```\nidf.py build\nidf.py -p PORT flash monitor\n```\n\n(To exit the serial monitor, type ``Ctrl-]``.)\n\nSee the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.\n\n## Example Output\ncurrent CoAP server would startup a daemon task,\nand the log is such as the following:\n\n```\n...\nI (332) wifi: mode : sta (30:ae:a4:04:1b:7c)\nI (1672) wifi: n:11 0, o:1 0, ap:255 255, sta:11 0, prof:1\nI (1672) wifi: state: init -> auth (b0)\nI (1682) wifi: state: auth -> assoc (0)\nI (1692) wifi: state: assoc -> run (10)\nI (1692) wifi: connected with huawei_cw, channel 11\nI (1692) wifi: pm start, type: 1\n\nI (2622) event: sta ip: 192.168.3.84, mask: 255.255.255.0, gw: 192.168.3.1\nI (2622) CoAP_server: Connected to AP\n...\n```\n\nIf a CoAP client queries the `/Espressif` resource, CoAP server will return `\"Hello World!\"`\nuntil a CoAP client does a PUT with different data.\n\nIf a clent queries the `/oscore` resource, CoAP server will return `OSCORE Success!` if\nOSCORE is enable AND the client is using OSCORE.\n\n## libcoap Documentation\nThis can be found at [libcoap Documentation](https://libcoap.net/documentation.html).\nThe current API is 4.3.4.\n\n## libcoap Specific Issues\nThese can be raised at [libcoap Issues](https://github.com/obgm/libcoap/issues).\n\n## Troubleshooting\n* Please make sure CoAP client gets or puts data under path: `/Espressif` or\ngets `/.well-known/core`.\n\n* CoAP logging can be enabled by running\n'idf.py menuconfig -> Component config -> CoAP Configuration -> Enable CoAP debugging'\nand setting appropriate log level.  If Mbed TLS logging is required, this needs to be\nconfigured separately under mbedTLS Component Configuration.\n"
  },
  {
    "path": "coap/examples/coap_server/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"coap_server_example_main.c\"\n                    INCLUDE_DIRS \".\"\n                    EMBED_TXTFILES certs/coap_ca.pem certs/coap_server.crt certs/coap_server.key oscore/coap_oscore.conf)\n"
  },
  {
    "path": "coap/examples/coap_server/main/Kconfig.projbuild",
    "content": "menu \"Example CoAP Server Configuration\"\n\n    config EXAMPLE_COAP_PSK_KEY\n        string \"Preshared Key (PSK) to used in the connection from the CoAP client\"\n        depends on COAP_MBEDTLS_PSK\n        default \"secret-key\"\n        help\n            The Preshared Key to use to encrypt the communicatons. The same key must be\n            used at both ends of the CoAP connection, and the CoaP client must request\n            an URI prefixed with coaps:// instead of coap:// for DTLS to be used.\n\n    config EXAMPLE_COAP_LISTEN_PORT\n        string \"CoAP Listen port\"\n        default \"5683\"\n        help\n            Port number to listen for CoAP traffic.\n\n    config EXAMPLE_COAPS_LISTEN_PORT\n        string \"CoAP Secure Listen port\"\n        default \"5684\"\n        depends on COAP_MBEDTLS_PSK || COAP_MBEDTLS_PKI\n        help\n            Port number to listen for CoAP secure ((D)TLS) traffic.\n\n    config EXAMPLE_COAP_WEBSOCKET_PORT\n        string \"CoAP Websocket port\"\n        default \"80\"\n        depends on COAP_WEBSOCKETS\n        help\n            Port number to listen for WebSocket traffic on.\n\n            The default is 80.\n\n    config EXAMPLE_COAP_WEBSOCKET_SECURE_PORT\n        string \"CoAP Websocket Secure port\"\n        default \"443\"\n        depends on COAP_WEBSOCKETS && (COAP_MBEDTLS_PSK || COAP_MBEDTLS_PKI)\n        help\n            Port number to listen for WebSocket Secure (TLS) traffic on.\n\n            The default is 443.\n\n    choice EXAMPLE_COAP_MCAST_IP_MODE\n        prompt \"Receive Multicast IP type\"\n        help\n            Example can receive multicast IPV4, IPV6, both or none.\n\n        config EXAMPLE_COAP_MCAST_NONE\n            bool \"None\"\n\n        config EXAMPLE_COAP_MCAST_IPV4_V6\n            bool \"IPV4 & IPV6\"\n            depends on LWIP_IPV4 && LWIP_IPV6\n            select EXAMPLE_COAP_MCAST_IPV4\n            select EXAMPLE_COAP_MCAST_IPV6\n\n        config EXAMPLE_COAP_MCAST_IPV4_ONLY\n            bool \"IPV4\"\n            depends on LWIP_IPV4\n            select EXAMPLE_COAP_MCAST_IPV4\n\n        config EXAMPLE_COAP_MCAST_IPV6_ONLY\n            bool \"IPV6\"\n            depends on LWIP_IPV6\n            select EXAMPLE_COAP_MCAST_IPV6\n\n    endchoice\n\n    config EXAMPLE_COAP_MCAST_IPV4\n        bool\n        depends on LWIP_IPV4\n\n    config EXAMPLE_COAP_MCAST_IPV6\n        bool\n        depends on LWIP_IPV6\n\n    config EXAMPLE_COAP_MULTICAST_IPV4_ADDR\n        string \"CoAP Multicast IPV4 Address (receive)\"\n        default \"224.0.1.187\"\n        depends on EXAMPLE_COAP_MCAST_IPV4\n        help\n            IPV4 multicast address to receive multicast traffic on.\n\n            The default CoAP IPV4 address is 224.0.1.187.\n\n    config EXAMPLE_COAP_MULTICAST_IPV6_ADDR\n        string \"CoAP Multicast IPV6 Address (receive)\"\n        default \"FF02::FD\"\n        depends on EXAMPLE_COAP_MCAST_IPV6\n        help\n            IPV6 multicast address to receive multicast traffic on.\n\n            The default CoAP FF02::FD address is a link-local multicast address.\n            Consult IPV6 specifications or documentation for information about\n            meaning of different IPV6 multicast ranges.\n\nendmenu\n"
  },
  {
    "path": "coap/examples/coap_server/main/certs/coap_ca.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIICDDCCAbKgAwIBAgIIPKO8L7vZoqAwCgYIKoZIzj0EAwIwXDEQMA4GA1UEAxMH\nY2Ytcm9vdDEUMBIGA1UECxMLQ2FsaWZvcm5pdW0xFDASBgNVBAoTC0VjbGlwc2Ug\nSW9UMQ8wDQYDVQQHEwZPdHRhd2ExCzAJBgNVBAYTAkNBMB4XDTIzMTAyNjA4MDgx\nNVoXDTI1MTAyNTA4MDgxNVowWjEOMAwGA1UEAxMFY2YtY2ExFDASBgNVBAsTC0Nh\nbGlmb3JuaXVtMRQwEgYDVQQKEwtFY2xpcHNlIElvVDEPMA0GA1UEBxMGT3R0YXdh\nMQswCQYDVQQGEwJDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLCbJjxIS4hI\nAnRFTlx23gkd4zyFd50zdpTnoUPz19oQ1o1youavC5Go9vrYoWxyx+zpph8T4brB\nC/mZGIgPVMOjYDBeMB0GA1UdDgQWBBSxVzoI1TL87++hsUb9vQwqODzgUTALBgNV\nHQ8EBAMCAQYwDwYDVR0TBAgwBgEB/wIBATAfBgNVHSMEGDAWgBTqNhC1fqOTsHRn\nIVZ9OabfWsxpcTAKBggqhkjOPQQDAgNIADBFAiBSEn3egc31JhhHTVYi5uhl0t4d\newujkEmwzBuruzf/xAIhAK/fXy2tsNoyLitFQ97x6LYV25jKmLKUlhL2mC/PwQdO\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICDDCCAbKgAwIBAgIIPKO8L7vZoqAwCgYIKoZIzj0EAwIwXDEQMA4GA1UEAxMH\nY2Ytcm9vdDEUMBIGA1UECxMLQ2FsaWZvcm5pdW0xFDASBgNVBAoTC0VjbGlwc2Ug\nSW9UMQ8wDQYDVQQHEwZPdHRhd2ExCzAJBgNVBAYTAkNBMB4XDTIzMTAyNjA4MDgx\nNVoXDTI1MTAyNTA4MDgxNVowWjEOMAwGA1UEAxMFY2YtY2ExFDASBgNVBAsTC0Nh\nbGlmb3JuaXVtMRQwEgYDVQQKEwtFY2xpcHNlIElvVDEPMA0GA1UEBxMGT3R0YXdh\nMQswCQYDVQQGEwJDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLCbJjxIS4hI\nAnRFTlx23gkd4zyFd50zdpTnoUPz19oQ1o1youavC5Go9vrYoWxyx+zpph8T4brB\nC/mZGIgPVMOjYDBeMB0GA1UdDgQWBBSxVzoI1TL87++hsUb9vQwqODzgUTALBgNV\nHQ8EBAMCAQYwDwYDVR0TBAgwBgEB/wIBATAfBgNVHSMEGDAWgBTqNhC1fqOTsHRn\nIVZ9OabfWsxpcTAKBggqhkjOPQQDAgNIADBFAiBSEn3egc31JhhHTVYi5uhl0t4d\newujkEmwzBuruzf/xAIhAK/fXy2tsNoyLitFQ97x6LYV25jKmLKUlhL2mC/PwQdO\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "coap/examples/coap_server/main/certs/coap_server.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIICZDCCAgmgAwIBAgIIDY1x9glyw2UwCgYIKoZIzj0EAwIwWjEOMAwGA1UEAxMF\nY2YtY2ExFDASBgNVBAsTC0NhbGlmb3JuaXVtMRQwEgYDVQQKEwtFY2xpcHNlIElv\nVDEPMA0GA1UEBxMGT3R0YXdhMQswCQYDVQQGEwJDQTAeFw0yMzEwMjYwODA4MTZa\nFw0yNTEwMjUwODA4MTZaMF4xEjAQBgNVBAMTCWNmLXNlcnZlcjEUMBIGA1UECxML\nQ2FsaWZvcm5pdW0xFDASBgNVBAoTC0VjbGlwc2UgSW9UMQ8wDQYDVQQHEwZPdHRh\nd2ExCzAJBgNVBAYTAkNBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECXC+y/fC\n+rvwHZHizj7zVmLbhM6cjCK654Y8qFt+56G78+1VgfZzpIDf6k7XsSJIRpX+TrCY\nUDUmkknL9mnbB6OBtDCBsTAdBgNVHQ4EFgQUCp3HwJN1vjsydK1G5jjHjcGefqQw\nCwYDVR0PBAQDAgeAMGIGA1UdEQRbMFmCDm15LnRlc3Quc2VydmVygh5jYWxpZm9y\nbml1bS5lY2xpcHNlcHJvamVjdHMuaW+HBCO5KLaCCWxvY2FsaG9zdIcEfwAAAYcQ\nAAAAAAAAAAAAAAAAAAAAATAfBgNVHSMEGDAWgBSxVzoI1TL87++hsUb9vQwqODzg\nUTAKBggqhkjOPQQDAgNJADBGAiEArsVlRAvaNzmmKDfKHBtaG2ogusSec7+PAebk\nFIQSqEMCIQCbYJCnft3yhKbvBedO+zH/T0RT5V4eE/Yx4JKxbz1Q7A==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "coap/examples/coap_server/main/certs/coap_server.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgxL7AZvC26M+snaJ2\n+L8XSPUvKJN9Tk4im2CaBMzDezahRANCAAQJcL7L98L6u/AdkeLOPvNWYtuEzpyM\nIrrnhjyoW37nobvz7VWB9nOkgN/qTtexIkhGlf5OsJhQNSaSScv2adsH\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "coap/examples/coap_server/main/coap_server_example_main.c",
    "content": "/* CoAP server Example\n\n   This example code is in the Public Domain (or CC0 licensed, at your option.)\n\n   Unless required by applicable law or agreed to in writing, this\n   software is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n   CONDITIONS OF ANY KIND, either express or implied.\n*/\n\n/*\n * WARNING\n * libcoap is not multi-thread safe, so only this thread must make any coap_*()\n * calls.  Any external (to this thread) data transmitted in/out via libcoap\n * therefore has to be passed in/out by xQueue*() via this thread.\n */\n\n#include <string.h>\n#include <sys/socket.h>\n\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"freertos/event_groups.h\"\n\n#include \"esp_log.h\"\n#include \"esp_wifi.h\"\n#include \"esp_event.h\"\n\n#include \"nvs_flash.h\"\n\n#include \"protocol_examples_common.h\"\n\n#include \"coap_config.h\"\n#include \"coap3/coap.h\"\n\n#ifndef CONFIG_COAP_SERVER_SUPPORT\n#error COAP_SERVER_SUPPORT needs to be enabled\n#endif /* COAP_SERVER_SUPPORT */\n\n/* The examples use simple Pre-Shared-Key configuration that you can set via\n   'idf.py menuconfig'.\n\n   If you'd rather not, just change the below entries to strings with\n   the config you want - ie #define EXAMPLE_COAP_PSK_KEY \"some-agreed-preshared-key\"\n\n   Note: PSK will only be used if the URI is prefixed with coaps://\n   instead of coap:// and the PSK must be one that the server supports\n   (potentially associated with the IDENTITY)\n*/\n#define EXAMPLE_COAP_PSK_KEY CONFIG_EXAMPLE_COAP_PSK_KEY\n\n/* The examples use CoAP Logging Level that\n   you can set via 'idf.py menuconfig'.\n\n   If you'd rather not, just change the below entry to a value\n   that is between 0 and 7 with\n   the config you want - ie #define EXAMPLE_COAP_LOG_DEFAULT_LEVEL 7\n\n   Caution: Logging is enabled in libcoap only up to level as defined\n   by 'idf.py menuconfig' to reduce code size.\n*/\n#define EXAMPLE_COAP_LOG_DEFAULT_LEVEL CONFIG_COAP_LOG_DEFAULT_LEVEL\n\nconst static char *TAG = \"CoAP_server\";\n\nstatic char espressif_data[100];\nstatic int espressif_data_len = 0;\n\n#ifdef CONFIG_COAP_MBEDTLS_PKI\n/* CA cert, taken from coap_ca.pem\n   Server cert, taken from coap_server.crt\n   Server key, taken from coap_server.key\n\n   The PEM, CRT and KEY file are examples taken from\n   https://github.com/eclipse/californium/tree/master/demo-certs/src/main/resources\n   as the Certificate test (by default) for the coap_client is against the\n   californium server.\n\n   To embed it in the app binary, the PEM, CRT and KEY file is named\n   in the CMakeLists.txt EMBED_TXTFILES definition.\n */\nextern uint8_t ca_pem_start[] asm(\"_binary_coap_ca_pem_start\");\nextern uint8_t ca_pem_end[]   asm(\"_binary_coap_ca_pem_end\");\nextern uint8_t server_crt_start[] asm(\"_binary_coap_server_crt_start\");\nextern uint8_t server_crt_end[]   asm(\"_binary_coap_server_crt_end\");\nextern uint8_t server_key_start[] asm(\"_binary_coap_server_key_start\");\nextern uint8_t server_key_end[]   asm(\"_binary_coap_server_key_end\");\n#endif /* CONFIG_COAP_MBEDTLS_PKI */\n\n#ifdef CONFIG_COAP_OSCORE_SUPPORT\nextern uint8_t oscore_conf_start[] asm(\"_binary_coap_oscore_conf_start\");\nextern uint8_t oscore_conf_end[]   asm(\"_binary_coap_oscore_conf_end\");\n#endif /* CONFIG_COAP_OSCORE_SUPPORT */\n\n#define INITIAL_DATA \"Hello World!\"\n\n/*\n * The resource handler\n */\nstatic void\nhnd_espressif_get(coap_resource_t *resource,\n                  coap_session_t *session,\n                  const coap_pdu_t *request,\n                  const coap_string_t *query,\n                  coap_pdu_t *response)\n{\n    coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);\n    coap_add_data_large_response(resource, session, request, response,\n                                 query, COAP_MEDIATYPE_TEXT_PLAIN, 60, 0,\n                                 (size_t)espressif_data_len,\n                                 (const u_char *)espressif_data,\n                                 NULL, NULL);\n}\n\nstatic void\nhnd_espressif_put(coap_resource_t *resource,\n                  coap_session_t *session,\n                  const coap_pdu_t *request,\n                  const coap_string_t *query,\n                  coap_pdu_t *response)\n{\n    size_t size;\n    size_t offset;\n    size_t total;\n    const unsigned char *data;\n\n    coap_resource_notify_observers(resource, NULL);\n\n    if (strcmp (espressif_data, INITIAL_DATA) == 0) {\n        coap_pdu_set_code(response, COAP_RESPONSE_CODE_CREATED);\n    } else {\n        coap_pdu_set_code(response, COAP_RESPONSE_CODE_CHANGED);\n    }\n\n    /* coap_get_data_large() sets size to 0 on error */\n    (void)coap_get_data_large(request, &size, &data, &offset, &total);\n\n    if (size == 0) {      /* re-init */\n        snprintf(espressif_data, sizeof(espressif_data), INITIAL_DATA);\n        espressif_data_len = strlen(espressif_data);\n    } else {\n        espressif_data_len = size > sizeof (espressif_data) ? sizeof (espressif_data) : size;\n        memcpy (espressif_data, data, espressif_data_len);\n    }\n}\n\nstatic void\nhnd_espressif_delete(coap_resource_t *resource,\n                     coap_session_t *session,\n                     const coap_pdu_t *request,\n                     const coap_string_t *query,\n                     coap_pdu_t *response)\n{\n    coap_resource_notify_observers(resource, NULL);\n    snprintf(espressif_data, sizeof(espressif_data), INITIAL_DATA);\n    espressif_data_len = strlen(espressif_data);\n    coap_pdu_set_code(response, COAP_RESPONSE_CODE_DELETED);\n}\n\n#ifdef CONFIG_COAP_OSCORE_SUPPORT\nstatic void\nhnd_oscore_get(coap_resource_t *resource,\n               coap_session_t *session,\n               const coap_pdu_t *request,\n               const coap_string_t *query,\n               coap_pdu_t *response)\n{\n    coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);\n    coap_add_data_large_response(resource, session, request, response,\n                                 query, COAP_MEDIATYPE_TEXT_PLAIN, 60, 0,\n                                 sizeof(\"OSCORE Success!\"),\n                                 (const u_char *)\"OSCORE Success!\",\n                                 NULL, NULL);\n}\n#endif /* CONFIG_COAP_OSCORE_SUPPORT */\n\n#ifdef CONFIG_COAP_MBEDTLS_PKI\n\nstatic int\nverify_cn_callback(const char *cn,\n                   const uint8_t *asn1_public_cert,\n                   size_t asn1_length,\n                   coap_session_t *session,\n                   unsigned depth,\n                   int validated,\n                   void *arg\n                  )\n{\n    coap_log_info(\"CN '%s' presented by server (%s)\\n\",\n                  cn, depth ? \"CA\" : \"Certificate\");\n    return 1;\n}\n#endif /* CONFIG_COAP_MBEDTLS_PKI */\n\nstatic void\ncoap_log_handler (coap_log_t level, const char *message)\n{\n    uint32_t esp_level = ESP_LOG_INFO;\n    const char *cp = strchr(message, '\\n');\n\n    while (cp) {\n        ESP_LOG_LEVEL(esp_level, TAG, \"%.*s\", (int)(cp - message), message);\n        message = cp + 1;\n        cp = strchr(message, '\\n');\n    }\n    if (message[0] != '\\000') {\n        ESP_LOG_LEVEL(esp_level, TAG, \"%s\", message);\n    }\n}\n\nstatic void coap_example_server(void *p)\n{\n    coap_context_t *ctx = NULL;\n    coap_resource_t *resource = NULL;\n    int have_ep = 0;\n    uint16_t u_s_port = atoi(CONFIG_EXAMPLE_COAP_LISTEN_PORT);\n#ifdef CONFIG_EXAMPLE_COAPS_LISTEN_PORT\n    uint16_t s_port = atoi(CONFIG_EXAMPLE_COAPS_LISTEN_PORT);\n#else /* ! CONFIG_EXAMPLE_COAPS_LISTEN_PORT */\n    uint16_t s_port = 0;\n#endif /* ! CONFIG_EXAMPLE_COAPS_LISTEN_PORT */\n\n#ifdef CONFIG_EXAMPLE_COAP_WEBSOCKET_PORT\n    uint16_t ws_port = atoi(CONFIG_EXAMPLE_COAP_WEBSOCKET_PORT);\n#else /* ! CONFIG_EXAMPLE_COAP_WEBSOCKET_PORT */\n    uint16_t ws_port = 0;\n#endif /* ! CONFIG_EXAMPLE_COAP_WEBSOCKET_PORT */\n\n#ifdef CONFIG_EXAMPLE_COAP_WEBSOCKET_SECURE_PORT\n    uint16_t ws_s_port = atoi(CONFIG_EXAMPLE_COAP_WEBSOCKET_SECURE_PORT);\n#else /* ! CONFIG_EXAMPLE_COAP_WEBSOCKET_SECURE_PORT */\n    uint16_t ws_s_port = 0;\n#endif /* ! CONFIG_EXAMPLE_COAP_WEBSOCKET_SECURE_PORT */\n    uint32_t scheme_hint_bits;\n#ifdef CONFIG_COAP_OSCORE_SUPPORT\n    coap_str_const_t osc_conf = { 0, 0};\n    coap_oscore_conf_t *oscore_conf;\n#endif /* CONFIG_COAP_OSCORE_SUPPORT */\n\n    /* Initialize libcoap library */\n    coap_startup();\n\n    snprintf(espressif_data, sizeof(espressif_data), INITIAL_DATA);\n    espressif_data_len = strlen(espressif_data);\n    coap_set_log_handler(coap_log_handler);\n    coap_set_log_level(EXAMPLE_COAP_LOG_DEFAULT_LEVEL);\n\n    while (1) {\n        unsigned wait_ms;\n        coap_addr_info_t *info = NULL;\n        coap_addr_info_t *info_list = NULL;\n\n        ctx = coap_new_context(NULL);\n        if (!ctx) {\n            ESP_LOGE(TAG, \"coap_new_context() failed\");\n            goto clean_up;\n        }\n        coap_context_set_block_mode(ctx,\n                                    COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);\n        coap_context_set_max_idle_sessions(ctx, 20);\n        coap_context_set_keepalive(ctx, 30);\n\n#ifdef CONFIG_COAP_MBEDTLS_PSK\n        /* Need PSK setup before we set up endpoints */\n        coap_context_set_psk(ctx, \"CoAP\",\n                             (const uint8_t *)EXAMPLE_COAP_PSK_KEY,\n                             sizeof(EXAMPLE_COAP_PSK_KEY) - 1);\n#endif /* CONFIG_COAP_MBEDTLS_PSK */\n\n#ifdef CONFIG_COAP_MBEDTLS_PKI\n        /* Need PKI setup before we set up endpoints */\n        unsigned int ca_pem_bytes = ca_pem_end - ca_pem_start;\n        unsigned int server_crt_bytes = server_crt_end - server_crt_start;\n        unsigned int server_key_bytes = server_key_end - server_key_start;\n        coap_dtls_pki_t dtls_pki;\n\n        memset (&dtls_pki, 0, sizeof(dtls_pki));\n        dtls_pki.version = COAP_DTLS_PKI_SETUP_VERSION;\n        if (ca_pem_bytes) {\n            /*\n             * Add in additional certificate checking.\n             * This list of enabled can be tuned for the specific\n             * requirements - see 'man coap_encryption'.\n             *\n             * Note: A list of root ca file can be setup separately using\n             * coap_context_set_pki_root_cas(), but the below is used to\n             * define what checking actually takes place.\n             */\n            dtls_pki.verify_peer_cert        = 1;\n            dtls_pki.check_common_ca         = 1;\n            dtls_pki.allow_self_signed       = 1;\n            dtls_pki.allow_expired_certs     = 1;\n            dtls_pki.cert_chain_validation   = 1;\n            dtls_pki.cert_chain_verify_depth = 2;\n            dtls_pki.check_cert_revocation   = 1;\n            dtls_pki.allow_no_crl            = 1;\n            dtls_pki.allow_expired_crl       = 1;\n            dtls_pki.allow_bad_md_hash       = 1;\n            dtls_pki.allow_short_rsa_length  = 1;\n            dtls_pki.validate_cn_call_back   = verify_cn_callback;\n            dtls_pki.cn_call_back_arg        = NULL;\n            dtls_pki.validate_sni_call_back  = NULL;\n            dtls_pki.sni_call_back_arg       = NULL;\n        }\n        dtls_pki.pki_key.key_type = COAP_PKI_KEY_PEM_BUF;\n        dtls_pki.pki_key.key.pem_buf.public_cert = server_crt_start;\n        dtls_pki.pki_key.key.pem_buf.public_cert_len = server_crt_bytes;\n        dtls_pki.pki_key.key.pem_buf.private_key = server_key_start;\n        dtls_pki.pki_key.key.pem_buf.private_key_len = server_key_bytes;\n        dtls_pki.pki_key.key.pem_buf.ca_cert = ca_pem_start;\n        dtls_pki.pki_key.key.pem_buf.ca_cert_len = ca_pem_bytes;\n\n        coap_context_set_pki(ctx, &dtls_pki);\n#endif /* CONFIG_COAP_MBEDTLS_PKI */\n\n#ifdef CONFIG_COAP_OSCORE_SUPPORT\n        osc_conf.s = oscore_conf_start;\n        osc_conf.length = oscore_conf_end - oscore_conf_start;\n        oscore_conf = coap_new_oscore_conf(osc_conf,\n                                           NULL,\n                                           NULL, 0);\n        coap_context_oscore_server(ctx, oscore_conf);\n#endif /* CONFIG_COAP_OSCORE_SUPPORT */\n\n        /* set up the CoAP server socket(s) */\n        scheme_hint_bits =\n            coap_get_available_scheme_hint_bits(\n#if defined(CONFIG_COAP_MBEDTLS_PSK) || defined(CONFIG_COAP_MBEDTLS_PKI)\n                1,\n#else /* ! CONFIG_COAP_MBEDTLS_PSK) && ! CONFIG_COAP_MBEDTLS_PKI */\n                0,\n#endif /* ! CONFIG_COAP_MBEDTLS_PSK) && ! CONFIG_COAP_MBEDTLS_PKI */\n#ifdef CONFIG_COAP_WEBSOCKETS\n                1,\n#else /* ! CONFIG_COAP_WEBSOCKETS */\n                0,\n#endif /* ! CONFIG_COAP_WEBSOCKETS */\n                0);\n\n#if LWIP_IPV6\n        info_list = coap_resolve_address_info(coap_make_str_const(\"::\"), u_s_port, s_port,\n                                              ws_port, ws_s_port,\n                                              0,\n                                              scheme_hint_bits,\n                                              COAP_RESOLVE_TYPE_LOCAL);\n#else /* LWIP_IPV6 */\n        info_list = coap_resolve_address_info(coap_make_str_const(\"0.0.0.0\"), u_s_port, s_port,\n                                              ws_port, ws_s_port,\n                                              0,\n                                              scheme_hint_bits,\n                                              COAP_RESOLVE_TYPE_LOCAL);\n#endif /* LWIP_IPV6 */\n        if (info_list == NULL) {\n            ESP_LOGE(TAG, \"coap_resolve_address_info() failed\");\n            goto clean_up;\n        }\n\n        for (info = info_list; info != NULL; info = info->next) {\n            coap_endpoint_t *ep;\n\n            ep = coap_new_endpoint(ctx, &info->addr, info->proto);\n            if (!ep) {\n                ESP_LOGW(TAG, \"cannot create endpoint for proto %u\", info->proto);\n            } else {\n                have_ep = 1;\n            }\n        }\n        coap_free_address_info(info_list);\n        if (!have_ep) {\n            ESP_LOGE(TAG, \"No endpoints available\");\n            goto clean_up;\n        }\n\n        resource = coap_resource_init(coap_make_str_const(\"Espressif\"), 0);\n        if (!resource) {\n            ESP_LOGE(TAG, \"coap_resource_init() failed\");\n            goto clean_up;\n        }\n        coap_register_handler(resource, COAP_REQUEST_GET, hnd_espressif_get);\n        coap_register_handler(resource, COAP_REQUEST_PUT, hnd_espressif_put);\n        coap_register_handler(resource, COAP_REQUEST_DELETE, hnd_espressif_delete);\n        /* We possibly want to Observe the GETs */\n        coap_resource_set_get_observable(resource, 1);\n        coap_add_resource(ctx, resource);\n#ifdef CONFIG_COAP_OSCORE_SUPPORT\n        resource = coap_resource_init(coap_make_str_const(\"oscore\"), COAP_RESOURCE_FLAGS_OSCORE_ONLY);\n        if (!resource) {\n            ESP_LOGE(TAG, \"coap_resource_init() failed\");\n            goto clean_up;\n        }\n        coap_register_handler(resource, COAP_REQUEST_GET, hnd_oscore_get);\n        coap_add_resource(ctx, resource);\n#endif /* CONFIG_COAP_OSCORE_SUPPORT */\n\n#if defined(CONFIG_EXAMPLE_COAP_MCAST_IPV4) || defined(CONFIG_EXAMPLE_COAP_MCAST_IPV6)\n        esp_netif_t *netif = NULL;\n        for (int i = 0; i < esp_netif_get_nr_of_ifs(); ++i) {\n            char buf[8];\n            netif = esp_netif_next(netif);\n            esp_netif_get_netif_impl_name(netif, buf);\n#if defined(CONFIG_EXAMPLE_COAP_MCAST_IPV4)\n            coap_join_mcast_group_intf(ctx, CONFIG_EXAMPLE_COAP_MULTICAST_IPV4_ADDR, buf);\n#endif /* CONFIG_EXAMPLE_COAP_MCAST_IPV4 */\n#if defined(CONFIG_EXAMPLE_COAP_MCAST_IPV6)\n            /* When adding IPV6 esp-idf requires ifname param to be filled in */\n            coap_join_mcast_group_intf(ctx, CONFIG_EXAMPLE_COAP_MULTICAST_IPV6_ADDR, buf);\n#endif /* CONFIG_EXAMPLE_COAP_MCAST_IPV6 */\n        }\n#endif /* CONFIG_EXAMPLE_COAP_MCAST_IPV4 || CONFIG_EXAMPLE_COAP_MCAST_IPV6 */\n\n        wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;\n\n        while (1) {\n            int result = coap_io_process(ctx, wait_ms);\n            if (result < 0) {\n                break;\n            } else if (result && (unsigned)result < wait_ms) {\n                /* decrement if there is a result wait time returned */\n                wait_ms -= result;\n            }\n            if (result) {\n                /* result must have been >= wait_ms, so reset wait_ms */\n                wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;\n            }\n        }\n    }\nclean_up:\n    coap_free_context(ctx);\n    coap_cleanup();\n\n    vTaskDelete(NULL);\n}\n\nvoid app_main(void)\n{\n    ESP_ERROR_CHECK( nvs_flash_init() );\n    ESP_ERROR_CHECK(esp_netif_init());\n    ESP_ERROR_CHECK(esp_event_loop_create_default());\n\n    /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.\n     * Read \"Establishing Wi-Fi or Ethernet Connection\" section in\n     * examples/protocols/README.md for more information about this function.\n     */\n    ESP_ERROR_CHECK(example_connect());\n\n    xTaskCreate(coap_example_server, \"coap\", 8 * 1024, NULL, 5, NULL);\n}\n"
  },
  {
    "path": "coap/examples/coap_server/main/idf_component.yml",
    "content": "version: 1.0.0\ndescription: CoAP Server Example\ndependencies:\n  espressif/coap:\n    version: ^4.3.0\n    override_path: ../../../\n  protocol_examples_common:\n    path: ${IDF_PATH}/examples/common_components/protocol_examples_common\n"
  },
  {
    "path": "coap/examples/coap_server/main/oscore/coap_oscore.conf",
    "content": "# https://libcoap.net/doc/reference/develop/man_coap-oscore-conf.html\nmaster_secret,hex,\"0102030405060708090a0b0c0d0e0f10\"\nmaster_salt,hex,\"9e7ca92223786340\"\nsender_id,hex,\"02\"\nrecipient_id,hex,\"01\"\nid_context,hex,\"37cbf3210017a2d3\"\nreplay_window,integer,30\naead_alg,integer,10\nhkdf_alg,integer,-10\nssn_freq,integer,4\nrfc8613_b_2,bool,true\n"
  },
  {
    "path": "coap/examples/coap_server/partitions.csv",
    "content": "# Name,   Type, SubType, Offset,  Size, Flags\n# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap\nnvs,      data, nvs,     ,        0x6000,\nphy_init, data, phy,     ,        0x1000,\nfactory,  app,  factory, ,        1300K,\n"
  },
  {
    "path": "coap/examples/coap_server/sdkconfig.ci",
    "content": "CONFIG_EXAMPLE_CONNECT_ETHERNET=y\nCONFIG_EXAMPLE_CONNECT_WIFI=n\nCONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y\nCONFIG_EXAMPLE_ETH_MDC_GPIO=23\nCONFIG_EXAMPLE_ETH_MDIO_GPIO=18\nCONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5\nCONFIG_EXAMPLE_ETH_PHY_ADDR=1\nCONFIG_COAP_OSCORE_SUPPORT=y\nCONFIG_COAP_OBSERVE_PERSIST=y\nCONFIG_COAP_WEBSOCKETS=y\n"
  },
  {
    "path": "coap/examples/coap_server/sdkconfig.defaults",
    "content": "CONFIG_MBEDTLS_SSL_PROTO_DTLS=y\nCONFIG_MBEDTLS_PSK_MODES=y\nCONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y\nCONFIG_LWIP_NETBUF_RECVINFO=y\nCONFIG_COAP_SERVER_SUPPORT=y\n\nCONFIG_PARTITION_TABLE_CUSTOM=y\nCONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions.csv\"\nCONFIG_PARTITION_TABLE_FILENAME=\"partitions.csv\"\n"
  },
  {
    "path": "coap/examples/coap_server/sdkconfig.defaults.esp32h2",
    "content": "CONFIG_EXAMPLE_CONNECT_WIFI=n\nCONFIG_EXAMPLE_CONNECT_ETHERNET=y"
  },
  {
    "path": "coap/idf_component.yml",
    "content": "version: \"4.3.5~6\"\ndescription: Constrained Application Protocol (CoAP) C Library\nurl: https://github.com/espressif/idf-extra-components/tree/master/coap\ndependencies:\n  idf: \">=4.4\"\nsbom:\n  manifests:\n    - path: sbom_libcoap.yml\n      dest: libcoap\n"
  },
  {
    "path": "coap/port/include/coap_config.h",
    "content": "/*\n * libcoap configure implementation for ESP32 platform.\n *\n * coap.h -- main header file for CoAP stack of libcoap\n *\n * Copyright (C) 2010-2012,2015-2025 Olaf Bergmann <bergmann@tzi.org>\n *               2015 Carsten Schoenert <c.schoenert@t-online.de>\n *\n * Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD\n *\n * This file is part of the CoAP library libcoap. Please see README for terms\n * of use.\n */\n\n#ifndef COAP_CONFIG_H_\n#define COAP_CONFIG_H_\n\n/* Always enabled in ESP-IDF */\n#ifndef WITH_POSIX\n#define WITH_POSIX\n#endif\n\n#include \"coap_config_posix.h\"\n\n#define HAVE_STDIO_H\n#define HAVE_ASSERT_H\n#define HAVE_INTTYPES_H\n\n#define PACKAGE_STRING PACKAGE_NAME PACKAGE_VERSION\n\n/* it's just provided by libc. i hope we don't get too many of those, as\n * actually we'd need autotools again to find out what environment we're\n * building in */\n#define HAVE_STRNLEN 1\n\n#define HAVE_LIMITS_H\n\n#define COAP_RESOURCES_NOHASH\n\n/* Note: If neither of COAP_CLIENT_SUPPORT or COAP_SERVER_SUPPORT is set,\n   then libcoap sets both for backward compatibility */\n#ifdef CONFIG_COAP_CLIENT_SUPPORT\n#define COAP_CLIENT_SUPPORT 1\n#endif /* CONFIG_COAP_CLIENT_SUPPORT */\n\n#ifdef CONFIG_COAP_SERVER_SUPPORT\n#define COAP_SERVER_SUPPORT 1\n#endif /* CONFIG_COAP_SERVER_SUPPORT */\n\n#ifdef CONFIG_COAP_PROXY_SUPPORT\n#define COAP_PROXY_SUPPORT 1\n#endif /* CONFIG_COAP_PROXY_SUPPORT */\n\n#ifdef CONFIG_LWIP_IPV4\n#define COAP_IPV4_SUPPORT 1\n#else /* ! CONFIG_LWIP_IPV4 */\nstruct sockaddr_in {\n    u8_t            sin_len;\n    sa_family_t     sin_family;\n    in_port_t       sin_port;\n    struct in_addr  sin_addr;\n};\n#endif /* ! CONFIG_LWIP_IPV4 */\n\n#ifdef CONFIG_LWIP_IPV6\n#define COAP_IPV6_SUPPORT 1\n#else /* ! CONFIG_LWIP_IPV6 */\nstruct sockaddr_in6 {\n    u8_t            sin6_len;\n    sa_family_t     sin6_family;\n    in_port_t       sin6_port;\n    u32_t           sin6_flowinfo;\n    struct in_addr  sin6_addr;\n    u32_t           sin6_scope_id;\n};\n#ifndef INET6_ADDRSTRLEN\n#define INET6_ADDRSTRLEN 40\n#endif /* INET6_ADDRSTRLEN */\n#endif /* ! CONFIG_LWIP_IPV6 */\n\n#ifdef CONFIG_COAP_ASYNC_SUPPORT\n#define COAP_ASYNC_SUPPORT 1\n#endif /* CONFIG_COAP_ASYNC_SUPPORT */\n\n#ifdef CONFIG_COAP_TCP_SUPPORT\n#define COAP_DISABLE_TCP 0\n#else /* ! CONFIG_COAP_TCP_SUPPORT */\n#define COAP_DISABLE_TCP 1\n#endif /* ! CONFIG_COAP_TCP_SUPPORT */\n\n#ifdef CONFIG_COAP_OSCORE_SUPPORT\n#define COAP_OSCORE_SUPPORT 1\n#else /* ! CONFIG_COAP_OSCORE_SUPPORT */\n#define COAP_OSCORE_SUPPORT 0\n#endif /* ! CONFIG_COAP_OSCORE_SUPPORT */\n\n#ifdef CONFIG_COAP_WEBSOCKETS\n#define COAP_WS_SUPPORT 1\n#else /* ! CONFIG_COAP_WEBSOCKETS */\n#define COAP_WS_SUPPORT 0\n#endif /* ! CONFIG_COAP_WEBSOCKETS */\n\n#ifdef CONFIG_COAP_OBSERVE_PERSIST\n#define COAP_WITH_OBSERVE_PERSIST 1\n#else /* ! CONFIG_COAP_OBSERVE_PERSIST */\n#define COAP_WITH_OBSERVE_PERSIST 0\n#endif /* ! CONFIG_COAP_OBSERVE_PERSIST */\n\n#ifdef CONFIG_COAP_Q_BLOCK\n#define COAP_Q_BLOCK_SUPPORT 1\n#else /* ! CONFIG_COAP_Q_BLOCK */\n#define COAP_Q_BLOCK_SUPPORT 0\n#endif /* ! CONFIG_COAP_Q_BLOCK */\n\n#ifdef CONFIG_COAP_THREAD_RECURSIVE_CHECK\n#define COAP_THREAD_RECURSIVE_CHECK 1\n#else /* ! CONFIG_COAP_THREAD_RECURSIVE_CHECK */\n#define COAP_THREAD_RECURSIVE_CHECK 0\n#endif /* ! CONFIG_COAP_THREAD_RECURSIVE_CHECK */\n\n#ifdef CONFIG_COAP_THREAD_SAFE\n#define COAP_THREAD_SAFE 1\n#else /* ! CONFIG_COAP_THREAD_SAFE */\n#define COAP_THREAD_SAFE 0\n#endif /* ! CONFIG_COAP_THREAD_SAFE */\n\n#ifdef CONFIG_COAP_DEBUGGING\n#define COAP_MAX_LOGGING_LEVEL CONFIG_COAP_LOG_DEFAULT_LEVEL\n#else /* ! CONFIG_COAP_DEBUGGING */\n#define COAP_MAX_LOGGING_LEVEL 0\n#endif /* ! CONFIG_COAP_DEBUGGING */\n\n#endif /* COAP_CONFIG_H_ */\n"
  },
  {
    "path": "coap/port/include/coap_config_posix.h",
    "content": "/*\n * libcoap configure implementation for ESP32 platform.\n *\n * Uses libcoap software implementation for failover when concurrent\n * configure operations are in use.\n *\n * coap.h -- main header file for CoAP stack of libcoap\n *\n * Copyright (C) 2010-2012,2015-2025 Olaf Bergmann <bergmann@tzi.org>\n *               2015 Carsten Schoenert <c.schoenert@t-online.de>\n *\n * Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD\n *\n * This file is part of the CoAP library libcoap. Please see README for terms\n * of use.\n */\n\n#ifndef COAP_CONFIG_POSIX_H_\n#define COAP_CONFIG_POSIX_H_\n\n#ifdef WITH_POSIX\n\n#include <sys/socket.h>\n#include <sys/un.h>\n#include <net/if.h>\n#include \"lwip/init.h\"\n\n#define HAVE_SYS_SOCKET_H\n#define HAVE_MALLOC\n#define HAVE_ARPA_INET_H\n#define HAVE_TIME_H\n#define HAVE_NETDB_H\n#define HAVE_NETINET_IN_H\n#define HAVE_STRUCT_CMSGHDR\n#define HAVE_PTHREAD_H\n#define HAVE_PTHREAD_MUTEX_LOCK\n#define HAVE_GETRANDOM\n\n#define ipi_spec_dst ipi_addr\nstruct in6_pktinfo {\n    struct in6_addr ipi6_addr;        /* src/dst IPv6 address */\n    unsigned int ipi6_ifindex;        /* send/recv interface index */\n};\n\n#if LWIP_VERSION < 0x02020000\n#define IN6_IS_ADDR_V4MAPPED(a) \\\n        ((((__const uint32_t *) (a))[0] == 0)                                 \\\n         && (((__const uint32_t *) (a))[1] == 0)                              \\\n         && (((__const uint32_t *) (a))[2] == htonl (0xffff)))\n#endif // LWIP_VERSION < 0x02020000\n\n/* As not defined, just need to define is as something innocuous */\n#define IPV6_PKTINFO IPV6_CHECKSUM\n\n#define PACKAGE_NAME \"libcoap-posix\"\n#define PACKAGE_VERSION \"4.3.5\"\n\n#ifdef CONFIG_MBEDTLS_TLS_ENABLED\n#define COAP_WITH_LIBMBEDTLS 1\n#endif /* CONFIG_MBEDTLS_TLS_ENABLED */\n\n#define COAP_DEFAULT_MAX_PDU_RX_SIZE CONFIG_LWIP_TCP_MSL\n\n#define COAP_CONSTRAINED_STACK 1\n#define ESPIDF_VERSION\n\n#define gai_strerror(x) \"gai_strerror() not supported\"\n\n#endif /* WITH_POSIX */\n#endif /* COAP_CONFIG_POSIX_H_ */\n"
  },
  {
    "path": "coap/sbom_libcoap.yml",
    "content": "name: libcoap\nversion: 4.3.5\ncpe: cpe:2.3:a:libcoap:libcoap:{}:*:*:*:*:*:*:*\nsupplier: 'Organization: libcoap <https://libcoap.net/>'\ndescription: A CoAP (RFC 7252) implementation in C\nurl: https://github.com/obgm/libcoap\nhash: d9b4031ee61df1a40ecec46fe3817a1f985b3919\ncve-exclude-list:\n  - cve: CVE-2024-31031\n    reason: Resolved in version 4.3.5-rc1\n  - cve: CVE-2023-51847\n    reason: Resolved in version 4.3.5-rc1\n  - cve: CVE-2024-46304\n    reason: Resolved in version 4.3.5-rc3\n  - cve: CVE-2025-50518\n    reason: Not applicable as per comment https://github.com/obgm/libcoap/issues/1724#issuecomment-3296780541\n  - cve: CVE-2025-59391\n    reason: Resolved in version 4.3.5a\n  - cve: CVE-2025-65493\n    reason: Resolved in version 4.3.5a\n  - cve: CVE-2025-65494\n    reason: Resolved in version 4.3.5a\n  - cve: CVE-2025-65495\n    reason: Resolved in version 4.3.5a\n  - cve: CVE-2025-65496\n    reason: Resolved in version 4.3.5a\n  - cve: CVE-2025-65497\n    reason: Resolved in version 4.3.5a\n  - cve: CVE-2025-65498\n    reason: Resolved in version 4.3.5a\n  - cve: CVE-2025-65499\n    reason: Resolved in version 4.3.5a\n  - cve: CVE-2025-65500\n    reason: Resolved in version 4.3.5a\n  - cve: CVE-2025-65501\n    reason: Resolved in version 4.3.5a\n  - cve: CVE-2025-34468\n    reason: Resolved in version 4.3.5a\n  - cve: CVE-2026-29013\n    reason: Resolved in version 4.3.5b\n"
  },
  {
    "path": "coap/sdkconfig.rename",
    "content": "# sdkconfig replacement configurations for deprecated options formatted as\n# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION\n\n# Compiler options\nCONFIG_COAP_MBEDTLS_DEBUG                  CONFIG_COAP_DEBUGGING\n"
  },
  {
    "path": "conftest.py",
    "content": "from _pytest.fixtures import FixtureRequest\nfrom pytest_embedded.plugin import multi_dut_argument, multi_dut_fixture\nimport pytest\nimport os\nimport logging\nimport typing as t\n\n@pytest.hookimpl(tryfirst=True)  # run early\ndef pytest_ignore_collect(collection_path, config):\n    ignoring = config.getoption(\"ignore\") or []\n    for pattern in ignoring:\n        if collection_path.match(pattern) or str(collection_path).startswith(pattern):\n            print(f\"pytest would ignore: {collection_path}\")\n            return True\n\n    for glob_pattern in config.getoption(\"ignore_glob\") or []:\n        if collection_path.match(glob_pattern):\n            print(f\"pytest would ignore by glob: {collection_path}\")\n            return True\n\n    return False\n\n@pytest.fixture\n@multi_dut_argument\ndef config(request: FixtureRequest) -> str:\n    \"\"\"Fixture that provides the configuration for tests.\n\n    :param request: Pytest fixture request\n\n    :returns: Configuration string, defaults to 'default' if not specified\n    \"\"\"\n    return getattr(request, 'param', None) or 'default'\n\n\n\n@pytest.fixture\n@multi_dut_fixture\ndef build_dir(\n    request: FixtureRequest,\n    app_path: str,\n    target: t.Optional[str],\n    config: t.Optional[str],\n) -> str:\n    \"\"\"Find a valid build directory based on priority rules.\n\n    Checks local build directories in the following order:\n\n    1. build_<target>_<config>\n    2. build_<target>\n    3. build_<config>\n    4. build\n\n    :param request: Pytest fixture request\n    :param app_path: Path to the application\n    :param target: Target being used\n    :param config: Configuration being used\n\n    :returns: Valid build directory name, or skips the test if no build directory is found\n    \"\"\"\n    check_dirs = []\n    build_dir_arg = request.config.getoption('build_dir')\n\n    if build_dir_arg:\n        check_dirs.append(build_dir_arg)\n    if target is not None and config is not None:\n        check_dirs.append(f'build_{target}_{config}')\n    if target is not None:\n        check_dirs.append(f'build_{target}')\n    if config is not None:\n        check_dirs.append(f'build_{config}')\n    check_dirs.append('build')\n\n    for check_dir in check_dirs:\n        binary_path = os.path.join(app_path, check_dir)\n        if os.path.isdir(binary_path):\n            logging.info(f'Found valid binary path: {binary_path}')\n            return check_dir\n\n        logging.warning('Checking binary path: %s... missing... trying another location', binary_path)\n\n    pytest.skip(\n        f'No valid build directory found (checked: {\", \".join(check_dirs)}). '\n        f'Build the binary via \"idf.py -B {check_dirs[0]} build\" to enable this test.'\n    )\n"
  },
  {
    "path": "coremark/.build-test-rules.yml",
    "content": "coremark/examples:\n  enable:\n    - if: IDF_TARGET in [\"esp32\", \"esp32c3\"]\n      reason: \"Sufficient to test on one Xtensa and one RISC-V target.\"\n"
  },
  {
    "path": "coremark/CMakeLists.txt",
    "content": "\nset(srcs coremark/core_list_join.c\n         coremark/core_main.c\n         coremark/core_matrix.c\n         coremark/core_state.c\n         coremark/core_util.c\n         port/core_portme.c\n)\n\nif(NOT CMAKE_BUILD_EARLY_EXPANSION)\n    configure_file(linker.lf.in ${CMAKE_CURRENT_BINARY_DIR}/linker.lf)\nendif()\n\nidf_component_register(SRCS ${srcs}\n                       PRIV_INCLUDE_DIRS port coremark\n                       LDFRAGMENTS ${CMAKE_CURRENT_BINARY_DIR}/linker.lf\n                       PRIV_REQUIRES esp_timer)\n\n# compile coremark component with -O3 flag (will override the optimization level which is set globally)\n# set \"-fjump-tables\" and \"-ftree-switch-conversion\" explicitly, since IDF build system disables them by default\nset(component_compile_options \"-O3\" \"-fjump-tables\" \"-ftree-switch-conversion\")\ntarget_compile_options(${COMPONENT_LIB} PRIVATE ${component_compile_options})\n\n# Get the compilation options and store them as a target property\nset(compile_options_list \"$<TARGET_PROPERTY:__idf_build_target,COMPILE_OPTIONS>;$<TARGET_PROPERTY:__idf_build_target,C_COMPILE_OPTIONS>;${component_compile_options}\")\nset_target_properties(${COMPONENT_LIB} PROPERTIES COMPILER_OPT \"${compile_options_list}\")\n\n# Generate core_portme.h file, expanding \"COMPILER_OPT\" and \"COMPILER_VER\" generator expressions\ntarget_include_directories(${COMPONENT_LIB} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})\nfile(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/core_portme.h INPUT ${CMAKE_CURRENT_SOURCE_DIR}/port/core_portme.h.in TARGET ${COMPONENT_LIB})\n"
  },
  {
    "path": "coremark/LICENSE",
    "content": "# COREMARK® ACCEPTABLE USE AGREEMENT \n\nThis ACCEPTABLE USE AGREEMENT (this “Agreement”) is offered by Embedded Microprocessor Benchmark Consortium, a California nonprofit corporation (“Licensor”), to users of its CoreMark® software (“Licensee”) exclusively on the following terms.\n\nLicensor offers benchmarking software (“Software”) pursuant to an open source license, but carefully controls use of its benchmarks and their associated goodwill. Licensor has registered its trademark in one of the benchmarks available through the Software, COREMARK, Ser. No. 85/487,290; Reg. No. 4,179,307 (the “Trademark”), and promotes the use of a standard metric as a benchmark for assessing the performance of embedded systems. Solely on the terms described herein, Licensee may use and display the Trademark in connection with the generation of data regarding measurement and analysis of computer and embedded system benchmarking via the Software (the “Licensed Use”).\n\n## Article 1 – License Grant.\n1.1.\tLicense. Subject to the terms and conditions of this Agreement, Licensor hereby grants to Licensee, and Licensee hereby accepts from Licensor, a personal, non-exclusive, royalty-free, revocable right and license to use and display the Trademark during the term of this Agreement (the “Term”), solely and exclusively in connection with the Licensed Use. During the Term, Licensee (i) shall not modify or otherwise create derivative works of the Trademark, and (ii) may use the Trademark only to the extent permitted under this License. Neither Licensee nor any affiliate or agent thereof shall otherwise use the Trademark without the prior express written consent of Licensor, which may be withheld in its sole and absolute discretion. All rights not expressly granted to Licensee hereunder shall remain the exclusive property of Licensor.\n\n1.2.\tModifications to the Software.  Licensee shall not use the Trademark in connection with any use of a modified, derivative, or otherwise altered copy of the Software.\n\n1.3.\tLicensor’s Use. Nothing in this Agreement shall preclude Licensor or any of its successors or assigns from using or permitting other entities to use the Trademark, whether or not such entity directly or indirectly competes or conflicts with Licensee’s Licensed Use in any manner. \n\n1.4.\tTerm and Termination.  This Agreement is perpetual unless terminated by either of the parties.  Licensee may terminate this Agreement for convenience, without cause or liability, for any reason or for no reason whatsoever, upon ten (10) business days written notice. Licensor may terminate this Agreement effective immediately upon notice of breach.  Upon termination, Licensee shall immediately remove all implementations of the Trademark from the Licensed Use, and delete all digitals files and records of all materials related to the Trademark. \n\n## Article 2 – Ownership.\n2.1.\tOwnership. Licensee acknowledges and agrees that Licensor is the owner of all right, title, and interest in and to the Trademark, and all such right, title, and interest shall remain with Licensor. Licensee shall not contest, dispute, challenge, oppose, or seek to cancel Licensor’s right, title, and interest in and to the Trademark. Licensee shall not prosecute any application for registration of the Trademark. Licensee shall display appropriate notices regarding ownership of the Trademark in connection with the Licensed Use.\n\n2.2.\tGoodwill. Licensee acknowledges that Licensee shall not acquire any right, title, or interest in the Trademark by virtue of this Agreement other than the license granted hereunder, and disclaims any such right, title, interest, or ownership. All goodwill and reputation generated by Licensee’s use of the Trademark shall inure to the exclusive benefit of Licensor. Licensee shall not by any act or omission use the Trademark in any manner that disparages or reflects adversely on Licensor or its Licensed Use or reputation. Licensee shall not take any action that would interfere with or prejudice Licensor’s ownership or registration of the Trademark, the validity of the Trademark or the validity of the license granted by this Agreement. If Licensor determines and notifies Licensee that any act taken in connection with the Licensed Use (i) is inaccurate, unlawful or offensive to good taste; (ii) fails to provide for proper trademark notices, or (iii) otherwise violates Licensee’s obligations under this Agreement, the license granted under this Agreement shall terminate. \n\n## Article 3 – Indemnification. \n3.1.\tIndemnification Generally.  Licensee agrees to indemnify, defend, and hold harmless (collectively “indemnify” or “indemnification”) Licensor, including Licensor’s members, managers, officers, and employees (collectively “Related Persons”), from and against, and pay or reimburse Licensor and such Related Persons for, any and all third-party actions, claims, demands, proceedings, investigations, inquiries (collectively, “Claims”), and any and all liabilities, obligations, fines, deficiencies, costs, expenses, royalties, losses, and damages (including reasonable outside counsel fees and expenses) associated with such Claims, to the extent that such Claim arises out of (i) Licensee’s material breach of this Agreement, or (ii) any allegation(s) that Licensee’s actions infringe or violate any third-party intellectual property right, including without limitation, any U.S. copyright, patent, or trademark, or are otherwise found to be tortious or criminal (whether or not such indemnified person is a named party in a legal proceeding).  \n\n3.2.\tNotice and Defense of Claims. Licensor shall promptly notify Licensee of any Claim for which indemnification is sought, following actual knowledge of such Claim, provided however that the failure to give such notice shall not relieve Licensee of its obligations hereunder except to the extent that Licensee is materially prejudiced by such failure. In the event that any third-party Claim is brought, Licensee shall have the right and option to undertake and control the defense of such action with counsel of its choice, provided however that (i) Licensor at its own expense may participate and appear on an equal footing with Licensee in the defense of any such Claim, (ii) Licensor may undertake and control such defense in the event of the material failure of Licensee to undertake and control the same; and (iii) the defense of any Claim relating to the intellectual property rights of Licensor or its licensors and any related counterclaims shall be solely controlled by Licensor with counsel of its choice. Licensee shall not consent to judgment or concede or settle or compromise any Claim without the prior written approval of Licensor (whose approval shall not be unreasonably withheld), unless such concession or settlement or compromise includes a full and unconditional release of Licensor and any applicable Related Persons from all liabilities in respect of such Claim.\n\n## Article 4 – Miscellaneous.\n4.1.\tRelationship of the Parties. This Agreement does not create a partnership, franchise, joint venture, agency, fiduciary, or employment relationship between the parties. \n\n4.2.\tNo Third-Party Beneficiaries. Except for the rights of Related Persons under Article 3 (Indemnification), there are no third-party beneficiaries to this Agreement.\n\n4.3.\tAssignment. Licensee’s rights hereunder are non-assignable, and may not be sublicensed. \n\n4.4.\tEquitable Relief. Licensee acknowledges that the remedies available at law for any breach of this Agreement will, by their nature, be inadequate.  Accordingly, Licensor may obtain injunctive relief or other equitable relief to restrain a breach or threatened breach of this Agreement or to specifically enforce this Agreement, without proving that any monetary damages have been sustained, and without the requirement of posting of a bond prior to obtaining such equitable relief.\n\n4.5.\tGoverning Law. This Agreement will be interpreted, construed, and enforced in all respects in accordance with the laws of the State of California, without reference to its conflict of law principles. \n\n4.6.\tAttorneys’ Fees.  If any legal action, arbitration or other proceeding is brought for the enforcement of this Agreement, or because of an alleged dispute, breach, default, or misrepresentation in connection with any of the provisions of this Agreement, the successful or prevailing party shall be entitled to recover its reasonable attorneys’ fees and other reasonable costs incurred in that action or proceeding, in addition to any other relief to which it may be entitled.\n\n4.7.\tAmendment; Waiver.  This Agreement may not be amended, nor may any rights under it be waived, except in writing by Licensor.\n\n4.8.\tSeverability. If any provision of this Agreement is held by a court of competent jurisdiction to be contrary to law, the provision shall be modified by the court and interpreted so as best to accomplish the objectives of the original provision to the fullest extent \npermitted by law, and the remaining provisions of this Agreement shall remain in effect.\n\n4.9.\tEntire Agreement. This Agreement constitutes the entire agreement between the parties and supersedes all prior and contemporaneous agreements, proposals or representations, written or oral, concerning its subject matter.\n\n\n# Apache License\n\nVersion 2.0, January 2004\n\nhttp://www.apache.org/licenses/\n\n## TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.\n\n\"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.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising permissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.\n\n\"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.\n\n\"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).\n\n\"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.\n\n\"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.\"\n\n\"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.\n\n2. 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.\n\n3. 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.\n\n4. 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:\n\n    You must give any other recipients of the Work or Derivative Works a copy of this License; and\n    You must cause any modified files to carry prominent notices stating that You changed the files; and\n    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\n    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.\n\n    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.\n\n5. 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.\n\n6. 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.\n\n7. 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.\n\n8. 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.\n\n9. 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.\n\nEND OF TERMS AND CONDITIONS\n"
  },
  {
    "path": "coremark/README.md",
    "content": "[![Component Registry](https://components.espressif.com/components/espressif/coremark/badge.svg)](https://components.espressif.com/components/espressif/coremark)\n\n# Coremark for ESP-IDF\n\nThis component is a port of [CoreMark® benchmark](https://github.com/eembc/coremark) to ESP-IDF. It handles compiling CoreMark source files, providing necessary functions to measure timestamps, and enables various compiler to get higher performance.\n\n# Using the benchmark\n\nIf you want to run the benchmark and see the results, create a demo project from the provided example:\n\n```bash\nidf.py create-project-from-example \"espressif/coremark:coremark_example\"\n```\n\nYou can then build the project in `coremark_example` directory as usual. For example, to build the project for ESP32-C3:\n\n```bash\ncd coremark_example\nidf.py set-target esp32c3\nidf.py build\nidf.py -p PORT flash monitor\n```\n\n(where `PORT` is the name of the serial port)\n\nRefer to ESP-IDF Getting Started Guide for more information about compiling and running a project.\n\n# Using as a component\n\nYou can also integrate CoreMark code into you project by adding dependency on `espressif/coremark` component:\n\n```bash\nidf.py add-dependency espressif/coremark\n```\n\nCoreMark benchmark entry point is an `int main(void)` function, which you can call from your application.\n\n# Performance tweaks\n\nThis example does the following things to improve the benchmark result:\n\n1. Enables `-O3` compiler flag for CoreMark source files.\n2. Adds `-fjump-tables -ftree-switch-conversion` compiler flags for CoreMark source files. This overrides `-fno-jump-tables -fno-tree-switch-conversion` flags which get set in ESP-IDF build system by default.\n3. Places CoreMark code into internal instruction RAM using [linker.lf](linker.lf) file.\n\nFor general information about optimizing performance of ESP-IDF applications, see the [\"Performance\" chapter of the Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/performance/index.html).\n\n# Example output\n\nRunning on ESP32-C3, we can obtain the following output:\n\n```\nRunning coremark...\n2K performance run parameters for coremark.\nCoreMark Size    : 666\nTotal ticks      : 14661\nTotal time (secs): 14.661000\nIterations/Sec   : 409.249028\nIterations       : 6000\nCompiler version : GCC12.2.0\nCompiler flags   : -ffunction-sections -fdata-sections -gdwarf-4 -ggdb -nostartfiles -nostartfiles -Og -fstrict-volatile-bitfields -fno-jump-tables -fno-tree-switch-conversion -std=gnu17 -O3 -fjump-tables -ftree-switch-conversion\nMemory location  : IRAM\nseedcrc          : 0xe9f5\n[0]crclist       : 0xe714\n[0]crcmatrix     : 0x1fd7\n[0]crcstate      : 0x8e3a\n[0]crcfinal      : 0xa14c\nCorrect operation validated. See README.md for run and reporting rules.\nCoreMark 1.0 : 409.249028 / GCC12.2.0 -ffunction-sections -fdata-sections -gdwarf-4 -ggdb -nostartfiles -nostartfiles -Og -fstrict-volatile-bitfields -fno-jump-tables -fno-tree-switch-conversion -std=gnu17 -O3 -fjump-tables -ftree-switch-conversion / IRAM\nCPU frequency: 160 MHz\n```\n\n# Legal\n\nCoreMark is a trademark of EEMBC and EEMBC is a registered trademark of the Embedded Microprocessor Benchmark Consortium.\n\nCoreMark source code is Copyright (c) 2009 EEMBC. The source code is distributed under Apache 2.0 license with additional restrictions with regards to the use of the benchmark. See [LICENSE.md](LICENSE.md) for more details.\n\nAny additional code in this component (\"port layer\") is Copyright (c) 2022-2023 Espressif Systems (Shanghai) Co. Ltd. and is licensed under Apache 2.0 license.\n\n\n\n"
  },
  {
    "path": "coremark/examples/coremark_example/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.5)\n\nset(COMPONENTS main)\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nproject(coremark_example)\n"
  },
  {
    "path": "coremark/examples/coremark_example/README.md",
    "content": "# CoreMark example\n\nThis example can be used to run CoreMark benchmark on an Espressif chip.\n\nThe example doesn't require any special hardware and can run on any development board.\n\n## Building and running\n\nRun the application as usual for an ESP-IDF project. For example, for ESP32-C3:\n```\nidf.py set-target esp32c3\nidf.py -p PORT flash monitor\n```\n\nAfter launching, the benchmark takes a few seconds to run, please be patient.\n\n## Example output\n\nRunning on ESP32-C3, we can obtain the following output:\n\n```\nRunning coremark...\n2K performance run parameters for coremark.\nCoreMark Size    : 666\nTotal ticks      : 14661\nTotal time (secs): 14.661000\nIterations/Sec   : 409.249028\nIterations       : 6000\nCompiler version : GCC12.2.0\nCompiler flags   : -ffunction-sections -fdata-sections -gdwarf-4 -ggdb -nostartfiles -nostartfiles -Og -fstrict-volatile-bitfields -fno-jump-tables -fno-tree-switch-conversion -std=gnu17 -O3 -fjump-tables -ftree-switch-conversion\nMemory location  : IRAM\nseedcrc          : 0xe9f5\n[0]crclist       : 0xe714\n[0]crcmatrix     : 0x1fd7\n[0]crcstate      : 0x8e3a\n[0]crcfinal      : 0xa14c\nCorrect operation validated. See README.md for run and reporting rules.\nCoreMark 1.0 : 409.249028 / GCC12.2.0 -ffunction-sections -fdata-sections -gdwarf-4 -ggdb -nostartfiles -nostartfiles -Og -fstrict-volatile-bitfields -fno-jump-tables -fno-tree-switch-conversion -std=gnu17 -O3 -fjump-tables -ftree-switch-conversion / IRAM\nCPU frequency: 160 MHz\n```\n"
  },
  {
    "path": "coremark/examples/coremark_example/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS coremark_example_main.c\n                       PRIV_REQUIRES coremark)\n"
  },
  {
    "path": "coremark/examples/coremark_example/main/coremark_example_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include \"sdkconfig.h\"\n\n// In IDF v5.x, there is a common CPU frequency option for all targets\n#if defined(CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ)\n#define CPU_FREQ CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ\n\n// In IDF v4.x, CPU frequency options were target-specific\n#elif defined(CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ)\n#define CPU_FREQ CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ\n#elif defined(CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ)\n#define CPU_FREQ CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ\n#elif defined(CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ)\n#define CPU_FREQ CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ\n#elif defined(CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ)\n#define CPU_FREQ CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ\n#endif\n\n// Entry point of coremark benchmark\nextern int main(void);\n\nvoid app_main(void)\n{\n    printf(\"Running coremark...\\n\");\n    main();\n    printf(\"CPU frequency: %d MHz\\n\", CPU_FREQ);\n}\n"
  },
  {
    "path": "coremark/examples/coremark_example/main/idf_component.yml",
    "content": "description: Coremark benchmark application\ndependencies:\n  espressif/coremark:\n    version: \"*\"\n    override_path: '../../../'\n"
  },
  {
    "path": "coremark/examples/coremark_example/pytest_coremark.py",
    "content": "import pytest\n\n\n@pytest.mark.generic\ndef test_coremark(dut):\n    dut.expect_exact(\"Running coremark...\")\n    dut.expect_exact(\"Correct operation validated\", timeout=30)\n"
  },
  {
    "path": "coremark/examples/coremark_example/sdkconfig.defaults",
    "content": "CONFIG_ESP_TASK_WDT_INIT=n\n"
  },
  {
    "path": "coremark/examples/coremark_example/sdkconfig.defaults.esp32",
    "content": "CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y\n"
  },
  {
    "path": "coremark/examples/coremark_example/sdkconfig.defaults.esp32s2",
    "content": "CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y\n"
  },
  {
    "path": "coremark/examples/coremark_example/sdkconfig.defaults.esp32s3",
    "content": "CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y\n"
  },
  {
    "path": "coremark/idf_component.yml",
    "content": "version: \"1.1.0~2\"\ndescription: CoreMark Benchmark\nurl: https://github.com/espressif/idf-extra-components/tree/master/coremark\nissues: https://github.com/espressif/idf-extra-components/issues\nrepository: https://github.com/espressif/idf-extra-components.git\ndocumentation: https://www.eembc.org/coremark/\ndependencies:\n  idf: \">=5.0\"\n"
  },
  {
    "path": "coremark/linker.lf.in",
    "content": "[mapping:coremark]\narchive: lib${COMPONENT_NAME}.a\nentries:\n    * (noflash)\n"
  },
  {
    "path": "coremark/port/core_portme.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2018 EEMBC\n * SPDX-FileContributor: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"coremark.h\"\n#include \"core_portme.h\"\n#include \"sdkconfig.h\"\n#include <stdint.h>\n#include <stddef.h>\n#include \"esp_timer.h\"\n\n#if VALIDATION_RUN\nvolatile ee_s32 seed1_volatile = 0x3415;\nvolatile ee_s32 seed2_volatile = 0x3415;\nvolatile ee_s32 seed3_volatile = 0x66;\n#endif\n#if PERFORMANCE_RUN\nvolatile ee_s32 seed1_volatile = 0x0;\nvolatile ee_s32 seed2_volatile = 0x0;\nvolatile ee_s32 seed3_volatile = 0x66;\n#endif\n#if PROFILE_RUN\nvolatile ee_s32 seed1_volatile = 0x8;\nvolatile ee_s32 seed2_volatile = 0x8;\nvolatile ee_s32 seed3_volatile = 0x8;\n#endif\nvolatile ee_s32 seed4_volatile = 0;\nvolatile ee_s32 seed5_volatile = 0;\n/* Porting : Timing functions\n    How to capture time and convert to seconds must be ported to whatever is supported by the platform.\n    e.g. Read value from on board RTC, read value from cpu clock cycles performance counter etc.\n    Sample implementation for standard time.h and windows.h definitions included.\n*/\n/* Define : TIMER_RES_DIVIDER\n    Divider to trade off timer resolution and total time that can be measured.\n\n    Use lower values to increase resolution, but make sure that overflow does not occur.\n    If there are issues with the return value overflowing, increase this value.\n    */\n\n#define NSECS_PER_SEC CLOCKS_PER_SEC\n#define CORETIMETYPE ee_u32\n#define GETMYTIME(_t) (*_t=(ee_u32)(esp_timer_get_time()/1000))\n#define MYTIMEDIFF(fin,ini) ((fin)-(ini) ) /* 32-bit Timer overflow */\n#define TIMER_RES_DIVIDER 1\n#define SAMPLE_TIME_IMPLEMENTATION 1\n#define EE_TICKS_PER_SEC (1000)\n\n/** Define Host specific (POSIX), or target specific global time variables. */\nstatic CORETIMETYPE start_time_val, stop_time_val;\n\n/* Function : start_time\n    This function will be called right before starting the timed portion of the benchmark.\n\n    Implementation may be capturing a system timer (as implemented in the example code)\n    or zeroing some system parameters - e.g. setting the cpu clocks cycles to 0.\n*/\nvoid start_time(void)\n{\n    GETMYTIME(&start_time_val );\n}\n/* Function : stop_time\n    This function will be called right after ending the timed portion of the benchmark.\n\n    Implementation may be capturing a system timer (as implemented in the example code)\n    or other system parameters - e.g. reading the current value of cpu cycles counter.\n*/\nvoid stop_time(void)\n{\n    GETMYTIME(&stop_time_val );\n}\n/* Function : get_time\n    Return an abstract \"ticks\" number that signifies time on the system.\n\n    Actual value returned may be cpu cycles, milliseconds or any other value,\n    as long as it can be converted to seconds by <time_in_secs>.\n    This methodology is taken to accommodate any hardware or simulated platform.\n    The sample implementation returns millisecs by default,\n    and the resolution is controlled by <TIMER_RES_DIVIDER>\n*/\nCORE_TICKS get_time(void)\n{\n    CORE_TICKS elapsed = (CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val));\n    return elapsed;\n}\n/* Function : time_in_secs\n    Convert the value returned by get_time to seconds.\n\n    The <secs_ret> type is used to accommodate systems with no support for floating point.\n    Default implementation implemented by the EE_TICKS_PER_SEC macro above.\n*/\nsecs_ret time_in_secs(CORE_TICKS ticks)\n{\n    secs_ret retval = ((secs_ret)ticks) / EE_TICKS_PER_SEC;\n    return retval;\n}\n\nee_u32 default_num_contexts = 1;\n\n/* Function : portable_init\n    Target specific initialization code\n    Test for some common mistakes.\n*/\nvoid portable_init(core_portable *p, int *argc, char *argv[])\n{\n    if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) {\n        ee_printf(\"ERROR! Please define ee_ptr_int to a type that holds a pointer!\\n\");\n    }\n    if (sizeof(ee_u32) != 4) {\n        ee_printf(\"ERROR! Please define ee_u32 to a 32b unsigned type!\\n\");\n    }\n    p->portable_id = 1;\n}\n/* Function : portable_fini\n    Target specific final code\n*/\nvoid portable_fini(core_portable *p)\n{\n    p->portable_id = 0;\n}\n"
  },
  {
    "path": "coremark/port/core_portme.h.in",
    "content": "/*\n * SPDX-FileCopyrightText: 2018 EEMBC\n * SPDX-FileContributor: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/* Topic : Description\n\tThis file contains configuration constants required to execute on different platforms\n*/\n#ifndef CORE_PORTME_H\n#define CORE_PORTME_H\n/************************/\n/* Data types and settings */\n/************************/\n\n#include <stdint.h>\n#include \"esp_idf_version.h\"\n\n/* Configuration : HAS_FLOAT\n\tDefine to 1 if the platform supports floating point.\n*/\n#ifndef HAS_FLOAT\n#define HAS_FLOAT 1\n#endif\n/* Configuration : HAS_TIME_H\n\tDefine to 1 if platform has the time.h header file,\n\tand implementation of functions thereof.\n*/\n#ifndef HAS_TIME_H\n#define HAS_TIME_H 0\n#endif\n/* Configuration : USE_CLOCK\n\tDefine to 1 if platform has the time.h header file,\n\tand implementation of functions thereof.\n*/\n#ifndef USE_CLOCK\n#define USE_CLOCK 0\n#endif\n/* Configuration : HAS_STDIO\n\tDefine to 1 if the platform has stdio.h.\n*/\n#ifndef HAS_STDIO\n#define HAS_STDIO 1\n#endif\n/* Configuration : HAS_PRINTF\n\tDefine to 1 if the platform has stdio.h and implements the printf function.\n*/\n#ifndef HAS_PRINTF\n#define HAS_PRINTF 1\n#endif\n\n/* Definitions : COMPILER_VERSION, COMPILER_FLAGS, MEM_LOCATION\n\tInitialize these strings per platform\n*/\n#ifndef COMPILER_VERSION\n #ifdef __GNUC__\n #define COMPILER_VERSION \"GCC\"__VERSION__\n #else\n #define COMPILER_VERSION \"Please put compiler version here (e.g. gcc 4.1)\"\n #endif\n#endif\n#ifndef COMPILER_FLAGS\n #define COMPILER_FLAGS \"$<JOIN:$<FILTER:$<GENEX_EVAL:$<TARGET_PROPERTY:COMPILER_OPT>>,EXCLUDE,^-(([DWI])|(fmacro)).*>, >\"\n#endif\n#ifndef MEM_LOCATION\n #define MEM_LOCATION \"IRAM\"\n#endif\n\n/* Data Types :\n\tTo avoid compiler issues, define the data types that need to be used for 8b, 16b and 32b in <core_portme.h>.\n\n\t*Important* :\n\tee_ptr_int needs to be the data type used to hold pointers, otherwise coremark may fail!!!\n*/\ntypedef int16_t ee_s16;\ntypedef uint16_t ee_u16;\ntypedef int ee_s32;\ntypedef double ee_f32;\ntypedef uint8_t ee_u8;\ntypedef unsigned long ee_u32;\ntypedef ee_u32 ee_ptr_int;\n\n#define ee_size_t       size_t\n\n/* Configuration : CORE_TICKS\n\tDefine type of return from the timing functions.\n */\n\ntypedef ee_u32 CORE_TICKS;\n\n/* align_mem :\n\tThis macro is used to align an offset to point to a 32b value. It is used in the Matrix algorithm to initialize the input memory blocks.\n*/\n#define align_mem(x) (void *)(4 + (((ee_ptr_int)(x) - 1) & ~3))\n\n/* Configuration : SEED_METHOD\n\tDefines method to get seed values that cannot be computed at compile time.\n\n\tValid values :\n\tSEED_ARG - from command line.\n\tSEED_FUNC - from a system function.\n\tSEED_VOLATILE - from volatile variables.\n*/\n#ifndef SEED_METHOD\n#define SEED_METHOD SEED_VOLATILE\n#endif\n\n/* Configuration : MEM_METHOD\n\tDefines method to get a block of memry.\n\n\tValid values :\n\tMEM_MALLOC - for platforms that implement malloc and have malloc.h.\n\tMEM_STATIC - to use a static memory array.\n\tMEM_STACK - to allocate the data block on the stack (NYI).\n*/\n#ifndef MEM_METHOD\n#define MEM_METHOD MEM_STATIC\n#endif\n\n/* Configuration : MULTITHREAD\n\tDefine for parallel execution\n\n\tValid values :\n\t1 - only one context (default).\n\tN>1 - will execute N copies in parallel.\n\n\tNote :\n\tIf this flag is defined to more then 1, an implementation for launching parallel contexts must be defined.\n\n\tTwo sample implementations are provided. Use <USE_PTHREAD> or <USE_FORK> to enable them.\n\n\tIt is valid to have a different implementation of <core_start_parallel> and <core_end_parallel> in <core_portme.c>,\n\tto fit a particular architecture.\n*/\n#ifndef MULTITHREAD\n#define MULTITHREAD 1\n#define USE_PTHREAD 0\n#define USE_FORK 0\n#define USE_SOCKET 0\n#endif\n\n/* Configuration : MAIN_HAS_NOARGC\n\tNeeded if platform does not support getting arguments to main.\n\n\tValid values :\n\t0 - argc/argv to main is supported\n\t1 - argc/argv to main is not supported\n\n\tNote :\n\tThis flag only matters if MULTITHREAD has been defined to a value greater then 1.\n*/\n#ifndef MAIN_HAS_NOARGC\n#define MAIN_HAS_NOARGC 1\n#endif\n\n/* Configuration : MAIN_HAS_NORETURN\n\tNeeded if platform does not support returning a value from main.\n\n\tValid values :\n\t0 - main returns an int, and return value will be 0.\n\t1 - platform does not support returning a value from main\n*/\n#ifndef MAIN_HAS_NORETURN\n#define MAIN_HAS_NORETURN 0\n#endif\n\n/* Variable : default_num_contexts\n\tNot used for this simple port, must cintain the value 1.\n*/\nextern ee_u32 default_num_contexts;\n\ntypedef struct CORE_PORTABLE_S {\n\tee_u8\tportable_id;\n} core_portable;\n\n/* target specific init/fini */\nvoid portable_init(core_portable *p, int *argc, char *argv[]);\nvoid portable_fini(core_portable *p);\n\n#if !defined(PROFILE_RUN) && !defined(PERFORMANCE_RUN) && !defined(VALIDATION_RUN)\n#if (TOTAL_DATA_SIZE==1200)\n#define PROFILE_RUN 1\n#elif (TOTAL_DATA_SIZE==2000)\n#define PERFORMANCE_RUN 1\n#else\n#define VALIDATION_RUN 1\n#endif\n#endif\n\n#endif /* CORE_PORTME_H */\n"
  },
  {
    "path": "dhara/CMakeLists.txt",
    "content": "idf_component_register(INCLUDE_DIRS dhara\n                       SRC_DIRS \"dhara/dhara\")\n"
  },
  {
    "path": "dhara/LICENSE",
    "content": "Dhara - NAND flash management layer\nCopyright (C) 2013 Daniel Beer <dlbeer@gmail.com>\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n"
  },
  {
    "path": "dhara/README.md",
    "content": "# NAND Flash translation layer for small MCUs\n\nThis component is an ESP-IDF wrapper around [dhara library](https://github.com/dlbeer/dhara)\n\nFor the details, please refer to the official documentation: https://github.com/dlbeer/dhara/blob/master/README\n"
  },
  {
    "path": "dhara/idf_component.yml",
    "content": "version: \"0.1.0\"\ndescription: NAND Flash translation layer\nurl: https://github.com/espressif/idf-extra-components/tree/master/dhara\nissues: https://github.com/espressif/idf-extra-components/issues\nrepository: https://github.com/espressif/idf-extra-components.git\nsbom:\n  manifests:\n    - path: sbom_dhara.yml\n      dest: dhara\n"
  },
  {
    "path": "dhara/sbom_dhara.yml",
    "content": "name: dhara\nversion: 1b166e41b74b4a62ee6001ba5fab7a8805e80ea2 \ncpe: cpe:2.3:a:dhara:dhara:{}:*:*:*:*:*:*:*\nsupplier: 'Organization: dhara'\ndescription: NAND Flash translation layer for small MCUs\nurl: https://github.com/dlbeer/dhara\nhash: 1b166e41b74b4a62ee6001ba5fab7a8805e80ea2\n"
  },
  {
    "path": "eigen/CMakeLists.txt",
    "content": "idf_component_register(\n                       # We need the dummy source file so that the component\n                       # library is not an interface library. This allows to\n                       # get the list of include directories from other components\n                       # via INCLUDE_DIRECTORIES property later on.\n                       SRCS dummy.c)\n\n# Determine compilation flags used for building Eigen\n# Flags inherited from IDF build system and other IDF components:\nset(idf_include_directories $<TARGET_PROPERTY:idf::eigen,INCLUDE_DIRECTORIES>)\nset(includes \"-I$<JOIN:${idf_include_directories}, -I>\")\n\nif(CONFIG_COMPILER_OPTIMIZATION_DEFAULT)\n    set(opt_args -DCMAKE_BUILD_TYPE=Debug)\nelseif(CONFIG_COMPILER_OPTIMIZATION_SIZE)\n    set(opt_args -DCMAKE_BUILD_TYPE=MinSizeRel)\nelseif(CONFIG_COMPILER_OPTIMIZATION_PERF)\n    set(opt_args -DCMAKE_BUILD_TYPE=Release)\nelseif(CONFIG_COMPILER_OPTIMIZATION_NONE)\n    set(opt_args -DCMAKE_BUILD_TYPE=Debug)\nelse()\n    message(FATAL_ERROR \"Unsupported optimization level\")\nendif()\n\ninclude(ExternalProject)\n\n# Build Eigen in this directory:\nset(BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/eigen-build)\n\n# Add Eigen as a subproject.\nExternalProject_Add(eigen_proj\n    SOURCE_DIR ${COMPONENT_DIR}/eigen\n    BINARY_DIR ${BINARY_DIR}\n    # These two options are set so that Ninja immediately outputs\n    # the subproject build to the terminal. Otherwise it looks like the\n    # build process \"hangs\" for too long until Eigen build is complete.\n    USES_TERMINAL_CONFIGURE TRUE\n    USES_TERMINAL_BUILD TRUE\n    # Arguments to pass to Eigen CMake invocation:\n    CMAKE_ARGS\n        ${opt_args}\n        -DCMAKE_INSTALL_PREFIX=${BINARY_DIR}/install\n        -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}\n)\n\nadd_dependencies(${COMPONENT_LIB} eigen_proj)\n\n# Attach generated libraries and header files to an interface library:\nadd_library(eigen_interface_lib INTERFACE)\nset_target_properties(eigen_interface_lib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${BINARY_DIR}/install/include)\nadd_dependencies(eigen_interface_lib eigen_proj)\n\n# Finally, link the interface library to the component library:\ntarget_link_libraries(${COMPONENT_LIB} INTERFACE eigen_interface_lib)\n"
  },
  {
    "path": "eigen/LICENSE",
    "content": "Mozilla Public License Version 2.0\n==================================\n\n1. Definitions\n--------------\n\n1.1. \"Contributor\"\n    means each individual or legal entity that creates, contributes to\n    the creation of, or owns Covered Software.\n\n1.2. \"Contributor Version\"\n    means the combination of the Contributions of others (if any) used\n    by a Contributor and that particular Contributor's Contribution.\n\n1.3. \"Contribution\"\n    means Covered Software of a particular Contributor.\n\n1.4. \"Covered Software\"\n    means Source Code Form to which the initial Contributor has attached\n    the notice in Exhibit A, the Executable Form of such Source Code\n    Form, and Modifications of such Source Code Form, in each case\n    including portions thereof.\n\n1.5. \"Incompatible With Secondary Licenses\"\n    means\n\n    (a) that the initial Contributor has attached the notice described\n        in Exhibit B to the Covered Software; or\n\n    (b) that the Covered Software was made available under the terms of\n        version 1.1 or earlier of the License, but not also under the\n        terms of a Secondary License.\n\n1.6. \"Executable Form\"\n    means any form of the work other than Source Code Form.\n\n1.7. \"Larger Work\"\n    means a work that combines Covered Software with other material, in \n    a separate file or files, that is not Covered Software.\n\n1.8. \"License\"\n    means this document.\n\n1.9. \"Licensable\"\n    means having the right to grant, to the maximum extent possible,\n    whether at the time of the initial grant or subsequently, any and\n    all of the rights conveyed by this License.\n\n1.10. \"Modifications\"\n    means any of the following:\n\n    (a) any file in Source Code Form that results from an addition to,\n        deletion from, or modification of the contents of Covered\n        Software; or\n\n    (b) any new file in Source Code Form that contains any Covered\n        Software.\n\n1.11. \"Patent Claims\" of a Contributor\n    means any patent claim(s), including without limitation, method,\n    process, and apparatus claims, in any patent Licensable by such\n    Contributor that would be infringed, but for the grant of the\n    License, by the making, using, selling, offering for sale, having\n    made, import, or transfer of either its Contributions or its\n    Contributor Version.\n\n1.12. \"Secondary License\"\n    means either the GNU General Public License, Version 2.0, the GNU\n    Lesser General Public License, Version 2.1, the GNU Affero General\n    Public License, Version 3.0, or any later versions of those\n    licenses.\n\n1.13. \"Source Code Form\"\n    means the form of the work preferred for making modifications.\n\n1.14. \"You\" (or \"Your\")\n    means an individual or a legal entity exercising rights under this\n    License. For legal entities, \"You\" includes any entity that\n    controls, is controlled by, or is under common control with You. For\n    purposes of this definition, \"control\" means (a) the power, direct\n    or indirect, to cause the direction or management of such entity,\n    whether by contract or otherwise, or (b) ownership of more than\n    fifty percent (50%) of the outstanding shares or beneficial\n    ownership of such entity.\n\n2. License Grants and Conditions\n--------------------------------\n\n2.1. Grants\n\nEach Contributor hereby grants You a world-wide, royalty-free,\nnon-exclusive license:\n\n(a) under intellectual property rights (other than patent or trademark)\n    Licensable by such Contributor to use, reproduce, make available,\n    modify, display, perform, distribute, and otherwise exploit its\n    Contributions, either on an unmodified basis, with Modifications, or\n    as part of a Larger Work; and\n\n(b) under Patent Claims of such Contributor to make, use, sell, offer\n    for sale, have made, import, and otherwise transfer either its\n    Contributions or its Contributor Version.\n\n2.2. Effective Date\n\nThe licenses granted in Section 2.1 with respect to any Contribution\nbecome effective for each Contribution on the date the Contributor first\ndistributes such Contribution.\n\n2.3. Limitations on Grant Scope\n\nThe licenses granted in this Section 2 are the only rights granted under\nthis License. No additional rights or licenses will be implied from the\ndistribution or licensing of Covered Software under this License.\nNotwithstanding Section 2.1(b) above, no patent license is granted by a\nContributor:\n\n(a) for any code that a Contributor has removed from Covered Software;\n    or\n\n(b) for infringements caused by: (i) Your and any other third party's\n    modifications of Covered Software, or (ii) the combination of its\n    Contributions with other software (except as part of its Contributor\n    Version); or\n\n(c) under Patent Claims infringed by Covered Software in the absence of\n    its Contributions.\n\nThis License does not grant any rights in the trademarks, service marks,\nor logos of any Contributor (except as may be necessary to comply with\nthe notice requirements in Section 3.4).\n\n2.4. Subsequent Licenses\n\nNo Contributor makes additional grants as a result of Your choice to\ndistribute the Covered Software under a subsequent version of this\nLicense (see Section 10.2) or under the terms of a Secondary License (if\npermitted under the terms of Section 3.3).\n\n2.5. Representation\n\nEach Contributor represents that the Contributor believes its\nContributions are its original creation(s) or it has sufficient rights\nto grant the rights to its Contributions conveyed by this License.\n\n2.6. Fair Use\n\nThis License is not intended to limit any rights You have under\napplicable copyright doctrines of fair use, fair dealing, or other\nequivalents.\n\n2.7. Conditions\n\nSections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted\nin Section 2.1.\n\n3. Responsibilities\n-------------------\n\n3.1. Distribution of Source Form\n\nAll distribution of Covered Software in Source Code Form, including any\nModifications that You create or to which You contribute, must be under\nthe terms of this License. You must inform recipients that the Source\nCode Form of the Covered Software is governed by the terms of this\nLicense, and how they can obtain a copy of this License. You may not\nattempt to alter or restrict the recipients' rights in the Source Code\nForm.\n\n3.2. Distribution of Executable Form\n\nIf You distribute Covered Software in Executable Form then:\n\n(a) such Covered Software must also be made available in Source Code\n    Form, as described in Section 3.1, and You must inform recipients of\n    the Executable Form how they can obtain a copy of such Source Code\n    Form by reasonable means in a timely manner, at a charge no more\n    than the cost of distribution to the recipient; and\n\n(b) You may distribute such Executable Form under the terms of this\n    License, or sublicense it under different terms, provided that the\n    license for the Executable Form does not attempt to limit or alter\n    the recipients' rights in the Source Code Form under this License.\n\n3.3. Distribution of a Larger Work\n\nYou may create and distribute a Larger Work under terms of Your choice,\nprovided that You also comply with the requirements of this License for\nthe Covered Software. If the Larger Work is a combination of Covered\nSoftware with a work governed by one or more Secondary Licenses, and the\nCovered Software is not Incompatible With Secondary Licenses, this\nLicense permits You to additionally distribute such Covered Software\nunder the terms of such Secondary License(s), so that the recipient of\nthe Larger Work may, at their option, further distribute the Covered\nSoftware under the terms of either this License or such Secondary\nLicense(s).\n\n3.4. Notices\n\nYou may not remove or alter the substance of any license notices\n(including copyright notices, patent notices, disclaimers of warranty,\nor limitations of liability) contained within the Source Code Form of\nthe Covered Software, except that You may alter any license notices to\nthe extent required to remedy known factual inaccuracies.\n\n3.5. Application of Additional Terms\n\nYou may choose to offer, and to charge a fee for, warranty, support,\nindemnity or liability obligations to one or more recipients of Covered\nSoftware. However, You may do so only on Your own behalf, and not on\nbehalf of any Contributor. You must make it absolutely clear that any\nsuch warranty, support, indemnity, or liability obligation is offered by\nYou alone, and You hereby agree to indemnify every Contributor for any\nliability incurred by such Contributor as a result of warranty, support,\nindemnity or liability terms You offer. You may include additional\ndisclaimers of warranty and limitations of liability specific to any\njurisdiction.\n\n4. Inability to Comply Due to Statute or Regulation\n---------------------------------------------------\n\nIf it is impossible for You to comply with any of the terms of this\nLicense with respect to some or all of the Covered Software due to\nstatute, judicial order, or regulation then You must: (a) comply with\nthe terms of this License to the maximum extent possible; and (b)\ndescribe the limitations and the code they affect. Such description must\nbe placed in a text file included with all distributions of the Covered\nSoftware under this License. Except to the extent prohibited by statute\nor regulation, such description must be sufficiently detailed for a\nrecipient of ordinary skill to be able to understand it.\n\n5. Termination\n--------------\n\n5.1. The rights granted under this License will terminate automatically\nif You fail to comply with any of its terms. However, if You become\ncompliant, then the rights granted under this License from a particular\nContributor are reinstated (a) provisionally, unless and until such\nContributor explicitly and finally terminates Your grants, and (b) on an\nongoing basis, if such Contributor fails to notify You of the\nnon-compliance by some reasonable means prior to 60 days after You have\ncome back into compliance. Moreover, Your grants from a particular\nContributor are reinstated on an ongoing basis if such Contributor\nnotifies You of the non-compliance by some reasonable means, this is the\nfirst time You have received notice of non-compliance with this License\nfrom such Contributor, and You become compliant prior to 30 days after\nYour receipt of the notice.\n\n5.2. If You initiate litigation against any entity by asserting a patent\ninfringement claim (excluding declaratory judgment actions,\ncounter-claims, and cross-claims) alleging that a Contributor Version\ndirectly or indirectly infringes any patent, then the rights granted to\nYou by any and all Contributors for the Covered Software under Section\n2.1 of this License shall terminate.\n\n5.3. In the event of termination under Sections 5.1 or 5.2 above, all\nend user license agreements (excluding distributors and resellers) which\nhave been validly granted by You or Your distributors under this License\nprior to termination shall survive termination.\n\n************************************************************************\n*                                                                      *\n*  6. Disclaimer of Warranty                                           *\n*  -------------------------                                           *\n*                                                                      *\n*  Covered Software is provided under this License on an \"as is\"       *\n*  basis, without warranty of any kind, either expressed, implied, or  *\n*  statutory, including, without limitation, warranties that the       *\n*  Covered Software is free of defects, merchantable, fit for a        *\n*  particular purpose or non-infringing. The entire risk as to the     *\n*  quality and performance of the Covered Software is with You.        *\n*  Should any Covered Software prove defective in any respect, You     *\n*  (not any Contributor) assume the cost of any necessary servicing,   *\n*  repair, or correction. This disclaimer of warranty constitutes an   *\n*  essential part of this License. No use of any Covered Software is   *\n*  authorized under this License except under this disclaimer.         *\n*                                                                      *\n************************************************************************\n\n************************************************************************\n*                                                                      *\n*  7. Limitation of Liability                                          *\n*  --------------------------                                          *\n*                                                                      *\n*  Under no circumstances and under no legal theory, whether tort      *\n*  (including negligence), contract, or otherwise, shall any           *\n*  Contributor, or anyone who distributes Covered Software as          *\n*  permitted above, be liable to You for any direct, indirect,         *\n*  special, incidental, or consequential damages of any character      *\n*  including, without limitation, damages for lost profits, loss of    *\n*  goodwill, work stoppage, computer failure or malfunction, or any    *\n*  and all other commercial damages or losses, even if such party      *\n*  shall have been informed of the possibility of such damages. This   *\n*  limitation of liability shall not apply to liability for death or   *\n*  personal injury resulting from such party's negligence to the       *\n*  extent applicable law prohibits such limitation. Some               *\n*  jurisdictions do not allow the exclusion or limitation of           *\n*  incidental or consequential damages, so this exclusion and          *\n*  limitation may not apply to You.                                    *\n*                                                                      *\n************************************************************************\n\n8. Litigation\n-------------\n\nAny litigation relating to this License may be brought only in the\ncourts of a jurisdiction where the defendant maintains its principal\nplace of business and such litigation shall be governed by laws of that\njurisdiction, without reference to its conflict-of-law provisions.\nNothing in this Section shall prevent a party's ability to bring\ncross-claims or counter-claims.\n\n9. Miscellaneous\n----------------\n\nThis License represents the complete agreement concerning the subject\nmatter hereof. If any provision of this License is held to be\nunenforceable, such provision shall be reformed only to the extent\nnecessary to make it enforceable. Any law or regulation which provides\nthat the language of a contract shall be construed against the drafter\nshall not be used to construe this License against a Contributor.\n\n10. Versions of the License\n---------------------------\n\n10.1. New Versions\n\nMozilla Foundation is the license steward. Except as provided in Section\n10.3, no one other than the license steward has the right to modify or\npublish new versions of this License. Each version will be given a\ndistinguishing version number.\n\n10.2. Effect of New Versions\n\nYou may distribute the Covered Software under the terms of the version\nof the License under which You originally received the Covered Software,\nor under the terms of any subsequent version published by the license\nsteward.\n\n10.3. Modified Versions\n\nIf you create software not governed by this License, and you want to\ncreate a new license for such software, you may create and use a\nmodified version of this License if you rename the license and remove\nany references to the name of the license steward (except to note that\nsuch modified license differs from this License).\n\n10.4. Distributing Source Code Form that is Incompatible With Secondary\nLicenses\n\nIf You choose to distribute Source Code Form that is Incompatible With\nSecondary Licenses under the terms of this version of the License, the\nnotice described in Exhibit B of this License must be attached.\n\nExhibit A - Source Code Form License Notice\n-------------------------------------------\n\n  This Source Code Form is subject to the terms of the Mozilla Public\n  License, v. 2.0. If a copy of the MPL was not distributed with this\n  file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\nIf it is not possible or desirable to put the notice in a particular\nfile, then You may include the notice in a location (such as a LICENSE\nfile in a relevant directory) where a recipient would be likely to look\nfor such a notice.\n\nYou may add additional accurate notices of copyright ownership.\n\nExhibit B - \"Incompatible With Secondary Licenses\" Notice\n---------------------------------------------------------\n\n  This Source Code Form is \"Incompatible With Secondary Licenses\", as\n  defined by the Mozilla Public License, v. 2.0.\n"
  },
  {
    "path": "eigen/README.md",
    "content": "# Eigen for ESP-IDF\n\n[![Component Registry](https://components.espressif.com/components/espressif/eigen/badge.svg)](https://components.espressif.com/components/espressif/eigen)\n\nThis component ports Eigen library into the esp-idf.\n\n**Eigen is a C++ template library for linear algebra: matrices, vectors, numerical solvers, and related algorithms.**\n\nFor more information go to http://eigen.tuxfamily.org/.\n\nFor ***pull request***, ***bug reports***, and ***feature requests***, go to https://gitlab.com/libeigen/eigen.\n\n"
  },
  {
    "path": "eigen/dummy.c",
    "content": ""
  },
  {
    "path": "eigen/examples/svd/CMakeLists.txt",
    "content": "# The following lines of boilerplate have to be in your project's\n# CMakeLists in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.5)\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(Eigen_SVD)\n\n"
  },
  {
    "path": "eigen/examples/svd/README.md",
    "content": "# Eigen example for IDF Eigen component\n\nThis example shows how to use Eigen library in ESP-IDF projects.\n\nThe example does matrix multiplication and single value decomposition (SVD)\ntransformation.\n\nThis example does not require any special hardware, and can be run on any common development board.\n\nTo run the example on target please run:\n\n```\nidf.py -p PORT flash monitor\n```\n"
  },
  {
    "path": "eigen/examples/svd/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"main.cpp\" \n                    INCLUDE_DIRS \".\"\n                    REQUIRES eigen)\n"
  },
  {
    "path": "eigen/examples/svd/main/idf_component.yml",
    "content": "## IDF Component Manager Manifest File\ndependencies:\n  espressif/eigen: \n    version: \"^3.4.0\"\n    # This line define the local path of the eigen component because this \n    # example is part of the eigen component. This line is optional.\n    override_path: \"../../..\"\n  ## Required IDF version\n  idf:\n    version: \">=4.3.0\"\n"
  },
  {
    "path": "eigen/examples/svd/main/main.cpp",
    "content": "/*\n * SPDX-FileCopyrightText: 2010-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n*/\n\n#include <iostream>\n\n#include <eigen3/Eigen/Eigen>\n\nextern \"C\" void app_main(void);\n\nstatic void multiply2Matrices()\n{\n    Eigen::MatrixXf M(2, 2);\n    Eigen::MatrixXf V(2, 2);\n    for (int i = 0; i <= 1; i++) {\n        for (int j = 0; j <= 1; j++) {\n            M(i, j) = 1;\n            V(i, j) = 2;\n        }\n    }\n    Eigen::MatrixXf Result = M * V;\n    std::cout << \"MatrixXf Result = \" << std::endl << Result << std::endl;\n}\n\nstatic void runSVD()\n{\n    Eigen::MatrixXf C;\n    C.setRandom(27, 18);\n    Eigen::JacobiSVD<Eigen::MatrixXf> svd(C, Eigen::ComputeThinU | Eigen::ComputeThinV);\n    Eigen::MatrixXf Cp = svd.matrixU() * svd.singularValues().asDiagonal() * svd.matrixV().transpose();\n    Eigen::MatrixXf diff = Cp - C;\n    std::cout << \"SDV matrix U: \" << std::endl << svd.matrixU() << std::endl;\n    std::cout << \"SDV singularValues: \" << std::endl << svd.singularValues().transpose() << std::endl;\n    std::cout << \"SDV matrix V: \" << std::endl << svd.matrixV() << std::endl;\n    std::cout << \"diff:\\n\" << diff.array().abs().sum() << \"\\n\";\n}\n\nvoid app_main(void)\n{\n    std::cout << \"Eigen example.\" << std::endl;\n    multiply2Matrices();\n    runSVD();\n    std::cout << \"Example finished!\" << std::endl;\n}\n"
  },
  {
    "path": "eigen/examples/svd/sdkconfig.defaults",
    "content": "#\n# Common ESP-related\n#\n# CONFIG_ESP_TIMER_PROFILING is not set\nCONFIG_ESP_MAIN_TASK_STACK_SIZE=16384\n"
  },
  {
    "path": "eigen/idf_component.yml",
    "content": "\nversion: \"3.4.0~2\"\ndescription: Eigen port to ESP\nurl: https://github.com/espressif/idf-extra-components/tree/master/eigen\ndependencies:\n  idf: \">=4.3.0\"\n"
  },
  {
    "path": "esp_cli/.build-test-rules.yml",
    "content": "esp_cli/host_test:\n  enable:\n    - if: IDF_TARGET == \"linux\"\n      reason: \"Sufficient to test on Linux target\"\n  disable:\n    - if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR <= 4\n      reason: \"those versions of esp-idf do not support eventfd for linux target\"\n\nesp_cli/test_apps:\n  enable:\n    - if: IDF_TARGET == \"esp32s3\"\n      reason: \"Need support for USB Serial JTAG\"\n  disable:\n    - if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR <= 3\n      reason: \"esp_vfs_fs_ops_t not available\"\n"
  },
  {
    "path": "esp_cli/CMakeLists.txt",
    "content": "idf_build_get_property(target IDF_TARGET)\n\nset(srcs \"src/esp_cli.c\")\n\nidf_component_register(\n                    SRCS ${srcs}\n                    INCLUDE_DIRS include\n                    REQUIRES esp_linenoise esp_cli_commands\n                    WHOLE_ARCHIVE)\n"
  },
  {
    "path": "esp_cli/Kconfig",
    "content": "menu \"esp_cli configuration\"\n\n    config ESP_CLI_HAS_QUIT_CMD\n        bool \"Register quit command\"\n        default n\n        help\n            Register a static command \"quit\" that allows the user to return from the esp_cli main loop.\n            The command is registered through the ESP_CLI_COMMAND_REGISTER macro provided by esp_cli_commands component\n            and is placed in the dedicated flash section.\nendmenu\n"
  },
  {
    "path": "esp_cli/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright Espressif Systems\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "esp_cli/README.md",
    "content": "# esp_cli Component\n\nThe `esp_cli` component provides a **Runtime Evaluation Loop (REPL)** mechanism for ESP-IDF-based applications.  \nIt allows developers to build interactive command-line interfaces (CLI) that support user-defined commands, history management, and customizable callbacks for command execution.\n\nThis component integrates with [`esp_linenoise`](../esp_linenoise) for line editing and input handling, and with [`esp_cli_commands`](../esp_cli_commands) for command parsing and execution.\n\n---\n\n## Features\n\n- Modular REPL management with explicit `start` and `stop` control\n- Integration with [`esp_linenoise`](../esp_linenoise) for input and history\n- Support for command sets through [`esp_cli_commands`](../esp_cli_commands)\n- Configurable callbacks for:\n  - Pre-execution processing\n  - Post-execution handling\n  - On-stop and on-exit events\n- Thread-safe operation using FreeRTOS semaphores\n- Optional command history persistence to filesystem\n\n---\n\n## Usage\n\nA typical use case involves:\n\n1. Initializing `esp_linenoise` and `esp_cli_commands`\n2. Creating the esp_cli instance with `esp_cli_create()`\n3. Running `esp_cli()` in a task\n4. Starting and stopping the esp_cli using `esp_cli_start()` and `esp_cli_stop()`\n5. Destroying the instance with `esp_cli_destroy()` when done\n\n### Example\n\n```c\n#include <string.h>\n#include <fcntl.h>\n#include \"driver/uart_vfs.h\"\n#include \"driver/uart.h\"\n#include \"esp_log.h\"\n#include \"esp_cli.h\"\n#include \"esp_cli_commands.h\"\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n\n#define EXAMPLE_COMMAND_MAX_LENGTH 128\n\nstatic const char *TAG = \"repl_example\";\n\nstatic int example_cmd_func(void *context, esp_cli_commands_exec_arg_t *cmd_args, int argc, char **argv)\n{\n    (void)context; /* this is NULL and useless for the help command */\n    (void)argc;\n    (void)argv;\n\n    const char example_cmd_msg[] = \"example command output\\n\";\n    cmd_args->write_func(cmd_args->out_fd, example_cmd_msg, strlen(example_cmd_msg));\n    return 0;\n}\n\nstatic const char *example_cmd_hint(void *context)\n{\n    (void)context;\n    return \"example cmd hint\";\n}\n\nstatic const char *example_cmd_glossary(void *context)\n{\n    (void)context;\n    return \"example command glossary\";\n}\n\nstatic const char example_cmd_help_str[] = \"example command help\";\n\nESP_CLI_COMMAND_REGISTER(cmd,\n                         cmd,\n                         example_cmd_help_str,\n                         example_cmd_func,\n                         NULL,\n                         example_cmd_hint,\n                         example_cmd_glossary);\n\nstatic void example_completion_cb(const char *str, void *cb_ctx, esp_linenoise_completion_cb_t cb)\n{\n    esp_cli_commands_get_completion(NULL, str, cb_ctx, cb);\n}\n\nstatic char *example_hints_cb(const char *str, int *color, int *bold)\n{\n    /* return the hint of a given command */\n    return NULL;\n}\n\nstatic void example_free_hints_cb(void *ptr)\n{\n    /* free the hint pointed at by the pointer in parameter */\n}\n\nstatic void example_cli_task(void *arg)\n{\n    esp_cli_handle_t repl_hdl = (esp_cli_handle_t)arg;\n\n    // Run REPL loop (blocking until esp_cli_stop() is called)\n    // The loop won't be reached until esp_cli_start() is called\n    esp_cli(repl_hdl);\n\n    ESP_LOGI(TAG, \"esp_cli instance task exiting\");\n    vTaskDelete(NULL);\n}\n\nstatic void example_init_io(void)\n{\n    /* Drain stdout before reconfiguring it */\n    fflush(stdout);\n    fsync(fileno(stdout));\n\n#if defined(CONFIG_ESP_CONSOLE_UART_DEFAULT) || defined(CONFIG_ESP_CONSOLE_UART_CUSTOM)\n    /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */\n    uart_vfs_dev_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR);\n    /* Move the caret to the beginning of the next line on '\\n' */\n    uart_vfs_dev_port_set_tx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CRLF);\n\n    /* Configure UART. Note that REF_TICK is used so that the baud rate remains\n     * correct while APB frequency is changing in light sleep mode.\n     */\n    const uart_config_t uart_config = {\n            .baud_rate = CONFIG_ESP_CONSOLE_UART_BAUDRATE,\n            .data_bits = UART_DATA_8_BITS,\n            .parity = UART_PARITY_DISABLE,\n            .stop_bits = UART_STOP_BITS_1,\n#if SOC_UART_SUPPORT_REF_TICK\n            .source_clk = UART_SCLK_REF_TICK,\n#elif SOC_UART_SUPPORT_XTAL_CLK\n            .source_clk = UART_SCLK_XTAL,\n#endif\n    };\n    /* Install UART driver for interrupt-driven reads and writes */\n    ESP_ERROR_CHECK( uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0) );\n    ESP_ERROR_CHECK( uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config) );\n\n    /* Tell VFS to use UART driver */\n    uart_vfs_dev_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);\n\n#elif defined(CONFIG_ESP_CONSOLE_USB_CDC)\n    /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */\n    esp_vfs_dev_cdcacm_set_rx_line_endings(ESP_LINE_ENDINGS_CR);\n    /* Move the caret to the beginning of the next line on '\\n' */\n    esp_vfs_dev_cdcacm_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);\n\n    /* Enable blocking mode on stdin and stdout */\n    fcntl(fileno(stdout), F_SETFL, 0);\n    fcntl(fileno(stdin), F_SETFL, 0);\n\n#elif defined(CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG)\n    /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */\n    usb_serial_jtag_vfs_set_rx_line_endings(ESP_LINE_ENDINGS_CR);\n    /* Move the caret to the beginning of the next line on '\\n' */\n    usb_serial_jtag_vfs_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);\n\n    /* Enable blocking mode on stdin and stdout */\n    fcntl(fileno(stdout), F_SETFL, 0);\n    fcntl(fileno(stdin), F_SETFL, 0);\n\n    usb_serial_jtag_driver_config_t jtag_config = {\n        .tx_buffer_size = 256,\n        .rx_buffer_size = 256,\n    };\n\n    /* Install USB-SERIAL-JTAG driver for interrupt-driven reads and writes */\n    ESP_ERROR_CHECK( usb_serial_jtag_driver_install(&jtag_config));\n\n    /* Tell vfs to use usb-serial-jtag driver */\n    usb_serial_jtag_vfs_use_driver();\n\n#else\n#error Unsupported console type\n#endif\n\n    /* Disable buffering on stdin */\n    setvbuf(stdin, NULL, _IONBF, 0);\n}\n\nvoid app_main(void)\n{\n    esp_err_t ret;\n    esp_cli_handle_t cli = NULL;\n\n    /* configure the IO used by the esp_cli */\n    example_init_io();\n\n    // Initialize esp_linenoise (mandatory)\n    esp_linenoise_handle_t esp_linenoise_hdl = NULL;\n    esp_linenoise_config_t esp_linenoise_config;\n    esp_linenoise_config.prompt = \">\";\n    esp_linenoise_config.max_cmd_line_length = EXAMPLE_COMMAND_MAX_LENGTH;\n    esp_linenoise_config.history_max_length = 16;\n    esp_linenoise_config.in_fd = STDIN_FILENO;\n    esp_linenoise_config.out_fd = STDOUT_FILENO;\n    esp_linenoise_config.allow_multi_line = true;\n    esp_linenoise_config.allow_empty_line = true;\n    esp_linenoise_config.allow_dumb_mode = false;\n    esp_linenoise_config.completion_cb = example_completion_cb;\n    esp_linenoise_config.hints_cb = example_hints_cb;\n    esp_linenoise_config.free_hints_cb = example_free_hints_cb;\n    esp_linenoise_config.read_bytes_cb = NULL; // use default read function\n    esp_linenoise_config.write_bytes_cb = NULL; // use default write function\n    esp_linenoise_config.history = NULL;\n    ESP_ERROR_CHECK(esp_linenoise_create_instance(&esp_linenoise_config, &esp_linenoise_hdl));\n\n    // Initialize command set (optional)\n    const char* cmd_set[1] = { \"cmd\" };\n    esp_cli_command_set_handle_t esp_cli_commands_cmd_set = ESP_CLI_COMMANDS_CREATE_CMD_SET(cmd_set, ESP_CLI_COMMAND_FIELD_ACCESSOR(name));\n\n    esp_cli_config_t cli_cfg = {\n        .linenoise_handle = esp_linenoise_hdl,\n        .command_set_handle = esp_cli_commands_cmd_set, /* optional */\n        .max_cmd_line_size = EXAMPLE_COMMAND_MAX_LENGTH,\n        .history_save_path = \"/spiffs/cli_history.txt\", /* optional */\n    };\n\n    ret = esp_cli_create(&cli_cfg, &cli);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to create esp_cli instance (%s)\", esp_err_to_name(ret));\n        return;\n    }\n\n    // Create esp_cli instance task\n    if (xTaskCreate(example_cli_task, \"example_cli_task\", 4096, cli, 5, NULL) != pdPASS) {\n        ESP_LOGE(TAG, \"Failed to create esp_cli instance task\");\n        esp_cli_destroy(cli);\n        return;\n    }\n\n    ESP_LOGI(TAG, \"Starting esp_cli...\");\n    ret = esp_cli_start(cli);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to start esp_cli (%s)\", esp_err_to_name(ret));\n        esp_cli_destroy(cli);\n        return;\n    }\n\n    // Application logic can run in parallel while esp_cli instance runs in its own task\n    // [...]\n    vTaskDelay(pdMS_TO_TICKS(10000)); // Example delay\n\n    // Stop esp_cli instance\n    ret = esp_cli_stop(cli);\n    if (ret != ESP_OK) {\n        ESP_LOGW(TAG, \"Failed to stop esp_cli (%s)\", esp_err_to_name(ret));\n    }\n\n    ESP_LOGI(TAG, \"esp_cli exited\");\n\n    // Destroy esp_cli instance and clean up\n    ret = esp_cli_destroy(cli);\n    if (ret != ESP_OK) {\n        ESP_LOGW(TAG, \"Failed to destroy esp_cli instance cleanly (%s)\", esp_err_to_name(ret));\n    }\n\n    ESP_LOGI(TAG, \"esp_cli example finished\");\n}\n```\n"
  },
  {
    "path": "esp_cli/host_test/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.22)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(esp_cli_host_test)\n"
  },
  {
    "path": "esp_cli/host_test/main/CMakeLists.txt",
    "content": "\nidf_component_register(SRCS \"test_esp_cli.c\" \"test_main.c\"\n                    PRIV_INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES unity\n                    WHOLE_ARCHIVE)\n"
  },
  {
    "path": "esp_cli/host_test/main/idf_component.yml",
    "content": "dependencies:\n  espressif/esp_cli:\n    version: \"*\"\n    override_path: \"../..\"\n"
  },
  {
    "path": "esp_cli/host_test/main/test_esp_cli.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include <stdio.h>\n#include <fcntl.h>\n#include <sys/time.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"freertos/semphr.h\"\n#include \"unity.h\"\n#include \"esp_cli.h\"\n#include \"esp_linenoise.h\"\n#include \"esp_cli_commands.h\"\n\n#include <sys/socket.h>\n\ninline __attribute__((always_inline))\nuint32_t get_millis(void)\n{\n    struct timeval tv = { 0 };\n    gettimeofday(&tv, NULL);\n    return tv.tv_sec * 1000 + tv.tv_usec / 1000;\n}\n\ninline __attribute__((always_inline))\nvoid wait_ms(int ms)\n{\n    vTaskDelay(pdMS_TO_TICKS(ms));\n}\n\nstatic size_t s_on_enter_nb_of_calls = 0;\nstatic size_t s_pre_executor_nb_of_calls = 0;\nstatic size_t s_post_executor_nb_of_calls = 0;\nstatic size_t s_on_stop_nb_of_calls = 0;\nstatic size_t s_on_exit_nb_of_calls = 0;\n\nvoid test_on_enter(void *ctx, esp_cli_handle_t handle)\n{\n    s_on_enter_nb_of_calls++;\n    return;\n}\n\nesp_err_t test_pre_executor(void *ctx, const char *buf, esp_err_t reader_ret_val)\n{\n    s_pre_executor_nb_of_calls++;\n    return ESP_OK;\n}\n\nesp_err_t test_post_executor(void *ctx, const char *buf, esp_err_t executor_ret_val, int cmd_ret_val)\n{\n    s_post_executor_nb_of_calls++;\n    return ESP_OK;\n}\n\nvoid test_on_stop(void *ctx, esp_cli_handle_t handle)\n{\n    s_on_stop_nb_of_calls++;\n    return;\n}\n\nvoid test_on_exit(void *ctx, esp_cli_handle_t handle)\n{\n    s_on_exit_nb_of_calls++;\n    return;\n}\n\n/* Pass two semaphores:\n *  - start_sem: child gives it when it reached esp_cli() (so main knows child started)\n *  - done_sem:   child gives it just before deleting itself (so main can \"join\")\n */\ntypedef struct task_args {\n    SemaphoreHandle_t start_sem;\n    SemaphoreHandle_t done_sem;\n    esp_cli_handle_t hdl;\n} task_args_t;\n\nstatic void esp_cli_task(void *args)\n{\n    task_args_t *task_args = (task_args_t *)args;\n\n    /* signal to main that task started and esp_cli() will run */\n    xSemaphoreGive(task_args->start_sem);\n\n    /* run the esp_cli REPL loop (will return when stopped) */\n    esp_cli(task_args->hdl);\n\n    /* signal completion (emulates pthread_join notification) */\n    xSemaphoreGive(task_args->done_sem);\n\n    /* self-delete */\n    vTaskDelete(NULL);\n}\n\nstatic int s_socket_fd[2];\n\nstatic void test_socket_setup(int socket_fd[2])\n{\n    TEST_ASSERT_EQUAL(0, socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fd));\n\n    /* ensure reads are blocking */\n    int flags = fcntl(socket_fd[0], F_GETFL, 0);\n    flags &= ~O_NONBLOCK;\n    fcntl(socket_fd[0], F_SETFL, flags);\n\n    flags = fcntl(socket_fd[1], F_GETFL, 0);\n    flags &= ~O_NONBLOCK;\n    fcntl(socket_fd[1], F_SETFL, flags);\n}\n\nstatic void test_socket_teardown(int socket_fd[2])\n{\n    close(socket_fd[0]);\n    close(socket_fd[1]);\n}\n\nstatic void test_send_characters(int socket_fd, const char *msg)\n{\n    wait_ms(100);\n\n    const size_t msg_len = strlen(msg);\n    const int nwrite = write(socket_fd, msg, msg_len);\n    TEST_ASSERT_EQUAL(msg_len, nwrite);\n}\n\nstatic void esp_cli_teardown(SemaphoreHandle_t *start_sem, SemaphoreHandle_t *done_sem, int socket_fd[2],\n                             esp_linenoise_handle_t *linenoise_hdl, esp_cli_handle_t *cli_hdl)\n{\n    /* destroy the instance of esp_cli */\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_destroy(*cli_hdl));\n\n    /* delete the linenoise instance */\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_delete_instance(*linenoise_hdl));\n\n    /* cleanup semaphores */\n    vSemaphoreDelete(*start_sem);\n    vSemaphoreDelete(*done_sem);\n\n    /* close the socketpair */\n    test_socket_teardown(socket_fd);\n\n    s_on_stop_nb_of_calls = 0;\n    s_on_exit_nb_of_calls = 0;\n    s_on_enter_nb_of_calls = 0;\n    s_pre_executor_nb_of_calls = 0;\n    s_post_executor_nb_of_calls = 0;\n}\n\nstatic void esp_cli_setup(SemaphoreHandle_t *start_sem, SemaphoreHandle_t *done_sem, int socket_fd[2],\n                          esp_linenoise_handle_t *linenoise_hdl, esp_cli_handle_t *cli_hdl)\n{\n    /* create semaphores */\n    *start_sem = xSemaphoreCreateBinary();\n    TEST_ASSERT_NOT_NULL(start_sem);\n    *done_sem = xSemaphoreCreateBinary();\n    TEST_ASSERT_NOT_NULL(done_sem);\n\n    /* create the socket_pair */\n    test_socket_setup(socket_fd);\n\n    /* ensure both semaphores are in the \"taken/empty\" state:\n    taking with 0 timeout guarantees they are empty afterwards\n    regardless of the create semantics on this FreeRTOS build. */\n    xSemaphoreTake(*start_sem, 0);\n    xSemaphoreTake(*done_sem, 0);\n\n    esp_linenoise_config_t linenoise_config;\n    esp_linenoise_get_instance_config_default(&linenoise_config);\n    linenoise_config.in_fd = socket_fd[0];\n    linenoise_config.out_fd = socket_fd[0];\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_create_instance(&linenoise_config, linenoise_hdl));\n    TEST_ASSERT_NOT_NULL(*linenoise_hdl);\n\n    esp_cli_config_t cli_config = {\n        .linenoise_handle = *linenoise_hdl,\n        .command_set_handle = NULL,\n        .max_cmd_line_size = 256,\n        .history_save_path = NULL,\n        .on_enter = { .func = test_on_enter, .ctx = NULL },\n        .pre_executor = { .func = test_pre_executor, .ctx = NULL },\n        .post_executor = { .func = test_post_executor, .ctx = NULL },\n        .on_stop = { .func = test_on_stop, .ctx = NULL },\n        .on_exit = { .func = test_on_exit, .ctx = NULL }\n    };\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_create(&cli_config, cli_hdl));\n    TEST_ASSERT_NOT_NULL(*cli_hdl);\n\n    s_on_stop_nb_of_calls = 0;\n    s_on_exit_nb_of_calls = 0;\n    s_on_enter_nb_of_calls = 0;\n    s_pre_executor_nb_of_calls = 0;\n    s_post_executor_nb_of_calls = 0;\n}\n\nTEST_CASE(\"esp_cli() loop calls all callbacks and exit on call to esp_cli_stop\", \"[esp_cli]\")\n{\n    SemaphoreHandle_t start_sem, done_sem;\n    esp_linenoise_handle_t linenoise_hdl;\n    esp_cli_handle_t cli_hdl;\n    esp_cli_setup(&start_sem, &done_sem, s_socket_fd, &linenoise_hdl, &cli_hdl);\n\n    /* create the esp_cli instance task */\n    task_args_t args = {.start_sem = start_sem, .done_sem = done_sem, .hdl = cli_hdl};\n    BaseType_t rc = xTaskCreate(esp_cli_task, \"esp_cli_task\", 4096, &args, 5, NULL);\n    TEST_ASSERT_EQUAL(pdPASS, rc);\n\n    /* should fail before esp_cli instance is started */\n    TEST_ASSERT_NOT_EQUAL(ESP_OK, esp_cli_stop(cli_hdl));\n\n    /* start esp_cli instance */\n    TEST_ASSERT_NOT_EQUAL(ESP_OK, esp_cli_start(NULL));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_start(cli_hdl));\n\n    wait_ms(100);\n\n    /* wait for the esp_cli task to signal it started */\n    TEST_ASSERT_TRUE(xSemaphoreTake(start_sem, pdMS_TO_TICKS(2000)));\n\n    /* send a dummy string new line terminated to trigger linenoise to return */\n    const char *input_line = \"dummy_message\\n\";\n    test_send_characters(s_socket_fd[1], input_line);\n\n    /* wait for a bit so esp_cli() has time to loop back into esp_linenoise_get_line */\n    wait_ms(500);\n\n    /* check that pre-executor, post-executor callbacks are called */\n    TEST_ASSERT_EQUAL(1, s_pre_executor_nb_of_calls);\n    TEST_ASSERT_EQUAL(1, s_post_executor_nb_of_calls);\n\n    /* stop esp_cli and wait for task to finish (emulate pthread_join) */\n    TEST_ASSERT_NOT_EQUAL(ESP_OK, esp_cli_stop(NULL));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_stop(cli_hdl));\n\n    /* wait for the esp_cli task to signal completion */\n    TEST_ASSERT_TRUE(xSemaphoreTake(done_sem, pdMS_TO_TICKS(2000)));\n\n    /* check that all callbacks were called the right number of times */\n    TEST_ASSERT_EQUAL(1, s_on_stop_nb_of_calls);\n    TEST_ASSERT_EQUAL(1, s_on_enter_nb_of_calls);\n    TEST_ASSERT_EQUAL(1, s_on_exit_nb_of_calls);\n    TEST_ASSERT_EQUAL(2, s_pre_executor_nb_of_calls);\n    TEST_ASSERT_EQUAL(2, s_post_executor_nb_of_calls);\n\n    /* make sure calling stop fails because the esp_cli instance is no longer running */\n    TEST_ASSERT_NOT_EQUAL(ESP_OK, esp_cli_stop(cli_hdl));\n\n    /* destroy the esp_cli instance */\n    TEST_ASSERT_NOT_EQUAL(ESP_OK, esp_cli_destroy(NULL));\n    esp_cli_teardown(&start_sem, &done_sem, s_socket_fd, &linenoise_hdl, &cli_hdl);\n}\n\nTEST_CASE(\"esp_cli() exits when esp_cli_stop() called from the task running esp_cli()\", \"[esp_cli]\")\n{\n    SemaphoreHandle_t start_sem, done_sem;\n    esp_linenoise_handle_t linenoise_hdl;\n    esp_cli_handle_t cli_hdl;\n    esp_cli_setup(&start_sem, &done_sem, s_socket_fd, &linenoise_hdl, &cli_hdl);\n\n    /* create the esp_cli instance task */\n    task_args_t args = {.start_sem = start_sem, .done_sem = done_sem, .hdl = cli_hdl};\n    BaseType_t rc = xTaskCreate(esp_cli_task, \"esp_cli_task\", 4096, &args, 5, NULL);\n    TEST_ASSERT_EQUAL(pdPASS, rc);\n\n    /* start esp_cli instance */\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_start(cli_hdl));\n\n    wait_ms(100);\n\n    /* wait for the esp_cli instance task to signal it started */\n    TEST_ASSERT_TRUE(xSemaphoreTake(start_sem, pdMS_TO_TICKS(2000)));\n\n    /* send the quit command */\n    const char *quit_cmd_line = \"quit  \\n\";\n    test_send_characters(s_socket_fd[1], quit_cmd_line);\n\n    /* wait for the esp_cli instance task to signal completion */\n    TEST_ASSERT_TRUE(xSemaphoreTake(done_sem, pdMS_TO_TICKS(2000)));\n\n    esp_cli_teardown(&start_sem, &done_sem, s_socket_fd, &linenoise_hdl, &cli_hdl);\n}\n\nTEST_CASE(\"create and destroy several instances of esp_cli\", \"[esp_cli]\")\n{\n    /* create semaphores */\n    SemaphoreHandle_t start_sem_a, start_sem_b;\n    SemaphoreHandle_t done_sem_a, done_sem_b;\n    esp_cli_handle_t cli_hdl_a, cli_hdl_b;\n    esp_linenoise_handle_t linenoise_hdl_a, linenoise_hdl_b;\n    int socket_fd_a[2], socket_fd_b[2];\n\n    /*  create 2 instances of esp_cli*/\n    esp_cli_setup(&start_sem_a, &done_sem_a, socket_fd_a, &linenoise_hdl_a, &cli_hdl_a);\n    esp_cli_setup(&start_sem_b, &done_sem_b, socket_fd_b, &linenoise_hdl_b, &cli_hdl_b);\n\n    /* create the esp_cli instance task A */\n    task_args_t args_a = {.start_sem = start_sem_a, .done_sem = done_sem_a, .hdl = cli_hdl_a};\n    BaseType_t rc = xTaskCreate(esp_cli_task, \"esp_cli_task_a\", 4096, &args_a, 5, NULL);\n    TEST_ASSERT_EQUAL(pdPASS, rc);\n\n    /* create the esp_cli instance task B */\n    task_args_t args_b = {.start_sem = start_sem_b, .done_sem = done_sem_b, .hdl = cli_hdl_b};\n    rc = xTaskCreate(esp_cli_task, \"esp_cli_task_b\", 4096, &args_b, 5, NULL);\n    TEST_ASSERT_EQUAL(pdPASS, rc);\n\n    /* start esp_cli instance */\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_start(cli_hdl_a));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_start(cli_hdl_b));\n    wait_ms(500);\n\n    /* wait for the esp_cli instance tasks to signal it started */\n    TEST_ASSERT_TRUE(xSemaphoreTake(start_sem_a, pdMS_TO_TICKS(2000)));\n    TEST_ASSERT_TRUE(xSemaphoreTake(start_sem_b, pdMS_TO_TICKS(2000)));\n\n    /* terminate instance A */\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_stop(cli_hdl_a));\n\n    /* wait for the esp_cli instance task to signal completion */\n    TEST_ASSERT_TRUE(xSemaphoreTake(done_sem_a, pdMS_TO_TICKS(2000)));\n\n    /* terminate instance B */\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_stop(cli_hdl_b));\n\n    /* wait for the esp_cli instance task to signal completion */\n    TEST_ASSERT_TRUE(xSemaphoreTake(done_sem_b, pdMS_TO_TICKS(2000)));\n\n    esp_cli_teardown(&start_sem_a, &done_sem_a, socket_fd_a, &linenoise_hdl_a, &cli_hdl_a);\n    esp_cli_teardown(&start_sem_b, &done_sem_b, socket_fd_b, &linenoise_hdl_b, &cli_hdl_b);\n}\n"
  },
  {
    "path": "esp_cli/host_test/main/test_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"unity.h\"\n#include \"unity_test_runner.h\"\n#include \"esp_heap_caps.h\"\n#include \"unity_test_utils_memory.h\"\n\nvoid setUp(void)\n{\n    unity_utils_record_free_mem();\n}\n\nvoid tearDown(void)\n{\n    unity_utils_evaluate_leaks_direct(0);\n}\n\nvoid app_main(void)\n{\n    printf(\"Running esp_cli component host tests\\n\");\n    unity_run_menu();\n}\n"
  },
  {
    "path": "esp_cli/host_test/pytest_host_esp_cli.py",
    "content": "import pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.utils import idf_parametrize\nimport glob\nfrom pathlib import Path\n\n\n\n@pytest.mark.host_test\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that did not build\"\n)\n@pytest.mark.parametrize('target', ['linux'], indirect=['target'])\ndef host_test_esp_cli(dut) -> None:\n    dut.run_all_single_board_cases()\n"
  },
  {
    "path": "esp_cli/host_test/sdkconfig.defaults",
    "content": "CONFIG_ESP_TASK_WDT_EN=n\nCONFIG_ESP_CLI_HAS_QUIT_CMD=y"
  },
  {
    "path": "esp_cli/idf_component.yml",
    "content": "version: \"0.1.2\"\ndescription: \"esp_cli — A command-line interface component that uses a REPL as its main execution loop.\"\nurl: https://github.com/espressif/idf-extra-components/tree/master/esp_cli\ndependencies:\n  espressif/esp_linenoise: \"*\"\n  espressif/esp_cli_commands: \"*\"\nsbom:\n  manifests:\n    - path: sbom_esp_cli.yml\n      dest: ."
  },
  {
    "path": "esp_cli/include/esp_cli.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdbool.h>\n#include \"esp_err.h\"\n#include \"esp_linenoise.h\"\n#include \"esp_cli_commands.h\"\n\n/**\n * @brief Handle to a esp_cli instance.\n */\ntypedef struct esp_cli_instance *esp_cli_handle_t;\n\n/**\n * @brief Function prototype called at the beginning of esp_cli().\n *\n * @param ctx User-defined context pointer.\n * @param handle Handle to the esp_cli instance.\n */\ntypedef void (*esp_cli_on_enter_fn)(void *ctx, esp_cli_handle_t handle);\n\n/**\n * @brief Enter callback configuration structure for the esp_cli.\n */\ntypedef struct esp_cli_on_enter {\n    esp_cli_on_enter_fn func; /**!< Function called at the beginning of esp_cli() */\n    void *ctx;                /**!< Context passed to the enter function */\n} esp_cli_on_enter_t;\n\n/**\n * @brief Function prototype called before executing a command.\n *\n * @param ctx User-defined context pointer.\n * @param buf Buffer containing the command.\n * @param reader_ret_val Return value from the reader function.\n *\n * @return ESP_OK to continue execution, error code to abort.\n */\ntypedef esp_err_t (*esp_cli_pre_executor_fn)(void *ctx, const char *buf, esp_err_t reader_ret_val);\n\n/**\n * @brief Pre-executor configuration structure for the esp_cli.\n */\ntypedef struct esp_cli_pre_executor {\n    esp_cli_pre_executor_fn func; /**!< Function to run before command execution */\n    void *ctx;                      /**!< Context passed to the pre-executor function */\n} esp_cli_pre_executor_t;\n\n/**\n * @brief Function prototype called after executing a command.\n *\n * @param ctx User-defined context pointer.\n * @param buf Command that was executed.\n * @param executor_ret_val Return value from the executor function.\n * @param cmd_ret_val Command-specific return value.\n *\n * @return ESP_OK on success, error code otherwise.\n */\ntypedef esp_err_t (*esp_cli_post_executor_fn)(void *ctx, const char *buf, esp_err_t executor_ret_val, int cmd_ret_val);\n\n/**\n * @brief Post-executor configuration structure for the esp_cli.\n */\ntypedef struct esp_cli_post_executor {\n    esp_cli_post_executor_fn func; /**!< Function called after command execution */\n    void *ctx;                       /**!< Context passed to the post-executor function */\n} esp_cli_post_executor_t;\n\n/**\n * @brief Function prototype called when the esp_cli is stopping.\n *\n * This callback allows the user to unblock the reader (or perform other\n * cleanup) so that the esp_cli can return from `esp_cli()`.\n *\n * @param ctx User-defined context pointer.\n * @param handle Handle to the esp_cli instance.\n */\ntypedef void (*esp_cli_on_stop_fn)(void *ctx, esp_cli_handle_t handle);\n\n/**\n * @brief Stop callback configuration structure for the esp_cli.\n */\ntypedef struct esp_cli_on_stop {\n    esp_cli_on_stop_fn func; /**!< Function called when esp_cli stop is requested */\n    void *ctx;                /**!< Context passed to the on_stop function */\n} esp_cli_on_stop_t;\n\n/**\n * @brief Function prototype called when the esp_cli exits.\n *\n * @param ctx User-defined context pointer.\n * @param handle Handle to the esp_cli instance.\n */\ntypedef void (*esp_cli_on_exit_fn)(void *ctx, esp_cli_handle_t handle);\n\n/**\n * @brief Exit callback configuration structure for the esp_cli.\n */\ntypedef struct esp_cli_on_exit {\n    esp_cli_on_exit_fn func; /**!< Function called on esp_cli exit */\n    void *ctx;                /**!< Context passed to the exit function */\n} esp_cli_on_exit_t;\n\n/**\n * @brief Configuration structure to initialize a esp_cli instance.\n */\ntypedef struct esp_cli_config {\n    esp_linenoise_handle_t linenoise_handle;    /**!< Handle to the esp_linenoise instance */\n    esp_cli_command_set_handle_t command_set_handle;   /**!< Handle to a set of commands */\n    size_t max_cmd_line_size;                   /**!< Maximum allowed command line size */\n    const char *history_save_path;              /**!< Path to file to save the history */\n    esp_cli_on_enter_t on_enter;               /**!< Enter callback and context */\n    esp_cli_pre_executor_t pre_executor;       /**!< Pre-executor callback and context */\n    esp_cli_post_executor_t post_executor;     /**!< Post-executor callback and context */\n    esp_cli_on_stop_t on_stop;                 /**!< Stop callback and context */\n    esp_cli_on_exit_t on_exit;                 /**!< Exit callback and context */\n} esp_cli_config_t;\n\n/**\n * @brief Create a esp_cli instance.\n *\n * @param config Pointer to the configuration structure.\n * @param out_handle Pointer to store the created esp_cli instance handle.\n *\n * @return ESP_OK on success, error code otherwise.\n */\nesp_err_t esp_cli_create(const esp_cli_config_t *config, esp_cli_handle_t *out_handle);\n\n/**\n * @brief Destroy a esp_cli instance.\n *\n * @param handle esp_cli instance handle to destroy.\n *\n * @return ESP_OK on success, error code otherwise.\n */\nesp_err_t esp_cli_destroy(esp_cli_handle_t handle);\n\n/**\n * @brief Start a esp_cli instance.\n *\n * @param handle esp_cli instance handle.\n *\n * @return ESP_OK on success, error code otherwise.\n */\nesp_err_t esp_cli_start(esp_cli_handle_t handle);\n\n/**\n * @brief Stop a esp_cli instance.\n *\n * @note This function will internally call 'esp_linenoise_abort' first to try to return from\n * 'esp_linenoise_get_line'. If the user has provided a custom read to the esp_linenoise\n * instance used by the esp_cli instance, it is the responsibility of the user to provide\n * the mechanism to return from this custom read by providing a callback to the 'on_stop' field\n * in the esp_cli_config_t.\n *\n * Return Values:\n *   - ESP_OK: Returned if the user has not provided a custom read and the abort operation succeeds.\n *   - ESP_ERR_INVALID_STATE: Returned if the user has provided a custom read. In this case, the user\n *     is responsible for implementing an abort mechanism that ensures a successful return from\n *     their custom read. This can be achieved by placing the logic in the on_stop callback.\n *\n * Behavior:\n *   - When a custom read is registered, ESP_ERR_INVALID_STATE indicates that esp_cli_stop() cannot\n *     forcibly return from the read. The user must handle the return themselves via on_stop().\n *   - From the perspective of esp_cli_stop(), this scenario is treated as successful, and its\n *     return value should be set to ESP_OK.\n *\n * @param handle esp_cli instance handle.\n *\n * @return ESP_OK on success, error code otherwise.\n */\nesp_err_t esp_cli_stop(esp_cli_handle_t handle);\n\n/**\n * @brief Run the esp_cli loop.\n *\n * @param handle esp_cli instance handle.\n */\nvoid esp_cli(esp_cli_handle_t handle);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_cli/sbom_esp_cli.yml",
    "content": "name: esp_cli\ndescription: Command handling component\nurl: https://github.com/espressif/idf-extra-components/tree/master/esp_cli\nversion: 1.0.0\ncpe: cpe:2.3:a:espressif:esp_cli:{}:*:*:*:*:*:*:*\nsupplier: 'Organization: Espressif Systems'"
  },
  {
    "path": "esp_cli/src/esp_cli.c",
    "content": "\n/*\n* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n*\n* SPDX-License-Identifier: Apache-2.0\n*/\n#include <stdbool.h>\n#include <string.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/semphr.h\"\n#include \"freertos/task.h\"\n#include \"esp_cli.h\"\n#include \"esp_err.h\"\n#include \"esp_cli_commands.h\"\n#include \"esp_linenoise.h\"\ntypedef enum {\n    ESP_CLI_STATE_RUNNING,\n    ESP_CLI_STATE_STOPPED\n} esp_cli_state_e;\n\ntypedef struct esp_cli_state {\n    esp_cli_state_e state;\n    TaskHandle_t task_hdl;\n    SemaphoreHandle_t mux;\n} esp_cli_state_t;\n\ntypedef struct esp_cli_instance {\n    esp_cli_config_t config;\n    esp_cli_state_t state;\n} esp_cli_instance_t;\n\n#if CONFIG_ESP_CLI_HAS_QUIT_CMD\n#define _ESP_CLI_STRINGIFY(x) #x\n#define ESP_CLI_STRINGIFY(x) _ESP_CLI_STRINGIFY(x)\n\n#define ESP_CLI_QUIT_CMD quit\n#define ESP_CLI_QUIT_CMD_STR ESP_CLI_STRINGIFY(ESP_CLI_QUIT_CMD)\n#define ESP_CLI_QUIT_CMD_SIZE strlen(ESP_CLI_QUIT_CMD_STR)\n\n/* dummy command function callback to allow the registration for the quit command\n * to succeed */\nstatic int esp_cli_quit_cmd(void *context, esp_cli_commands_exec_arg_t *cmd_args, int argc, char **argv)\n{\n    return 0;\n}\n\nESP_CLI_COMMAND_REGISTER(ESP_CLI_QUIT_CMD,\n                         \"esp_cli\",\n                         \"This command will trigger the exit mechanism to exit from esp_cli() main loop\",\n                         esp_cli_quit_cmd,\n                         NULL,\n                         NULL,\n                         NULL\n                        );\n#endif // CONFIG_ESP_CLI_HAS_QUIT_CMD\n\n#define ESP_CLI_CHECK_INSTANCE(handle) do {    \\\n        if(handle == NULL) {                    \\\n            return ESP_ERR_INVALID_ARG;         \\\n        }                                       \\\n    } while(0)\n\nesp_err_t esp_cli_create(const esp_cli_config_t *config, esp_cli_handle_t *out_handle)\n{\n    if (!config || !out_handle) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    if ((config->linenoise_handle == NULL) ||\n            (config->max_cmd_line_size == 0)) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    esp_cli_instance_t *instance = malloc(sizeof(esp_cli_instance_t));\n    if (!instance) {\n        return ESP_ERR_NO_MEM;\n    }\n\n    instance->config = *config;\n    instance->state.state = ESP_CLI_STATE_STOPPED;\n    instance->state.mux = xSemaphoreCreateMutex();\n    if (!instance->state.mux) {\n        free(instance);\n        return ESP_FAIL;\n    }\n\n    /* take the mutex right away to prevent the task to start running until\n    * the user explicitly calls esp_cli_start */\n    xSemaphoreTake(instance->state.mux, portMAX_DELAY);\n\n    *out_handle = instance;\n    return ESP_OK;\n}\n\nesp_err_t esp_cli_destroy(esp_cli_handle_t handle)\n{\n    ESP_CLI_CHECK_INSTANCE(handle);\n    esp_cli_state_t *state = &handle->state;\n\n    /* the instance has to be not running for esp_cli to destroy it */\n    if (state->state != ESP_CLI_STATE_STOPPED) {\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    vSemaphoreDelete(state->mux);\n\n    free(handle);\n\n    return ESP_OK;\n}\n\nesp_err_t esp_cli_start(esp_cli_handle_t handle)\n{\n    ESP_CLI_CHECK_INSTANCE(handle);\n    esp_cli_state_t *state = &handle->state;\n\n    if (state->state != ESP_CLI_STATE_STOPPED) {\n        return ESP_ERR_INVALID_STATE;\n    }\n    state->state = ESP_CLI_STATE_RUNNING;\n    xSemaphoreGive(state->mux);\n\n    return ESP_OK;\n}\n\nesp_err_t esp_cli_stop(esp_cli_handle_t handle)\n{\n    ESP_CLI_CHECK_INSTANCE(handle);\n    esp_cli_config_t *config = &handle->config;\n    esp_cli_state_t *state = &handle->state;\n\n    if (state->state != ESP_CLI_STATE_RUNNING) {\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    /* update the state to force the while loop in esp_cli to return */\n    state->state = ESP_CLI_STATE_STOPPED;\n\n    /** This function forces esp_linenoise_get_line() to return.\n     *\n     * Return Values:\n     *   - ESP_OK: Returned if the user has not provided a custom read and the abort operation succeeds.\n     *   - ESP_ERR_INVALID_STATE: Returned if the user has provided a custom read. In this case, the user\n     *     is responsible for implementing an abort mechanism that ensures a successful return from\n     *     their custom read. This can be achieved by placing the logic in the on_stop callback.\n     *\n     * Behavior:\n     *   - When a custom read is registered, ESP_ERR_INVALID_STATE indicates that esp_cli_stop() cannot\n     *     forcibly return from the read. The user must handle the return of their custom read via on_stop().\n     *   - From the perspective of esp_cli_stop(), this scenario is treated as successful, and its\n     *     return value should be set to ESP_OK.\n     */\n    esp_err_t ret_val = esp_linenoise_abort(config->linenoise_handle);\n    if (ret_val == ESP_ERR_INVALID_STATE) {\n        ret_val = ESP_OK;\n    }\n\n    /* Call the on_stop callback to let the user unblock esp_linenoise\n    * if a custom read is provided */\n    if (config->on_stop.func != NULL) {\n        config->on_stop.func(config->on_stop.ctx, handle);\n    }\n\n    /* Wait for esp_cli() to finish and signal completion, in the event of\n     * esp_cli_stop() is called from the same task running esp_cli() (e.g.,\n     * called from a \"quit\" command), do not take the mutex to avoid a deadlock.\n     *\n     * If esp_cli_stop() is called from the same task, it assures that this task\n     * is not blocking in esp_linenoise_get_line() so the while loop in esp_cli()\n     * will return as we updated the state above */\n    if (state->task_hdl && state->task_hdl != xTaskGetCurrentTaskHandle()) {\n        xSemaphoreTake(state->mux, portMAX_DELAY);\n    }\n\n    return ret_val;\n}\n\nvoid esp_cli(esp_cli_handle_t handle)\n{\n    if (!handle) {\n        return;\n    }\n\n    esp_cli_config_t *config = &handle->config;\n    esp_cli_state_t *state = &handle->state;\n\n    /* trigger a user defined callback before the function gets into the while loop\n     * if the user wants to perform some logic that needs to be done within the task\n     * running the esp_cli instance */\n    if (config->on_enter.func != NULL) {\n        config->on_enter.func(config->on_enter.ctx, handle);\n    }\n\n    /* get the task handle of the task running this function.\n     * It is necessary to gather this information in case esp_cli_stop()\n     * is called from the same task as the one running esp_cli() (e.g.,\n     * through the execution of a command) */\n    state->task_hdl = xTaskGetCurrentTaskHandle();\n\n    /* allocate memory for the command line buffer */\n    const size_t cmd_line_size = config->max_cmd_line_size;\n    char *cmd_line = calloc(1, cmd_line_size);\n    if (!cmd_line) {\n        return;\n    }\n\n    /* Waiting for task notify. This happens when `esp_cli_start`\n    * function is called. */\n    xSemaphoreTake(state->mux, portMAX_DELAY);\n\n    esp_linenoise_handle_t l_hdl = config->linenoise_handle;\n    esp_cli_command_set_handle_t c_set = config->command_set_handle;\n\n    /* esp_cli REPL loop */\n    while (state->state == ESP_CLI_STATE_RUNNING) {\n\n        /* try to read a command line */\n        const esp_err_t read_ret = esp_linenoise_get_line(l_hdl, cmd_line, cmd_line_size);\n\n        /* Add the command to the history */\n        esp_linenoise_history_add(l_hdl, cmd_line);\n\n        /* Save command history to filesystem */\n        if (config->history_save_path) {\n            esp_linenoise_history_save(l_hdl, config->history_save_path);\n        }\n\n        /* forward the raw command line to the pre executor callback (e.g., save in history).\n        * this callback is not necessary for the user to register, continue if it isn't */\n        if (config->pre_executor.func != NULL) {\n            config->pre_executor.func(config->pre_executor.ctx, cmd_line, read_ret);\n        }\n\n        /* at this point, if the command is NULL, skip the executing part */\n        if (read_ret != ESP_OK) {\n            continue;\n        }\n\n#if CONFIG_ESP_CLI_HAS_QUIT_CMD\n        /* evaluate the command name. make sure that the first argument of the cmd_line\n         * is ESP_CLI_QUIT_CMD_STR and the character following that is either a space\n         * or a null character */\n        if ((strncmp(ESP_CLI_QUIT_CMD_STR, cmd_line, ESP_CLI_QUIT_CMD_SIZE) == 0) &&\n                ((cmd_line[ESP_CLI_QUIT_CMD_SIZE] == ' ') || (cmd_line[ESP_CLI_QUIT_CMD_SIZE] == '\\0'))) {\n            /* quit command received, call esp_cli_stop() */\n            if (esp_cli_stop(handle) == ESP_OK) {\n                /* if esp_cli_stop() was successful, retry the while condition.\n                 * the esp_cli state should have been changed which will force\n                 * the while to break */\n                continue;\n            }\n        }\n#endif // CONFIG_ESP_CLI_HAS_QUIT_CMD\n\n        /* try to run the command */\n        int cmd_func_ret;\n        esp_cli_commands_exec_arg_t cmd_args;\n        esp_err_t get_ret = esp_linenoise_get_out_fd(handle->config.linenoise_handle, &(cmd_args.out_fd));\n        if (get_ret != ESP_OK) {\n            cmd_args.out_fd = STDOUT_FILENO;\n        }\n        get_ret = esp_linenoise_get_write(handle->config.linenoise_handle, &(cmd_args.write_func));\n        if (get_ret != ESP_OK) {\n            cmd_args.write_func = write;\n        }\n\n        const esp_err_t exec_ret = esp_cli_commands_execute(cmd_line, &cmd_func_ret, c_set, &cmd_args);\n\n        /* forward the raw command line to the post executor callback (e.g., save in history).\n        * this callback is not necessary for the user to register, continue if it isn't */\n        if (config->post_executor.func != NULL) {\n            config->post_executor.func(config->post_executor.ctx, cmd_line, exec_ret, cmd_func_ret);\n        }\n\n        /* reset the cmd_line for next loop */\n        memset(cmd_line, 0x00, cmd_line_size);\n    }\n\n    /* free the memory allocated for the cmd_line buffer */\n    free(cmd_line);\n\n    /* call the on_exit callback before returning from esp_cli */\n    if (config->on_exit.func != NULL) {\n        config->on_exit.func(config->on_exit.ctx, handle);\n    }\n\n    /* release the semaphore to indicate esp_cli_stop that the esp_cli returned */\n    xSemaphoreGive(state->mux);\n}\n"
  },
  {
    "path": "esp_cli/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(esp_cli_test)\n"
  },
  {
    "path": "esp_cli/test_apps/main/CMakeLists.txt",
    "content": "\nidf_component_register(SRCS \"test_esp_cli.c\" \"test_main.c\"\n                    PRIV_INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES unity vfs esp_driver_uart esp_driver_usb_serial_jtag\n                    WHOLE_ARCHIVE)\n"
  },
  {
    "path": "esp_cli/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/esp_cli:\n    version: \"*\"\n    override_path: \"../..\"\n"
  },
  {
    "path": "esp_cli/test_apps/main/test_esp_cli.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include <stdio.h>\n#include <fcntl.h>\n\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"freertos/semphr.h\"\n#include \"unity.h\"\n\n#include \"esp_cli.h\"\n#include \"esp_linenoise.h\"\n#include \"esp_cli_commands.h\"\n\n#include \"sdkconfig.h\"\n#include \"esp_vfs.h\"\n#include \"esp_vfs_common.h\"\n#include \"driver/esp_private/uart_vfs.h\"\n#include \"driver/uart_vfs.h\"\n#include \"driver/uart.h\"\n#include \"driver/esp_private/usb_serial_jtag_vfs.h\"\n#include \"driver/usb_serial_jtag_vfs.h\"\n#include \"driver/usb_serial_jtag.h\"\n\nstatic size_t s_on_enter_nb_of_calls = 0;\nstatic size_t s_pre_executor_nb_of_calls = 0;\nstatic size_t s_post_executor_nb_of_calls = 0;\nstatic size_t s_on_stop_nb_of_calls = 0;\nstatic size_t s_on_exit_nb_of_calls = 0;\n\nvoid test_on_enter(void *ctx, esp_cli_handle_t handle)\n{\n    s_on_enter_nb_of_calls++;\n    return;\n}\n\nesp_err_t test_pre_executor(void *ctx, const char *buf, esp_err_t reader_ret_val)\n{\n    s_pre_executor_nb_of_calls++;\n    return ESP_OK;\n}\n\nesp_err_t test_post_executor(void *ctx, const char *buf, esp_err_t executor_ret_val, int cmd_ret_val)\n{\n    s_post_executor_nb_of_calls++;\n    return ESP_OK;\n}\n\nvoid test_on_stop(void *ctx, esp_cli_handle_t handle)\n{\n    s_on_stop_nb_of_calls++;\n    return;\n}\n\nvoid test_on_exit(void *ctx, esp_cli_handle_t handle)\n{\n    s_on_exit_nb_of_calls++;\n    return;\n}\n\n/* Pass two semaphores:\n *  - start_sem: child gives it when it reached esp_cli() (so main knows child started)\n *  - done_sem:   child gives it just before deleting itself (so main can \"join\")\n */\ntypedef struct task_args {\n    SemaphoreHandle_t start_sem;\n    SemaphoreHandle_t done_sem;\n    esp_cli_handle_t hdl;\n} task_args_t;\n\nstatic void esp_cli_task(void *args)\n{\n    task_args_t *task_args = (task_args_t *)args;\n\n    /* signal to main that task started and esp_cli() will run */\n    xSemaphoreGive(task_args->start_sem);\n\n    /* run the esp_cli REPL loop (will return when stopped) */\n    esp_cli(task_args->hdl);\n\n    /* signal completion (emulates pthread_join notification) */\n    xSemaphoreGive(task_args->done_sem);\n\n    /* self-delete */\n    vTaskDelete(NULL);\n}\n\nstatic void test_uart_install(int *in_fd, int *out_fd)\n{\n    /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */\n    uart_vfs_dev_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR);\n    /* Move the caret to the beginning of the next line on '\\n' */\n    uart_vfs_dev_port_set_tx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CRLF);\n\n    /* Configure UART. Note that REF_TICK/XTAL is used so that the baud rate remains\n     * correct while APB frequency is changing in light sleep mode.\n     */\n#if SOC_UART_SUPPORT_REF_TICK\n    uart_sclk_t clk_source = UART_SCLK_REF_TICK;\n    // REF_TICK clock can't provide a high baudrate\n    if (CONFIG_ESP_CONSOLE_UART_BAUDRATE > 1 * 1000 * 1000) {\n        clk_source = UART_SCLK_DEFAULT;\n        ESP_LOGW(TAG, \"light sleep UART wakeup might not work at the configured baud rate\");\n    }\n#elif SOC_UART_SUPPORT_XTAL_CLK\n    uart_sclk_t clk_source = UART_SCLK_XTAL;\n#else\n#error \"No UART clock source is aware of DFS\"\n#endif // SOC_UART_SUPPORT_xxx\n    const uart_config_t uart_config = {\n        .baud_rate = CONFIG_ESP_CONSOLE_UART_BAUDRATE,\n        .data_bits = UART_DATA_8_BITS,\n        .parity = UART_PARITY_DISABLE,\n        .stop_bits = UART_STOP_BITS_1,\n        .source_clk = clk_source,\n    };\n\n    uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config);\n\n    /* Install UART driver for interrupt-driven reads and writes */\n    TEST_ASSERT_EQUAL(ESP_OK, uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0));\n\n    /* Tell VFS to use UART driver */\n    uart_vfs_dev_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);\n\n    /* register the vfs, create a FD used to interface the UART */\n    const esp_vfs_fs_ops_t *uart_vfs = esp_vfs_uart_get_vfs();\n    TEST_ASSERT_EQUAL(ESP_OK, esp_vfs_register_fs(\"/dev/test_uart\", uart_vfs, 0, NULL));\n    /* open in blocking mode */\n    const int uart_fd = open(\"/dev/test_uart/0\", 0);\n    TEST_ASSERT(uart_fd != -1);\n    *in_fd = uart_fd;\n    *out_fd = uart_fd;\n}\n\nstatic void test_uart_uninstall(const int fd)\n{\n    /* close the stream */\n    const int ret = close(fd);\n    TEST_ASSERT(ret != -1);\n\n    /* unregister the vfs */\n    TEST_ASSERT_EQUAL(ESP_OK, esp_vfs_unregister(\"/dev/test_uart\"));\n\n    /* uninstall the driver for the default uart */\n    uart_vfs_dev_use_nonblocking(CONFIG_ESP_CONSOLE_UART_NUM);\n    TEST_ASSERT_EQUAL(ESP_OK, uart_driver_delete(CONFIG_ESP_CONSOLE_UART_NUM));\n}\n\nstatic void test_usj_install(int *in_fd, int *out_fd)\n{\n    /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */\n    usb_serial_jtag_vfs_set_rx_line_endings(ESP_LINE_ENDINGS_CR);\n    /* Move the caret to the beginning of the next line on '\\n' */\n    usb_serial_jtag_vfs_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);\n\n    /* Install USB-SERIAL-JTAG driver for interrupt-driven reads and writes */\n    usb_serial_jtag_driver_config_t usb_serial_jtag_config = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT();\n    TEST_ASSERT_EQUAL(ESP_OK, usb_serial_jtag_driver_install(&usb_serial_jtag_config));\n\n    /* register the vfs, create a FD used to interface the USJ */\n    const esp_vfs_fs_ops_t *usj_vfs = esp_vfs_usb_serial_jtag_get_vfs();\n    TEST_ASSERT_EQUAL(ESP_OK, esp_vfs_register_fs(\"/dev/test_usj\", usj_vfs, 0, NULL));\n    /* open in blocking mode */\n    const int usj_fd = open(\"/dev/test_usj/0\", 0);\n    TEST_ASSERT(usj_fd != -1);\n    *in_fd = usj_fd;\n    *out_fd = usj_fd;\n}\n\nstatic void test_usj_uninstall(const int fd)\n{\n    /* close the stream */\n    const int ret = close(fd);\n    TEST_ASSERT(ret != -1);\n\n    /* unregister the vfs */\n    TEST_ASSERT_EQUAL(ESP_OK, esp_vfs_unregister(\"/dev/test_usj\"));\n\n    /* uninstall the driver */\n    TEST_ASSERT_EQUAL(ESP_OK, usb_serial_jtag_driver_uninstall());\n}\n\nstatic void test_esp_cli_teardown(SemaphoreHandle_t *start_sem, SemaphoreHandle_t *done_sem,\n                                  esp_linenoise_handle_t *linenoise_hdl, esp_cli_handle_t *cli_hdl)\n{\n    /* destroy the instance of esp_cli */\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_destroy(*cli_hdl));\n\n    /* delete the linenoise instance */\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_delete_instance(*linenoise_hdl));\n\n    /* cleanup semaphores */\n    vSemaphoreDelete(*start_sem);\n    vSemaphoreDelete(*done_sem);\n\n    s_on_stop_nb_of_calls = 0;\n    s_on_exit_nb_of_calls = 0;\n    s_on_enter_nb_of_calls = 0;\n    s_pre_executor_nb_of_calls = 0;\n    s_post_executor_nb_of_calls = 0;\n}\n\nstatic void test_esp_cli_setup(SemaphoreHandle_t *start_sem, SemaphoreHandle_t *done_sem, int in_fd, int out_fd,\n                               esp_linenoise_handle_t *linenoise_hdl, esp_cli_handle_t *cli_hdl)\n{\n    /* create semaphores */\n    *start_sem = xSemaphoreCreateBinary();\n    TEST_ASSERT_NOT_NULL(start_sem);\n    *done_sem = xSemaphoreCreateBinary();\n    TEST_ASSERT_NOT_NULL(done_sem);\n\n    /* ensure both semaphores are in the \"taken/empty\" state:\n    taking with 0 timeout guarantees they are empty afterwards\n    regardless of the create semantics on this FreeRTOS build. */\n    xSemaphoreTake(*start_sem, 0);\n    xSemaphoreTake(*done_sem, 0);\n\n    esp_linenoise_config_t linenoise_config;\n    esp_linenoise_get_instance_config_default(&linenoise_config);\n    linenoise_config.in_fd = in_fd;\n    linenoise_config.out_fd = out_fd;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_create_instance(&linenoise_config, linenoise_hdl));\n    TEST_ASSERT_NOT_NULL(*linenoise_hdl);\n\n    esp_cli_config_t cli_config = {\n        .linenoise_handle = *linenoise_hdl,\n        .command_set_handle = NULL,\n        .max_cmd_line_size = 256,\n        .history_save_path = NULL,\n        .on_enter = { .func = test_on_enter, .ctx = NULL },\n        .pre_executor = { .func = test_pre_executor, .ctx = NULL },\n        .post_executor = { .func = test_post_executor, .ctx = NULL },\n        .on_stop = { .func = test_on_stop, .ctx = NULL },\n        .on_exit = { .func = test_on_exit, .ctx = NULL }\n    };\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_create(&cli_config, cli_hdl));\n    TEST_ASSERT_NOT_NULL(*cli_hdl);\n\n    s_on_stop_nb_of_calls = 0;\n    s_on_exit_nb_of_calls = 0;\n    s_on_enter_nb_of_calls = 0;\n    s_pre_executor_nb_of_calls = 0;\n    s_post_executor_nb_of_calls = 0;\n}\n\nTEST_CASE(\"esp_cli() loop calls callbacks and exit on call to esp_cli_stop\", \"[esp_cli]\")\n{\n    SemaphoreHandle_t start_sem, done_sem;\n    esp_linenoise_handle_t linenoise_hdl;\n    esp_cli_handle_t cli_hdl;\n    int in_fd, out_fd;\n\n    test_uart_install(&in_fd, &out_fd);\n    test_esp_cli_setup(&start_sem, &done_sem, in_fd, out_fd, &linenoise_hdl, &cli_hdl);\n\n    /* create the esp_cli instance task */\n    task_args_t args = {.start_sem = start_sem, .done_sem = done_sem, .hdl = cli_hdl};\n    BaseType_t rc = xTaskCreate(esp_cli_task, \"esp_cli_task\", 2048, &args, 5, NULL);\n    TEST_ASSERT_EQUAL(pdPASS, rc);\n\n    /* should fail before esp_cli instance is started */\n    TEST_ASSERT_NOT_EQUAL(ESP_OK, esp_cli_stop(cli_hdl));\n\n    /* start esp_cli instance */\n    TEST_ASSERT_NOT_EQUAL(ESP_OK, esp_cli_start(NULL));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_start(cli_hdl));\n\n    /* wait for the esp_cli task to signal it started */\n    TEST_ASSERT_TRUE(xSemaphoreTake(start_sem, pdMS_TO_TICKS(2000)));\n\n    /* wait for a bit so esp_cli() has time to loop back into esp_linenoise_get_line */\n    vTaskDelay(pdMS_TO_TICKS(500));\n\n    /* stop esp_cli and wait for task to finish (emulate pthread_join) */\n    TEST_ASSERT_NOT_EQUAL(ESP_OK, esp_cli_stop(NULL));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_stop(cli_hdl));\n\n    /* wait for the esp_cli task to signal completion */\n    TEST_ASSERT_TRUE(xSemaphoreTake(done_sem, pdMS_TO_TICKS(2000)));\n\n    /* check that all callbacks were called the right number of times */\n    TEST_ASSERT_EQUAL(1, s_on_stop_nb_of_calls);\n    TEST_ASSERT_EQUAL(1, s_on_enter_nb_of_calls);\n    TEST_ASSERT_EQUAL(1, s_on_exit_nb_of_calls);\n\n    /* make sure calling stop fails because the esp_cli instance is no longer running */\n    TEST_ASSERT_NOT_EQUAL(ESP_OK, esp_cli_stop(cli_hdl));\n\n    /* destroy the esp_cli instance */\n    TEST_ASSERT_NOT_EQUAL(ESP_OK, esp_cli_destroy(NULL));\n    test_esp_cli_teardown(&start_sem, &done_sem, &linenoise_hdl, &cli_hdl);\n\n    /* uninstall the uart driver */\n    test_uart_uninstall(in_fd);\n\n    /* make sure the cleanup of the deleted task is done to not bias\n     * the memory leak calculations */\n    vTaskDelay(pdMS_TO_TICKS(500));\n}\n\nTEST_CASE(\"create and destroy several instances of esp_cli\", \"[esp_cli]\")\n{\n    /* create semaphores */\n    SemaphoreHandle_t start_sem_a, start_sem_b;\n    SemaphoreHandle_t done_sem_a, done_sem_b;\n    esp_cli_handle_t cli_hdl_a, cli_hdl_b;\n    esp_linenoise_handle_t linenoise_hdl_a, linenoise_hdl_b;\n    int in_fd_uart, in_fd_usj, out_fd_uart, out_fd_usj;\n\n    /* install uart and usb serial jtag drivers */\n    test_uart_install(&in_fd_uart, &out_fd_uart);\n    test_usj_install(&in_fd_usj, &out_fd_usj);\n\n    /*  create 2 instances of esp_cli*/\n    test_esp_cli_setup(&start_sem_a, &done_sem_a, in_fd_uart, out_fd_uart, &linenoise_hdl_a, &cli_hdl_a);\n    test_esp_cli_setup(&start_sem_b, &done_sem_b, in_fd_usj, out_fd_usj, &linenoise_hdl_b, &cli_hdl_b);\n\n    /* create the esp_cli instance task A */\n    task_args_t args_a = {.start_sem = start_sem_a, .done_sem = done_sem_a, .hdl = cli_hdl_a};\n    BaseType_t rc = xTaskCreate(esp_cli_task, \"esp_cli_task_a\", 4096, &args_a, 5, NULL);\n    TEST_ASSERT_EQUAL(pdPASS, rc);\n\n    /* create the esp_cli instance task B */\n    task_args_t args_b = {.start_sem = start_sem_b, .done_sem = done_sem_b, .hdl = cli_hdl_b};\n    rc = xTaskCreate(esp_cli_task, \"esp_cli_task_b\", 4096, &args_b, 5, NULL);\n    TEST_ASSERT_EQUAL(pdPASS, rc);\n\n    /* start esp_cli instance */\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_start(cli_hdl_a));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_start(cli_hdl_b));\n    vTaskDelay(pdMS_TO_TICKS(500));\n\n    /* wait for the esp_cli instance tasks to signal it started */\n    TEST_ASSERT_TRUE(xSemaphoreTake(start_sem_a, pdMS_TO_TICKS(2000)));\n    TEST_ASSERT_TRUE(xSemaphoreTake(start_sem_b, pdMS_TO_TICKS(2000)));\n\n    /* terminate instance A */\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_stop(cli_hdl_a));\n\n    /* wait for the esp_cli instance task to signal completion */\n    TEST_ASSERT_TRUE(xSemaphoreTake(done_sem_a, pdMS_TO_TICKS(2000)));\n\n    /* terminate instance B */\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_stop(cli_hdl_b));\n\n    /* wait for the esp_cli instance task to signal completion */\n    TEST_ASSERT_TRUE(xSemaphoreTake(done_sem_b, pdMS_TO_TICKS(2000)));\n\n    test_esp_cli_teardown(&start_sem_a, &done_sem_a, &linenoise_hdl_a, &cli_hdl_a);\n    test_esp_cli_teardown(&start_sem_b, &done_sem_b, &linenoise_hdl_b, &cli_hdl_b);\n\n    test_uart_uninstall(in_fd_uart);\n    test_usj_uninstall(in_fd_usj);\n\n    /* make sure the cleanup of the deleted task is done to not bias\n     * the memory leak calculations */\n    vTaskDelay(pdMS_TO_TICKS(500));\n}\n\nTEST_CASE(\"create more esp_linenoise instances that possible based on CONFIG_ESP_LINENOISE_MAX_INSTANCE_NB\", \"[esp_cli]\")\n{\n    esp_linenoise_config_t linenoise_config;\n    esp_linenoise_get_instance_config_default(&linenoise_config);\n\n    const size_t hdl_array_size = CONFIG_ESP_LINENOISE_MAX_INSTANCE_NB + 1;\n    esp_linenoise_handle_t hdl_array[hdl_array_size];\n    memset(hdl_array, 0x00, sizeof(hdl_array));\n\n    /* try to create more instances than allowed */\n    for (size_t i = 0; i < hdl_array_size; i++) {\n        if (i < CONFIG_ESP_LINENOISE_MAX_INSTANCE_NB) {\n            /* we don't exceed the max number of instance yet, success expected */\n            TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_create_instance(&linenoise_config, &hdl_array[i]));\n            TEST_ASSERT_NOT_NULL(hdl_array[i]);\n        } else {\n            /* we exceed the max number of instance, failure expected */\n            TEST_ASSERT_NOT_EQUAL(ESP_OK, esp_linenoise_create_instance(&linenoise_config, &hdl_array[i]));\n            TEST_ASSERT_NULL(hdl_array[i]);\n        }\n    }\n\n    /* free the instances that were successfully created */\\\n    for (size_t i = 0; i < hdl_array_size; i++) {\n        if (hdl_array[i] != NULL) {\n            TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_delete_instance(hdl_array[i]));\n            hdl_array[i] = NULL;\n        }\n    }\n\n    /* try to create an instance again and deleted */\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_create_instance(&linenoise_config, &hdl_array[0]));\n    TEST_ASSERT_NOT_NULL(hdl_array[0]);\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_delete_instance(hdl_array[0]));\n}\n"
  },
  {
    "path": "esp_cli/test_apps/main/test_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"unity.h\"\n#include \"unity_test_runner.h\"\n#include \"esp_heap_caps.h\"\n#include \"unity_test_utils_memory.h\"\n\nvoid setUp(void)\n{\n    unity_utils_record_free_mem();\n}\n\nvoid tearDown(void)\n{\n    /* the threshold is necessary because on esp_linenoise instance\n     * creation, a bunch of heap memory is being used to initialize (e.g.,\n     * eventfd and vfs internals) */\n    unity_utils_evaluate_leaks_direct(500);\n}\n\nvoid app_main(void)\n{\n    printf(\"Running esp_cli component tests\\n\");\n    unity_run_menu();\n}\n"
  },
  {
    "path": "esp_cli/test_apps/pytest_esp_cli.py",
    "content": "import pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.utils import idf_parametrize\nimport glob\nfrom pathlib import Path\n\n\n@pytest.mark.generic\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that did not build\"\n)\n@pytest.mark.parametrize('target', ['esp32s3'], indirect=['target'])\ndef test_esp_cli(dut) -> None:\n    dut.run_all_single_board_cases()\n"
  },
  {
    "path": "esp_cli/test_apps/sdkconfig.defaults",
    "content": "CONFIG_ESP_LINENOISE_MAX_INSTANCE_NB=2\nCONFIG_ESP_TASK_WDT_EN=n\nCONFIG_ESP_CLI_HAS_QUIT_CMD=y\nCONFIG_VFS_SUPPORT_IO=y"
  },
  {
    "path": "esp_cli_commands/.build-test-rules.yml",
    "content": "esp_cli_commands/test_apps:\n  enable:\n    - if: IDF_TARGET in [\"esp32\", \"linux\"]\n  disable:\n    - if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR < 3\n\nesp_cli_commands/examples/command_set:\n  enable:\n    - if: IDF_TARGET == \"linux\"\n  disable:\n    - if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR < 3\n\nesp_cli_commands/examples/command_with_arg:\n  enable:\n    - if: IDF_TARGET == \"linux\"\n  disable:\n    - if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR < 3\n\nesp_cli_commands/examples/dynamic_registration:\n  enable:\n    - if: IDF_TARGET == \"linux\"\n  disable:\n    - if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR < 3\n\nesp_cli_commands/examples/integration_with_argtable:\n  enable:\n    - if: IDF_TARGET == \"linux\"\n  disable:\n    - if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR < 3\n\nesp_cli_commands/examples/static_registration:\n  enable:\n    - if: IDF_TARGET == \"linux\"\n  disable:\n    - if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR < 3\n"
  },
  {
    "path": "esp_cli_commands/CMakeLists.txt",
    "content": "idf_build_get_property(idf_target IDF_TARGET)\n\nset(srcs \"src/esp_cli_commands.c\"\n         \"src/esp_cli_dynamic_commands.c\"\n         \"src/esp_cli_commands_helpers.c\")\n\nidf_component_register(\n    SRCS ${srcs}\n    INCLUDE_DIRS include\n    PRIV_INCLUDE_DIRS private_include\n    LDFRAGMENTS linker.lf\n    WHOLE_ARCHIVE)\n\nif(${idf_target} STREQUAL \"linux\")\n    # Add custom ld file \n    target_link_options(${COMPONENT_TARGET} INTERFACE \"-Wl,-T,${CMAKE_CURRENT_SOURCE_DIR}/linux/esp_cli_commands.ld\")\nendif()\n"
  },
  {
    "path": "esp_cli_commands/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright Espressif Systems\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "esp_cli_commands/README.md",
    "content": "# ESP Commands\n\nThe `esp_cli_commands` component provides a flexible command registration and execution framework for ESP-IDF applications.  \nIt allows applications to define console-like commands with metadata (help text, hints, glossary entries) and register them dynamically or statically.\n\n---\n\n## Features\n\n- Define commands with:\n  - Command name\n  - Group categorization\n  - Help text\n  - Optional hints and glossary callbacks\n- Register commands at runtime or at compile-time (via section placement macros).\n- Execute commands from command line strings.\n- Provide command completion, hints, and glossary callback registration mechanism.\n- Create and manage subsets of commands (command sets).\n- Customizable configuration for command parsing and hint display.\n\n---\n\n## Configuration\n\nBy default, the component is initialized with a default configuration. It is however possible for the user to update this configuration with the call of the following API:\n\n```c\nesp_cli_commands_config_t config = {\n    .heap_caps_used = <user specific value>,\n    .max_cmdline_length = <user specific value>,\n    .max_cmdline_args = <user specific value>,\n    .hint_color = <user specific value>,\n    .hint_bold = <user specific value>\n};\nesp_cli_commands_update_config(&config);\n```\n\n- `write_func`: The custom write function used by esp_cli_commands to output data (default to posix write is not specified)\n- `max_cmdline_length`: Maximum command line buffer length (bytes).\n- `max_cmdline_args`: Maximum number of arguments parsed.\n- `hint_color`: ANSI color code used for hints.\n- `hint_bold`: Whether hints are displayed in bold.\n\n## Usage Examples\n\nFor real-world usage and demonstration, see the following example projects in this repository:\n\n- [hello_command_static](examples/hello_command_static): Static registration and API usage\n- [math_op_static](examples/math_op_static): Static registration, argument parsing, error handling\n- [debug_and_unregister_dynamic](examples/debug_and_unregister_dynamic): Dynamic registration and command lifecycle\n- [command_set_example](examples/command_set_example): Command set creation, filtering, and concatenation\n\nYou can find these in the `esp_cli_commands/examples/` directory. Each example contains a README and complete source code. These examples are the recommended starting point for learning how to use this component in your own project.\n\n---\n\n## API Reference\n\n- **Configuration**: `esp_cli_commands_update_config()`\n- **Registration**: `esp_cli_commands_register_cmd()`, `esp_cli_commands_unregister_cmd()`\n- **Execution**: `esp_cli_commands_execute()`, `esp_cli_commands_find_command()`\n- **Completion & Help APIs**: `esp_cli_commands_get_completion()`, `esp_cli_commands_get_hint()`, `esp_cli_commands_get_glossary()`\n- **Command Sets**: `esp_cli_commands_create_cmd_set()`, `esp_cli_commands_concat_cmd_set()`, `esp_cli_commands_destroy_cmd_set()`\n\n---\n"
  },
  {
    "path": "esp_cli_commands/examples/command_set/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.22)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(command_set)\n"
  },
  {
    "path": "esp_cli_commands/examples/command_set/README.md",
    "content": "# Command Set Example\n\nThis example demonstrates the use of command sets in esp_cli_commands:\n\n- Two commands are created, each belonging to a different group.\n- Two command sets are created, one for each group.\n- Each command is executed with each set to test filtering.\n- The sets are concatenated and both commands are executed with the combined set.\n- All sets and commands are cleaned up at the end.\n\n## Files\n- main/command_set_main.c: Main example source code\n- main/CMakeLists.txt: Build configuration\n- main/idf_component.yml: ESP-IDF component manifest\n\n## Usage\nBuild and flash as a standard ESP-IDF example. Output will show which commands are executed or filtered by the command set.\n"
  },
  {
    "path": "esp_cli_commands/examples/command_set/main/CMakeLists.txt",
    "content": "# Main CMakeLists.txt for command_set example\ncmake_minimum_required(VERSION 3.22)\n\nidf_component_register(\n    SRCS \"command_set_main.c\"\n    INCLUDE_DIRS \"\" \"../../utils\"\n    REQUIRES esp_cli_commands\n)\n"
  },
  {
    "path": "esp_cli_commands/examples/command_set/main/command_set_main.c",
    "content": "/*\n * Example: Command Set Functionality Demonstration\n *\n * This example creates two commands, each belonging to a different group.\n * It demonstrates the use of command sets for filtering and executing commands.\n *\n * Steps:\n * 1. Create two commands (cmd_a, cmd_b) in groups (group_a, group_b).\n * 2. Create two command sets, each for one group.\n * 3. Execute each command with each command set (4 cases).\n * 4. Concatenate the sets and execute both commands with the combined set.\n * 5. Clean up all sets and commands.\n */\n#include <stdio.h>\n#include <string.h>\n#include \"esp_cli_commands.h\"\n#include \"command_utils.h\"\n\nstatic int cmd_a_handler(void *context, esp_cli_commands_exec_arg_t *cmd_arg, int argc, char **argv)\n{\n    (void)context; (void)argc; (void)argv;\n    const char *msg = \"cmd_a executed\\n\";\n    const size_t msg_len = sizeof(msg) - 1;\n    const int nwrite = cmd_arg->write_func(cmd_arg->out_fd, msg, msg_len);\n    return nwrite == msg_len ? 0 : -1;\n}\n\nstatic int cmd_b_handler(void *context, esp_cli_commands_exec_arg_t *cmd_arg, int argc, char **argv)\n{\n    (void)context; (void)argc; (void)argv;\n    const char *msg = \"cmd_b executed\\n\";\n    const size_t msg_len = sizeof(msg) - 1;\n    const int nwrite = cmd_arg->write_func(cmd_arg->out_fd, msg, msg_len);\n    return nwrite == msg_len ? 0 : -1;\n}\n\nvoid app_main(void)\n{\n    printf(\"esp_cli_commands command_set example started.\\n\");\n\n    esp_cli_commands_exec_arg_t cmd_args = {\n        .out_fd = STDOUT_FILENO,\n        .write_func = write,\n        .dynamic_ctx = NULL\n    };\n\n    // Define two commands\n    esp_cli_command_t cmd_a = {\n        .name = \"cmd_a\",\n        .group = \"group_a\",\n        .help = \"Command A\",\n        .func = cmd_a_handler,\n        .func_ctx = NULL,\n        .hint_cb = NULL,\n        .glossary_cb = NULL\n    };\n    esp_cli_command_t cmd_b = {\n        .name = \"cmd_b\",\n        .group = \"group_b\",\n        .help = \"Command B\",\n        .func = cmd_b_handler,\n        .func_ctx = NULL,\n        .hint_cb = NULL,\n        .glossary_cb = NULL\n    };\n\n    ESP_ERROR_CHECK(esp_cli_commands_register_cmd(&cmd_a));\n    ESP_ERROR_CHECK(esp_cli_commands_register_cmd(&cmd_b));\n\n    // create command sets. One with command name, another with group name\n    const char *cmd_set_a[] = { \"cmd_a\" };\n    const char *cmd_set_b[] = { \"group_b\" };\n    esp_cli_command_set_handle_t set_a = ESP_CLI_COMMANDS_CREATE_CMD_SET(cmd_set_a, ESP_CLI_COMMAND_FIELD_ACCESSOR(name));\n    esp_cli_command_set_handle_t set_b = ESP_CLI_COMMANDS_CREATE_CMD_SET(cmd_set_b, ESP_CLI_COMMAND_FIELD_ACCESSOR(group));\n\n    // Test all combinations\n    int ret = -1;\n    printf(\"-- Executing cmd_a with set_a (should succeed) --\\n\");\n    ESP_ERROR_CHECK(esp_cli_commands_execute(\"cmd_a\", &ret, set_a, &cmd_args));\n\n    printf(\"-- Executing cmd_b with set_b (should succeed) --\\n\");\n    ESP_ERROR_CHECK(esp_cli_commands_execute(\"cmd_b\", &ret, set_b, &cmd_args));\n\n    printf(\"-- Executing cmd_a with set_b (should fail) --\\n\");\n    esp_err_t ret_val = esp_cli_commands_execute(\"cmd_a\", &ret, set_b, &cmd_args);\n    if (ret_val != ESP_OK) {\n        printf(\"Expected failure: cmd_a not in set_b\\n\");\n    }\n\n    printf(\"-- Executing cmd_b with set_a (should fail) --\\n\");\n    ret_val = esp_cli_commands_execute(\"cmd_b\", &ret, set_a, &cmd_args);\n    if (ret_val != ESP_OK) {\n        printf(\"Expected failure: cmd_b not in set_a\\n\");\n    }\n\n    // Concatenate sets\n    esp_cli_command_set_handle_t set_concat = esp_cli_commands_concat_cmd_set(set_a, set_b);\n    printf(\"-- Executing cmd_a with concatenated set (should succeed) --\\n\");\n    ESP_ERROR_CHECK(esp_cli_commands_execute(\"cmd_a\", &ret, set_concat, &cmd_args));\n    printf(\"-- Executing cmd_b with concatenated set (should succeed) --\\n\");\n    ESP_ERROR_CHECK(esp_cli_commands_execute(\"cmd_b\", &ret, set_concat, &cmd_args));\n\n    // Cleanup\n    esp_cli_commands_destroy_cmd_set(&set_concat);\n    ESP_ERROR_CHECK(esp_cli_commands_unregister_cmd(\"cmd_a\"));\n    ESP_ERROR_CHECK(esp_cli_commands_unregister_cmd(\"cmd_b\"));\n\n    printf(\"end of example\\n\");\n}"
  },
  {
    "path": "esp_cli_commands/examples/command_set/main/idf_component.yml",
    "content": "dependencies:\n  espressif/esp_cli_commands: \"*\"\n"
  },
  {
    "path": "esp_cli_commands/examples/command_set/pytest_command_set.py",
    "content": "# SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.utils import idf_parametrize\nimport glob\nfrom pathlib import Path\n\n\n@pytest.mark.host_test\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that not build\"\n)\n@idf_parametrize('target', ['linux'], indirect=['target'])\ndef test_command_set(dut: Dut) -> None:\n    dut.expect(\"end of example\", timeout=10)\n"
  },
  {
    "path": "esp_cli_commands/examples/command_with_arg/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.22)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(command_with_arg)\n"
  },
  {
    "path": "esp_cli_commands/examples/command_with_arg/README.md",
    "content": "# command_with_arg\n\nThis example demonstrates static registration of a CLI command (`math_op`) that performs basic math operations (add, sub, mul, div) on two arguments, with error handling for invalid input and division by zero.\n"
  },
  {
    "path": "esp_cli_commands/examples/command_with_arg/main/CMakeLists.txt",
    "content": "idf_component_register(\n    SRCS \"command_with_arg_main.c\"\n    INCLUDE_DIRS \".\" \"../../utils\"\n    REQUIRES esp_cli_commands\n)\n"
  },
  {
    "path": "esp_cli_commands/examples/command_with_arg/main/command_with_arg_main.c",
    "content": "#include <stdio.h>\n#include <string.h>\n#include \"esp_cli_commands.h\"\n#include \"command_utils.h\"\n\n// Handler function signature must match: int (*)(void *, esp_cli_commands_exec_arg_t *, int, char **)\nstatic int math_op_cmd_handler(void *ctx, esp_cli_commands_exec_arg_t *cmd_arg, int argc, char **argv)\n{\n    (void)ctx;\n    if (argc != 4) {\n        int color = 0;\n        bool bold = false;\n        const char *hint = esp_cli_commands_get_hint(NULL, \"math_op\", &color, &bold);\n        WRITE_FN(cmd_arg->write_func, cmd_arg->out_fd, \"Usage: math_op %s\\n\", hint ? hint : \"<add|sub|mul|div> <a> <b>\");\n        return -1;\n    }\n    const char *op = argv[1];\n    int a = atoi(argv[2]);\n    int b = atoi(argv[3]);\n    int result = 0;\n    WRITE_FN(cmd_arg->write_func, cmd_arg->out_fd, \"Performing operation: %s %d %d\\n\", op, a, b);\n    if (strcmp(op, \"add\") == 0) {\n        result = a + b;\n    } else if (strcmp(op, \"sub\") == 0) {\n        result = a - b;\n    } else if (strcmp(op, \"mul\") == 0) {\n        result = a * b;\n    } else if (strcmp(op, \"div\") == 0) {\n        if (b == 0) {\n            WRITE_FN(cmd_arg->write_func, cmd_arg->out_fd, \"Error: Division by zero\\n\");\n            return -2;\n        }\n        result = a / b;\n    } else {\n        WRITE_FN(cmd_arg->write_func, cmd_arg->out_fd, \"Unknown operation: %s\\n\", op);\n        return -3;\n    }\n    WRITE_FN(cmd_arg->write_func, cmd_arg->out_fd, \"Result: %d\\n\", result);\n    return 0;\n}\n\n// Hint callback signature: const char *(*)(void *)\nstatic const char *math_op_cmd_hint_cb(void *ctx)\n{\n    (void)ctx;\n    return \"<add|sub|mul|div> <a> <b>\";\n}\n\n// Glossary callback signature: const char *(*)(void *)\nstatic const char *math_op_cmd_glossary_cb(void *ctx)\n{\n    (void)ctx;\n    return \"Performs a math operation (add, sub, mul, div) on two integers.\";\n}\n\n// Static registration of the math_op command with all fields\nESP_CLI_COMMAND_REGISTER(\n    math_op,                // Command name\n    example,                // Command group\n    \"Performs math operation on two integers\", // Help string\n    math_op_cmd_handler,    // Handler function\n    NULL,                   // Context pointer\n    math_op_cmd_hint_cb,    // Hint callback\n    math_op_cmd_glossary_cb // Glossary callback\n);\n\nvoid app_main(void)\n{\n    printf(\"esp_cli_commands command_with_arg example started.\\n\");\n\n    esp_cli_commands_exec_arg_t cmd_args = {\n        .out_fd = STDOUT_FILENO,\n        .write_func = write,\n        .dynamic_ctx = NULL\n    };\n\n    // Print help output for all commands\n    int ret = -1;\n    esp_err_t err = esp_cli_commands_execute(\"help\", &ret, NULL, &cmd_args);\n    if (err == ESP_OK) {\n        printf(\"'help' command executed successfully, return value: %d\\n\", ret);\n    } else {\n        printf(\"Failed to execute 'help' command, error: %d\\n\", err);\n    }\n\n    // Find the 'math_op' command by name\n    esp_cli_command_t *cmd = esp_cli_commands_find_command(NULL, \"math_op\");\n    if (cmd) {\n        printf(\"Found command: %s\\n\", cmd->name);\n    } else {\n        printf(\"Command 'math_op' not found!\\n\");\n    }\n\n    // Execute the 'math_op' command programmatically (example: add 3 5)\n    ret = -1;\n    err = esp_cli_commands_execute(\"math_op add 3 5\", &ret, NULL, &cmd_args);\n    if (err == ESP_OK) {\n        printf(\"'math_op' command executed successfully, return value: %d\\n\", ret);\n    } else {\n        printf(\"Failed to execute 'math_op' command, error: %d\\n\", err);\n    }\n\n    // Execute the 'math_op' command with wrong arguments (missing b)\n    ret = -1;\n    err = esp_cli_commands_execute(\"math_op add 3\", &ret, NULL, &cmd_args);\n    if (err == ESP_OK) {\n        printf(\"'math_op' command (wrong args) executed, return value: %d\\n\", ret);\n    } else {\n        printf(\"Failed to execute 'math_op' command (wrong args), error: %d\\n\", err);\n    }\n\n    // Get hint for the 'math_op' command\n    int color = 0;\n    bool bold = false;\n    const char *hint = esp_cli_commands_get_hint(NULL, \"math_op\", &color, &bold);\n    printf(\"Hint for 'math_op': %s (color: %d, bold: %d)\\n\", hint ? hint : \"none\", color, bold);\n\n    // Get glossary for the 'math_op' command\n    const char *glossary = esp_cli_commands_get_glossary(NULL, \"math_op\");\n    printf(\"Glossary for 'math_op': %s\\n\", glossary ? glossary : \"none\");\n\n    printf(\"end of example\\n\");\n}\n"
  },
  {
    "path": "esp_cli_commands/examples/command_with_arg/main/idf_component.yml",
    "content": "dependencies:\n  espressif/esp_cli_commands: '*'\n"
  },
  {
    "path": "esp_cli_commands/examples/command_with_arg/pytest_command_with_arg.py",
    "content": "# SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.utils import idf_parametrize\nimport glob\nfrom pathlib import Path\n\n\n@pytest.mark.host_test\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that not build\"\n)\n@idf_parametrize('target', ['linux'], indirect=['target'])\ndef test_command_with_arg(dut: Dut) -> None:\n    dut.expect(\"end of example\", timeout=10)\n"
  },
  {
    "path": "esp_cli_commands/examples/conftest.py",
    "content": "def pytest_ignore_collect(collection_path, config):\n    skip_dirs = {'utils', 'managed_components'}\n    return any(part in skip_dirs for part in collection_path.parts)"
  },
  {
    "path": "esp_cli_commands/examples/dynamic_registration/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.22)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(dynamic_registration)\n"
  },
  {
    "path": "esp_cli_commands/examples/dynamic_registration/README.md",
    "content": "# dynamic_registration\n\nThis example demonstrates dynamic registration of a `debug` command and an `unregister` command at runtime. The `unregister` command can remove dynamically registered commands, including itself and `debug`.\n"
  },
  {
    "path": "esp_cli_commands/examples/dynamic_registration/main/CMakeLists.txt",
    "content": "# Main CMakeLists.txt for debug_and_unregister_dynamic example\ncmake_minimum_required(VERSION 3.22)\n\nidf_component_register(\n    SRCS \"dynamic_registration_main.c\"\n    INCLUDE_DIRS \"\" \"../../utils\"\n    REQUIRES esp_cli_commands\n)\n"
  },
  {
    "path": "esp_cli_commands/examples/dynamic_registration/main/dynamic_registration_main.c",
    "content": "#include <stdio.h>\n#include <string.h>\n#include \"esp_cli_commands.h\"\n#include \"command_utils.h\"\n\nstatic int debug_cmd_handler(void *ctx, esp_cli_commands_exec_arg_t *cmd_arg, int argc, char **argv)\n{\n    (void)ctx;\n    WRITE_FN(cmd_arg->write_func, cmd_arg->out_fd, \"Debug info: CLI is running.\\n\");\n    return 0;\n}\n\nstatic const char *debug_cmd_hint_cb(void *ctx)\n{\n    (void)ctx;\n    return \"[No arguments]\";\n}\n\nstatic const char *debug_cmd_glossary_cb(void *ctx)\n{\n    (void)ctx;\n    return \"Prints debug information.\";\n}\n\n// Unregister command context\n\nstatic int unregister_cmd_handler(void *ctx, esp_cli_commands_exec_arg_t *cmd_arg, int argc, char **argv)\n{\n    (void)ctx;\n    if (argc != 2) {\n        int color = 0;\n        bool bold = false;\n        const char *hint = esp_cli_commands_get_hint(NULL, \"unregister\", &color, &bold);\n        WRITE_FN(cmd_arg->write_func, cmd_arg->out_fd, \"Usage: unregister <command> %s\\n\", hint ? hint : \"<command>\");\n        return -1;\n    }\n    const char *cmd_name = argv[1];\n    esp_err_t err = esp_cli_commands_unregister_cmd(cmd_name);\n    if (err == ESP_OK) {\n        WRITE_FN(cmd_arg->write_func, cmd_arg->out_fd, \"Command '%s' unregistered successfully.\\n\", cmd_name);\n        // If unregistering itself, print a message\n        if (strcmp(cmd_name, \"unregister\") == 0) {\n            WRITE_FN(cmd_arg->write_func, cmd_arg->out_fd, \"'unregister' command has removed itself.\\n\");\n        }\n    } else {\n        WRITE_FN(cmd_arg->write_func, cmd_arg->out_fd, \"Failed to unregister command '%s', error: %d\\n\", cmd_name, err);\n    }\n    return err;\n}\n\nstatic const char *unregister_cmd_hint_cb(void *ctx)\n{\n    (void)ctx;\n    return \"<command>\";\n}\n\nstatic const char *unregister_cmd_glossary_cb(void *ctx)\n{\n    (void)ctx;\n    return \"Unregisters a dynamically registered command, including itself.\";\n}\n\nvoid app_main(void)\n{\n    printf(\"esp_cli_commands dynamic_registration example started.\\n\");\n\n    esp_cli_commands_exec_arg_t cmd_args = {\n        .out_fd = STDOUT_FILENO,\n        .write_func = write,\n        .dynamic_ctx = NULL\n    };\n\n    int ret = -1;\n    esp_err_t err = ESP_FAIL;\n\n    // Dynamically register debug command\n    esp_cli_command_t debug_cmd = {\n        .name = \"debug\",\n        .group = \"example\",\n        .help = \"Prints debug information\",\n        .func = debug_cmd_handler,\n        .func_ctx = NULL,\n        .hint_cb = debug_cmd_hint_cb,\n        .glossary_cb = debug_cmd_glossary_cb\n    };\n    ESP_ERROR_CHECK(esp_cli_commands_register_cmd(&debug_cmd));\n\n    // Dynamically register unregister commandF\n    esp_cli_command_t unregister_cmd = {\n        .name = \"unregister\",\n        .group = \"example\",\n        .help = \"Unregisters a command by name\",\n        .func = unregister_cmd_handler,\n        .func_ctx = NULL,\n        .hint_cb = unregister_cmd_hint_cb,\n        .glossary_cb = unregister_cmd_glossary_cb\n    };\n    ESP_ERROR_CHECK(esp_cli_commands_register_cmd(&unregister_cmd));\n\n    // Show that debug and unregister commands are available\n    ret = -1;\n    err = esp_cli_commands_execute(\"help\", &ret, NULL, &cmd_args);\n    if (err == ESP_OK) {\n        printf(\"'help' command executed successfully after dynamic registration, return value: %d\\n\", ret);\n    } else {\n        printf(\"Failed to execute 'help' command after dynamic registration, error: %d\\n\", err);\n    }\n\n    // Execute debug command\n    ret = -1;\n    err = esp_cli_commands_execute(\"debug\", &ret, NULL, &cmd_args);\n    if (err == ESP_OK) {\n        printf(\"'debug' command executed successfully, return value: %d\\n\", ret);\n    } else {\n        printf(\"Failed to execute 'debug' command, error: %d\\n\", err);\n    }\n\n    // Unregister debug command using unregister command\n    ret = -1;\n    err = esp_cli_commands_execute(\"unregister debug\", &ret, NULL, &cmd_args);\n    if (err == ESP_OK) {\n        printf(\"'unregister debug' command executed successfully, return value: %d\\n\", ret);\n    } else {\n        printf(\"Failed to execute 'unregister debug' command, error: %d\\n\", err);\n    }\n\n    // Unregister itself\n    ret = -1;\n    err = esp_cli_commands_execute(\"unregister unregister\", &ret, NULL, &cmd_args);\n    if (err == ESP_OK) {\n        printf(\"'unregister unregister' command executed successfully, return value: %d\\n\", ret);\n    } else {\n        printf(\"Failed to execute 'unregister unregister' command, error: %d\\n\", err);\n    }\n\n    // Show that debug and unregister commands are no longer registered\n    ret = -1;\n    err = esp_cli_commands_execute(\"help\", &ret, NULL, &cmd_args);\n    if (err == ESP_OK) {\n        printf(\"'help' command executed successfully after dynamic registration, return value: %d\\n\", ret);\n    } else {\n        printf(\"Failed to execute 'help' command after dynamic registration, error: %d\\n\", err);\n    }\n\n    printf(\"end of example\\n\");\n}\n"
  },
  {
    "path": "esp_cli_commands/examples/dynamic_registration/main/idf_component.yml",
    "content": "dependencies:\n  espressif/esp_cli_commands: '*'\n"
  },
  {
    "path": "esp_cli_commands/examples/dynamic_registration/pytest_dynamic_registration.py",
    "content": "# SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.utils import idf_parametrize\nimport glob\nfrom pathlib import Path\n\n\n@pytest.mark.host_test\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that not build\"\n)\n@idf_parametrize('target', ['linux'], indirect=['target'])\ndef test_dynamic_registration(dut: Dut) -> None:\n    dut.expect(\"end of example\", timeout=10)\n"
  },
  {
    "path": "esp_cli_commands/examples/integration_with_argtable/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.22)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(integration_with_argtable)\n"
  },
  {
    "path": "esp_cli_commands/examples/integration_with_argtable/README.md",
    "content": "# integration_with_argtable\n\nThis example demonstrates how to integrate argtable3 together with esp_cli_commands in order to\ngenerates hints and glossary for commands.\n"
  },
  {
    "path": "esp_cli_commands/examples/integration_with_argtable/main/CMakeLists.txt",
    "content": "idf_component_register(\n    SRCS \"integration_with_argtable_main.c\"\n    INCLUDE_DIRS \".\" \"../../utils\"\n    REQUIRES esp_cli_commands argtable3\n)\n"
  },
  {
    "path": "esp_cli_commands/examples/integration_with_argtable/main/idf_component.yml",
    "content": "dependencies:\n  espressif/esp_cli_commands: '*'\n  espressif/argtable3: '*'\n"
  },
  {
    "path": "esp_cli_commands/examples/integration_with_argtable/main/integration_with_argtable_main.c",
    "content": "#include <stdio.h>\n#include <string.h>\n#include \"esp_cli_commands.h\"\n#include \"argtable3/argtable3.h\"\n#include \"command_utils.h\"\n\nstatic struct {\n    struct arg_str *operator;\n    struct arg_int *operand_a;\n    struct arg_int *operand_b;\n    struct arg_end *end;\n} math_op_args;\n\nstatic void math_op_args_init(void)\n{\n    math_op_args.operator  = arg_str1(\"o\", \"operator\", \"<op>\", \"operation to perform (add, sub, mul, div)\");\n    math_op_args.operand_a = arg_int1(\"a\", \"operand-a\", \"<a>\", \"left side operand\");\n    math_op_args.operand_b = arg_int1(\"b\", \"operand-b\", \"<b>\", \"right side operand\");\n    math_op_args.end       = arg_end(3);\n}\n\n// Handler function signature must match: int (*)(void *, esp_cli_commands_exec_arg_t *, int, char **)\nstatic int math_op_cmd_handler(void *ctx, esp_cli_commands_exec_arg_t *cmd_arg, int argc, char **argv)\n{\n    (void)ctx;\n    if (argc != 4) {\n        int color = 0;\n        bool bold = false;\n        const char *hint = esp_cli_commands_get_hint(NULL, \"math_op\", &color, &bold);\n        WRITE_FN(cmd_arg->write_func, cmd_arg->out_fd, \"Usage: math_op %s\\n\", hint ? hint : \"<add|sub|mul|div> <a> <b>\");\n        return -1;\n    }\n    const char *op = argv[1];\n    int a = atoi(argv[2]);\n    int b = atoi(argv[3]);\n    int result = 0;\n    WRITE_FN(cmd_arg->write_func, cmd_arg->out_fd, \"Performing operation: %s %d %d\\n\", op, a, b);\n    if (strcmp(op, \"add\") == 0) {\n        result = a + b;\n    } else if (strcmp(op, \"sub\") == 0) {\n        result = a - b;\n    } else if (strcmp(op, \"mul\") == 0) {\n        result = a * b;\n    } else if (strcmp(op, \"div\") == 0) {\n        if (b == 0) {\n            WRITE_FN(cmd_arg->write_func, cmd_arg->out_fd, \"Error: Division by zero\\n\");\n            return -2;\n        }\n        result = a / b;\n    } else {\n        WRITE_FN(cmd_arg->write_func, cmd_arg->out_fd, \"Unknown operation: %s\\n\", op);\n        return -3;\n    }\n    WRITE_FN(cmd_arg->write_func, cmd_arg->out_fd, \"Result: %d\\n\", result);\n    return 0;\n}\n\n// Hint callback signature: const char *(*)(void *)\nstatic const char *math_op_cmd_hint_cb(void *ctx)\n{\n    (void)ctx;\n\n    arg_dstr_t ds = arg_dstr_create();\n    arg_print_syntax_ds(ds, (void *)&math_op_args, NULL);\n    const char *hint_str = strdup(arg_dstr_cstr(ds));\n    arg_dstr_destroy(ds);\n\n    return hint_str;\n}\n\n// Glossary callback signature: const char *(*)(void *)\nstatic const char *math_op_cmd_glossary_cb(void *ctx)\n{\n    (void)ctx;\n\n    arg_dstr_t ds = arg_dstr_create();\n    arg_print_glossary_ds(ds, (void *)&math_op_args, NULL);\n    const char *glossary_str = strdup(arg_dstr_cstr(ds));\n    arg_dstr_destroy(ds);\n\n    return glossary_str;\n}\n\n// Static registration of the math_op command with all fields\nESP_CLI_COMMAND_REGISTER(\n    math_op,                // Command name\n    example,                // Command group\n    \"Performs math operation on two integers\", // Help string\n    math_op_cmd_handler,    // Handler function\n    NULL,                   // Context pointer\n    math_op_cmd_hint_cb,    // Hint callback\n    math_op_cmd_glossary_cb // Glossary callback\n);\n\nvoid app_main(void)\n{\n    printf(\"esp_cli_commands integration_with_argtable example started.\\n\");\n\n    esp_cli_commands_exec_arg_t cmd_args = {\n        .out_fd = STDOUT_FILENO,\n        .write_func = write,\n        .dynamic_ctx = NULL\n    };\n\n    math_op_args_init();\n\n    // Get hint for the 'math_op' command\n    int color = 0;\n    bool bold = false;\n    const char *hint = esp_cli_commands_get_hint(NULL, \"math_op\", &color, &bold);\n    printf(\"Hint for 'math_op': %s (color: %d, bold: %d)\\n\", hint ? hint : \"none\", color, bold);\n\n    // Get glossary for the 'math_op' command\n    const char *glossary = esp_cli_commands_get_glossary(NULL, \"math_op\");\n    printf(\"Glossary for 'math_op': %s\\n\", glossary ? glossary : \"none\");\n\n    int ret = -1;\n    esp_err_t err = esp_cli_commands_execute(\"math_op add 3 5\", &ret, NULL, &cmd_args);\n    if (err == ESP_OK) {\n        printf(\"'math_op' command executed successfully, return value: %d\\n\", ret);\n    } else {\n        printf(\"Failed to execute 'math_op' command, error: %d\\n\", err);\n    }\n\n    printf(\"end of example\\n\");\n}\n"
  },
  {
    "path": "esp_cli_commands/examples/integration_with_argtable/pytest_integration_with_argtable.py",
    "content": "# SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.utils import idf_parametrize\nimport glob\nfrom pathlib import Path\n\n\n@pytest.mark.host_test\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that not build\"\n)\n@idf_parametrize('target', ['linux'], indirect=['target'])\ndef test_integration_with_argtable(dut: Dut) -> None:\n    dut.expect(\"end of example\", timeout=10)\n"
  },
  {
    "path": "esp_cli_commands/examples/static_registration/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.22)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(static_registration)\n"
  },
  {
    "path": "esp_cli_commands/examples/static_registration/README.md",
    "content": "# static_registration\n\nThis example demonstrates static registration of a simple CLI command (`hello`) using esp_cli_commands..\n"
  },
  {
    "path": "esp_cli_commands/examples/static_registration/main/CMakeLists.txt",
    "content": "idf_component_register(\n    SRCS \"static_registration_main.c\"\n    INCLUDE_DIRS \"..\" \"../../utils\"\n    REQUIRES esp_cli_commands\n)\n"
  },
  {
    "path": "esp_cli_commands/examples/static_registration/main/idf_component.yml",
    "content": "dependencies:\n  espressif/esp_cli_commands: '*'\n"
  },
  {
    "path": "esp_cli_commands/examples/static_registration/main/static_registration_main.c",
    "content": "\n#include <stdio.h>\n#include \"esp_cli_commands.h\"\n#include \"command_utils.h\"\n\n\n// Context for the command (must be known at compile time for static registration)\nstatic int hello_cmd_ctx = 0;\n\n// Handler function signature must match: int (*)(void *, esp_cli_commands_exec_arg_t *, int, char **)\nstatic int hello_cmd_handler(void *ctx, esp_cli_commands_exec_arg_t *cmd_arg, int argc, char **argv)\n{\n    (void)ctx;\n    (void)argc;\n    (void)argv;\n    WRITE_FN(cmd_arg->write_func, cmd_arg->out_fd, \"Hello! This is the esp_cli_commands static example.\\n\");\n    return 0;\n}\n\n// Hint callback signature: const char *(*)(void *)\nstatic const char *hello_cmd_hint_cb(void *ctx)\n{\n    (void)ctx;\n    return \"[No arguments]\";\n}\n\n// Glossary callback signature: const char *(*)(void *)\nstatic const char *hello_cmd_glossary_cb(void *ctx)\n{\n    (void)ctx;\n    return \"This command prints a hello message for demonstration purposes.\";\n}\n\n// Static registration of the hello command with all fields\nESP_CLI_COMMAND_REGISTER(\n    hello,                  // Command name\n    example,                // Command group\n    \"Prints a hello message\", // Help string\n    hello_cmd_handler,      // Handler function\n    &hello_cmd_ctx,         // Context pointer (must be address of static object) (optional argument)\n    hello_cmd_hint_cb,      // Hint callback (optional argument)\n    hello_cmd_glossary_cb   // Glossary callback (optional argument)\n);\n\nvoid app_main(void)\n{\n    printf(\"esp_cli_commands static_registration example started.\\n\");\n\n    esp_cli_commands_exec_arg_t cmd_args = {\n        .out_fd = STDOUT_FILENO,\n        .write_func = write,\n        .dynamic_ctx = NULL\n    };\n\n    // Print help output for all commands\n    int ret = -1;\n    esp_err_t err = esp_cli_commands_execute(\"help\", &ret, NULL, &cmd_args);\n    if (err == ESP_OK) {\n        printf(\"'help' command executed successfully, return value: %d\\n\", ret);\n    } else {\n        printf(\"Failed to execute 'help' command, error: %d\\n\", err);\n    }\n\n    // Find the 'hello' command by name\n    esp_cli_command_t *cmd = esp_cli_commands_find_command(NULL, \"hello\");\n    if (cmd) {\n        printf(\"Found command: %s\\n\", cmd->name);\n    } else {\n        printf(\"Command 'hello' not found!\\n\");\n    }\n\n    // Execute the 'hello' command programmatically\n    ret = -1;\n    err = esp_cli_commands_execute(\"hello\", &ret, NULL, &cmd_args);\n    if (err == ESP_OK) {\n        printf(\"'hello' command executed successfully, return value: %d\\n\", ret);\n    } else {\n        printf(\"Failed to execute 'hello' command, error: %d\\n\", err);\n    }\n\n    // Get hint for the 'hello' command\n    int color = 0;\n    bool bold = false;\n    const char *hint = esp_cli_commands_get_hint(NULL, \"hello\", &color, &bold);\n    printf(\"Hint for 'hello': %s (color: %d, bold: %d)\\n\", hint ? hint : \"none\", color, bold);\n\n    // Get glossary for the 'hello' command\n    const char *glossary = esp_cli_commands_get_glossary(NULL, \"hello\");\n    printf(\"Glossary for 'hello': %s\\n\", glossary ? glossary : \"none\");\n\n    printf(\"end of example\\n\");\n}\n"
  },
  {
    "path": "esp_cli_commands/examples/static_registration/pytest_static_registration.py",
    "content": "# SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.utils import idf_parametrize\nimport glob\nfrom pathlib import Path\n\n\n@pytest.mark.host_test\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that not build\"\n)\n@idf_parametrize('target', ['linux'], indirect=['target'])\ndef test_static_registration(dut: Dut) -> None:\n    dut.expect(\"end of example\", timeout=10)\n"
  },
  {
    "path": "esp_cli_commands/examples/utils/command_utils.h",
    "content": "\n#pragma once\n\n#include \"unistd.h\"\n\n#define WRITE_FN(fn, fd, fmt, ...) do {                           \\\n    char _buf[256];                                               \\\n    int _len = snprintf(_buf, sizeof(_buf), fmt, ##__VA_ARGS__);  \\\n    if (_len > 0)                                                 \\\n        fn(fd, _buf, _len);                                       \\\n} while(0)\n"
  },
  {
    "path": "esp_cli_commands/idf_component.yml",
    "content": "version: \"0.1.3\"\ndescription: \"esp_cli_commands - Command handling component\"\nurl: https://github.com/espressif/idf-extra-components/tree/master/esp_cli_commands\ndependencies:\n  idf: \">=5.3\"\nsbom:\n  manifests:\n    - path: sbom_esp_cli_commands.yml\n      dest: ."
  },
  {
    "path": "esp_cli_commands/include/esp_cli_commands.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdbool.h>\n#include \"esp_cli_commands_utils.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_err.h\"\n\n/**\n * @brief Update the component configuration\n *\n * @param config Configuration data to update\n * @return ESP_OK if successful\n *         ESP_ERR_INVALID_ARG if config pointer is NULL\n */\nesp_err_t esp_cli_commands_update_config(const esp_cli_commands_config_t *config);\n\n/**\n * @brief macro registering a command and placing it in a specific section of flash.rodata\n * @note see the linker.lf file for more information concerning the section characteristics\n */\n#define _ESP_CLI_COMMAND_REGISTER(cmd_name, cmd_group, cmd_help, cmd_func, cmd_func_ctx, cmd_hint_cb, cmd_glossary_cb) \\\n    static_assert((cmd_func) != NULL); \\\n    static const esp_cli_command_t cmd_name __attribute__((used, section(\".esp_cli_commands\" \".\" _ESP_REPL_STRINGIFY(cmd_name)), aligned(4))) = { \\\n        .name = _ESP_REPL_STRINGIFY(cmd_name), \\\n        .group = _ESP_REPL_STRINGIFY(cmd_group), \\\n        .help = cmd_help, \\\n        .func = cmd_func, \\\n        .func_ctx = cmd_func_ctx, \\\n        .hint_cb = cmd_hint_cb, \\\n        .glossary_cb = cmd_glossary_cb \\\n    };\n\n#define ESP_CLI_COMMAND_REGISTER(cmd_name, cmd_group, cmd_help, cmd_func, cmd_func_ctx, cmd_hint_cb, cmd_glossary_cb) \\\n    _ESP_CLI_COMMAND_REGISTER(cmd_name, cmd_group, cmd_help, cmd_func, cmd_func_ctx, cmd_hint_cb, cmd_glossary_cb)\n\n/**\n * @brief Register a command\n *\n * @param cmd Pointer to the command structure\n * @return ESP_OK if successful\n *         Other esp_err_t on error\n */\nesp_err_t esp_cli_commands_register_cmd(esp_cli_command_t *cmd);\n\n/**\n * @brief Unregister a command by name or group\n *\n * @param cmd_name Name or group of the command to unregister\n * @return ESP_OK if successful\n *         Other esp_err_t on error\n */\nesp_err_t esp_cli_commands_unregister_cmd(const char *cmd_name);\n\n/**\n * @brief Execute a command line\n *\n * @param cmd_line Command line string to execute\n * @param cmd_ret Return value from the command function. If -1, standard output will be used.\n * @param cmd_set Set of commands allowed to execute. If NULL, all registered commands are allowed\n * @param cmd_arg Structure containing dynamic arguments necessary for the command\n * callback to execute properly\n * @return ESP_OK on success\n *         ESP_ERR_INVALID_ARG if the command line is empty or only whitespace\n *         ESP_ERR_NOT_FOUND if command is not found in cmd_set\n *         ESP_ERR_NO_MEM if internal memory allocation fails\n */\nesp_err_t esp_cli_commands_execute(const char *cmdline, int *cmd_ret, esp_cli_command_set_handle_t cmd_set, esp_cli_commands_exec_arg_t *cmd_args);\n\n/**\n * @brief Find a command by name within a specific command set.\n *\n * This function searches a command whose name matches the provided string.\n *\n * @param cmd_set Handle to the command set to search in. Must be a valid\n * `esp_cli_command_set_handle_t` or `NULL` if the search should be performed\n * on all statically and dynamically registered commands.\n * @param name String containing the name of the command to search for.\n *\n * @return pointer to the matching command or NULL if no command is found.\n */\nesp_cli_command_t *esp_cli_commands_find_command(esp_cli_command_set_handle_t cmd_set, const char *name);\n\n/**\n * @brief Provide command completion for linenoise library\n *\n * @param cmd_set Set of commands allowed for completion. If NULL, all registered commands are used\n * @param buf Input string typed by the user\n * @param cb_ctx context passed to the completion callback\n * @param completion_cb Callback to return completed command names\n */\nvoid esp_cli_commands_get_completion(esp_cli_command_set_handle_t cmd_set, const char *buf, void *cb_ctx, esp_cli_command_get_completion_t completion_cb);\n\n/**\n * @brief Provide command hint for linenoise library\n *\n * @param cmd_set Set of commands allowed for hinting. If NULL, all registered commands are used\n * @param buf Input string typed by the user\n * @param[out] color ANSI color code for hint text\n * @param[out] bold True if hint should be displayed in bold\n * @return Persistent string containing the hint; must not be freed\n */\nconst char *esp_cli_commands_get_hint(esp_cli_command_set_handle_t cmd_set, const char *buf, int *color, bool *bold);\n\n/**\n * @brief Retrieve glossary for a command line\n *\n * @param cmd_set Set of commands allowed\n * @param buf Command line typed by the user\n * @return Persistent string containing the glossary; must not be freed\n */\nconst char *esp_cli_commands_get_glossary(esp_cli_command_set_handle_t cmd_set, const char *buf);\n\n/**\n * @brief Create a command set from an array of command names\n *\n * @param cmd_set Array of command names\n * @param cmd_set_size Number of entries in cmd_set\n * @param get_field Function to retrieve the field from esp_cli_command_t for comparison\n * @return Handle to the created command set\n */\nesp_cli_command_set_handle_t esp_cli_commands_create_cmd_set(const char **cmd_set, const size_t cmd_set_size, esp_cli_commands_get_field_t get_field);\n\n/**\n * @brief Convenience macro to create a command set\n *\n * @param cmd_set Array of command names\n * @param accessor Field accessor function\n */\n#define ESP_CLI_COMMANDS_CREATE_CMD_SET(cmd_set, accessor) \\\n    esp_cli_commands_create_cmd_set(cmd_set, sizeof(cmd_set) / sizeof((cmd_set)[0]), accessor)\n\n/**\n * @brief Concatenate two command sets\n *\n * @note If one set is NULL, the other is returned\n * @note If both are NULL, returns NULL\n * @note Duplicates are not removed\n *\n * @param cmd_set_a First command set\n * @param cmd_set_b Second command set\n * @return New command set containing all commands from both sets\n */\nesp_cli_command_set_handle_t esp_cli_commands_concat_cmd_set(esp_cli_command_set_handle_t cmd_set_a, esp_cli_command_set_handle_t cmd_set_b);\n\n/**\n * @brief Destroy a command set\n *\n * @param cmd_set Pointer to the handle of the command set to destroy\n */\nvoid esp_cli_commands_destroy_cmd_set(esp_cli_command_set_handle_t *cmd_set);\n\n/**\n * @brief Split a command line and populate argc and argv parameters\n *\n * @param line the line that has to be split into arguments\n * @param argv array of arguments created from the line\n * @param argv_size size of the argument array\n * @return size_t number of arguments found in the line and stored\n * in argv\n */\nsize_t esp_cli_commands_split_argv(char *line, char **argv, size_t argv_size);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_cli_commands/include/esp_cli_commands_utils.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdbool.h>\n#include <stdint.h>\n\n#define _ESP_REPL_STRINGIFY(x) #x\n#define ESP_REPL_STRINGIFY(x) _ESP_REPL_STRINGIFY(x)\n\n/**\n * @brief Function pointer type for writing bytes.\n *\n * @param fd File descriptor.\n * @param buf Buffer containing bytes to write.\n * @param count Number of bytes to write.\n * @return Number of bytes written, or -1 on error.\n */\ntypedef ssize_t (*esp_cli_commands_write_t)(int fd, const void *buf, size_t count);\n\n/**\n * @brief Structure containing dynamic argument necessary for the\n * command callback to execute properly.\n *\n * @note Since a command function callback can be executed from\n * a random context, the callback has to be aware of what file descriptor\n * and what write function to use in order to print data to the expected\n * destination.\n */\ntypedef struct esp_cli_commands_exec_arg {\n    int out_fd; /*!< file descriptor that the command function has to use to print data in the environment it was called from */\n    esp_cli_commands_write_t write_func; /*!< write function the command function has to use to print data in the environment it was called from */\n    void *dynamic_ctx; /*!< dynamic context passed to the command function */\n} esp_cli_commands_exec_arg_t;\n\n/**\n * @brief Console command main function type with user context\n *\n * This function type is used to implement a console command.\n *\n * @param context User-defined context passed at invocation\n * @param cmd_arg Structure containing dynamic arguments necessary for the command\n * @param argc Number of arguments\n * @param argv Array of argc entries, each pointing to a null-terminated string argument\n * @return Return code of the console command; 0 indicates success\n */\ntypedef int (*esp_cli_command_func_t)(void *context, esp_cli_commands_exec_arg_t *cmd_arg, int argc, char **argv);\n\n/**\n * @brief Callback to generate a command hint\n *\n * This function is called to retrieve a short hint for a command,\n * typically used for auto-completion or UI help.\n *\n * @param context Context registered when the command was registered\n * @return Persistent string containing the generated hint\n */\ntypedef const char *(*esp_cli_command_hint_t)(void *context);\n\n/**\n * @brief Callback to generate a command glossary entry\n *\n * This function is called to retrieve detailed description or glossary\n * information for a command.\n *\n * @param context Context registered when the command was registered\n * @return Persistent string containing the generated glossary\n */\ntypedef const char *(*esp_cli_command_glossary_t)(void *context);\n\n/**\n * @brief Structure describing a console command\n *\n * @note The `group` field allows categorizing commands into groups,\n * which can simplify filtering or listing commands.\n */\ntypedef struct esp_cli_command {\n    const char *name; /*!< Name of the command */\n    const char *group; /*!< Command group to which this command belongs */\n    const char *help; /*!< Short help text for the command */\n    esp_cli_command_func_t func; /*!< Function implementing the command */\n    void *func_ctx; /*!< User-defined context for the command function */\n    esp_cli_command_hint_t hint_cb; /*!< Callback returning the hint for the command */\n    esp_cli_command_glossary_t glossary_cb; /*!< Callback returning the glossary for the command */\n} esp_cli_command_t;\n\n/**\n * @brief Configuration parameters for esp_cli_commands_manager initialization\n */\ntypedef struct esp_cli_commands_config {\n    uint32_t heap_caps_used;            /*!< Set of heap capabilities to be used to perform internal allocations */\n    size_t max_cmdline_length;          /*!< Maximum length of the command line buffer, in bytes */\n    size_t max_cmdline_args;            /*!< Maximum number of command line arguments to parse */\n    int hint_color;                     /*!< ANSI color code used for hint text */\n    bool hint_bold;                     /*!< If true, display hint text in bold */\n} esp_cli_commands_config_t;\n\n/**\n * @brief Callback for a completed command name\n *\n * This callback is called when a command is successfully completed.\n *\n * @param cb_ctx Opaque pointer pointing at the context passed to the callback\n * @param completed_cmd_name Completed command name\n */\ntypedef void (*esp_cli_command_get_completion_t)(void *cb_ctx, const char *completed_cmd_name);\n\n/**\n * @brief Callback to retrieve a string field of esp_cli_command_t\n *\n * @param cmd Command object\n * @return Value of the requested string field\n */\ntypedef const char *(*esp_cli_commands_get_field_t)(const esp_cli_command_t *cmd);\n\n/**\n * @brief Opaque handle to a set of commands\n */\ntypedef struct esp_cli_command_sets *esp_cli_command_set_handle_t;\n\n/**\n * @brief Macro to define a forced inline accessor for a string field of esp_cli_command_t\n *\n * @param NAME Field name of the esp_cli_command_t structure\n */\n#define DEFINE_FIELD_ACCESSOR(NAME) \\\n    static inline __attribute__((always_inline)) \\\n    const char *get_##NAME(const esp_cli_command_t *cmd) { \\\n        if (!cmd) { \\\n            return NULL; \\\n        } \\\n        return cmd->NAME; \\\n    }\n\n/**\n * @brief Macro expanding to\n * static inline __attribute__((always_inline)) const char *get_name(esp_cli_command_t *cmd) {\n *     if (!cmd) {\n *         return NULL;\n *     }\n *     return cmd->name;\n * }\n */\nDEFINE_FIELD_ACCESSOR(name)\n\n/**\n * @brief Macro expanding to\n * static inline __attribute__((always_inline)) const char *get_group(esp_cli_command_t *cmd) {\n *     if (!cmd) {\n *         return NULL;\n *     }\n *     return cmd->group;\n * }\n */\nDEFINE_FIELD_ACCESSOR(group)\n\n/**\n * @brief Macro expanding to\n * static inline __attribute__((always_inline)) const char *get_help(esp_cli_command_t *cmd) {\n *     if (!cmd) {\n *         return NULL;\n *     }\n *     return cmd->help;\n * }\n */\nDEFINE_FIELD_ACCESSOR(help)\n\n/**\n * @brief Macro to create the accessor function name for a field of esp_cli_command_t\n *\n * @note Those accessor functions are defined in esp_cli_commands_internal.h\n *\n * @param NAME Field name of esp_cli_command_t\n */\n#define ESP_CLI_COMMAND_FIELD_ACCESSOR(NAME) get_##NAME\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_cli_commands/linker.lf",
    "content": "[sections:esp_cli_commands]\nentries:\n    .esp_cli_commands+\n\n[scheme:esp_cli_commands_default]\nentries:\n    esp_cli_commands -> flash_rodata\n\n[mapping:esp_cli_commands]\narchive: *\nentries:\n    * (esp_cli_commands_default);\n    esp_cli_commands -> flash_rodata KEEP() SORT(name) SURROUND(esp_cli_commands)\n"
  },
  {
    "path": "esp_cli_commands/linux/esp_cli_commands.ld",
    "content": "SECTIONS\n{\n    .esp_cli_commands :\n    {\n        PROVIDE(_esp_cli_commands_start = .);\n        KEEP(*(SORT(.esp_cli_commands*))) /* Concatenate all .esp_cli_commands */\n        PROVIDE(_esp_cli_commands_end = .);\n    }\n}\nINSERT AFTER .rodata;\n"
  },
  {
    "path": "esp_cli_commands/private_include/esp_cli_commands_internal.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include \"esp_heap_caps.h\"\n\n/**\n * @brief Component specific implementation of malloc\n *\n * @note This function uses heap_caps_malloc together\n * with the set of capabilities provided by the user in the\n * config structure. Implemented in esp_cli_commands.c\n *\n * @param malloc_size\n * @return void*\n */\nvoid *esp_cli_commands_malloc(const size_t malloc_size);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_cli_commands/private_include/esp_cli_dynamic_commands.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdio.h>\n#include <string.h>\n#include \"sys/queue.h\"\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/semphr.h\"\n#include \"esp_cli_commands.h\"\n\n/**\n * @brief Structure representing a fixed set of commands.\n *\n * This is typically used for static or predefined command lists.\n */\ntypedef struct esp_cli_command_set {\n    esp_cli_command_t **cmd_ptr_set; /*!< Array of pointers to commands. */\n    size_t cmd_set_size; /*!< Number of commands in the set. */\n} esp_cli_command_set_t;\n\n/**\n * @brief Internal structure for a dynamically registered command.\n *\n * Each dynamic command is stored as an `esp_cli_command_t` plus\n * linked list metadata for insertion/removal.\n */\ntypedef struct esp_cli_command_internal {\n    esp_cli_command_t cmd; /*!< Command instance. */\n    SLIST_ENTRY(esp_cli_command_internal) next_item; /*!< Linked list entry metadata. */\n} esp_cli_command_internal_t;\n\n/**\n * @brief Linked list head type for dynamic command storage.\n */\ntypedef SLIST_HEAD(esp_cli_command_internal_ll, esp_cli_command_internal) esp_cli_command_internal_ll_t;\n\n/**\n * @brief Iterate over a set of commands, either from a static set or dynamic list.\n *\n * This macro supports iterating over:\n * - A provided `esp_cli_command_set_t` (static set), OR\n * - The global dynamic command list if `cmd_set` is `NULL`.\n *\n * @param cmd_set Pointer to a command set (`esp_cli_command_set_t`) or `NULL` for dynamic commands.\n * @param item_cmd Iterator variable of type `esp_cli_command_t *` that will point to each command.\n *\n * @note Internally, the macro uses `_node` and `_i` as hidden variables.\n */\n#define FOR_EACH_DYNAMIC_COMMAND(cmd_set, item_cmd)                             \\\n    __attribute__((unused)) esp_cli_command_internal_t *_node =                     \\\n            ((cmd_set) == NULL ? SLIST_FIRST(esp_cli_dynamic_commands_get_list())  \\\n                                : NULL);                                        \\\n    __attribute__((unused)) size_t _i = 0;                                      \\\n    for (;                                                                      \\\n         ((cmd_set) == NULL                                                     \\\n              ? ((_node != NULL) && ((item_cmd) = &_node->cmd))                 \\\n              : (_i < (cmd_set)->cmd_set_size &&                                \\\n                 ((item_cmd) = (cmd_set)->cmd_ptr_set[_i])));                   \\\n         ((cmd_set) == NULL                                                     \\\n              ? (_node = SLIST_NEXT(_node, next_item))                          \\\n              : (void)++_i))\n\n/**\n * @brief Acquire the dynamic commands lock.\n *\n * This function must be called before modifying or iterating over\n * the dynamic command list to ensure thread safety.\n */\nvoid esp_cli_dynamic_commands_lock(void);\n\n/**\n * @brief Release the dynamic commands lock.\n *\n * Call this after operations on the dynamic command list are complete.\n */\nvoid esp_cli_dynamic_commands_unlock(void);\n\n/**\n * @brief Get the internal linked list of dynamic commands.\n *\n * @return Pointer to the dynamic command linked list head.\n *\n * @warning The returned list is internal; do not modify it directly.\n *          Use provided API functions to modify dynamic commands.\n */\nconst esp_cli_command_internal_ll_t *esp_cli_dynamic_commands_get_list(void);\n\n/**\n * @brief Add a new command to the dynamic command list.\n *\n * @param cmd Pointer to the command to add.\n * @return\n *      - `ESP_OK` on success.\n *      - Appropriate error code on failure.\n *\n * @note The function acquires the lock internally.\n */\nesp_err_t esp_cli_dynamic_commands_add(esp_cli_command_t *cmd);\n\n/**\n * @brief Replace an existing command in the dynamic command list.\n *\n * If a command with the same name exists, it will be replaced.\n *\n * @param old_cmd Pointer to the existing command to be replaced.\n * @param new_cmd Pointer to the new command data.\n * @return\n *      - `ESP_OK` on success.\n *      - Appropriate error code on failure.\n */\nesp_err_t esp_cli_dynamic_commands_replace(esp_cli_command_t *old_cmd, esp_cli_command_t *new_cmd);\n\n/**\n * @brief Remove a command from the dynamic command list.\n *\n * @param item_cmd Pointer to the command to remove.\n * @return\n *      - `ESP_OK` on success.\n *      - Appropriate error code on failure.\n */\nesp_err_t esp_cli_dynamic_commands_remove(esp_cli_command_t *item_cmd);\n\n/**\n * @brief Get the number of registered dynamic commands.\n *\n * @return The total number of dynamic commands currently registered.\n */\nsize_t esp_cli_dynamic_commands_get_number_of_cmd(void);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_cli_commands/sbom_esp_cli_commands.yml",
    "content": "name: esp_cli_commands\ndescription: Command handling component\nurl: https://github.com/espressif/idf-extra-components/tree/master/esp_cli_commands\nversion: 1.0.0\ncpe: cpe:2.3:a:espressif:esp_cli_commands:{}:*:*:*:*:*:*:*\nsupplier: 'Organization: Espressif Systems'"
  },
  {
    "path": "esp_cli_commands/src/esp_cli_commands.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include <stdbool.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <unistd.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/semphr.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_cli_commands.h\"\n#include \"esp_cli_commands_internal.h\"\n#include \"esp_cli_dynamic_commands.h\"\n#include \"esp_err.h\"\n\n/* Default foreground color */\n#define ANSI_COLOR_DEFAULT 39\n\n/* static mutex used to protect access to the static configuration */\nstatic SemaphoreHandle_t s_esp_cli_commands_mutex = NULL;\nstatic StaticSemaphore_t s_esp_cli_commands_mutex_buf;\n\n/* Pointers to the first and last command in the dedicated section.\n * See linker.lf for detailed information about the section */\nextern esp_cli_command_t _esp_cli_commands_start;\nextern esp_cli_command_t _esp_cli_commands_end;\n\ntypedef struct esp_cli_command_sets {\n    esp_cli_command_set_t static_set;\n    esp_cli_command_set_t dynamic_set;\n} esp_cli_command_sets_t;\n\n/** run-time configuration options */\nstatic esp_cli_commands_config_t s_config = {\n    .heap_caps_used = MALLOC_CAP_DEFAULT,\n    .hint_bold = false,\n    .hint_color = ANSI_COLOR_DEFAULT,\n    .max_cmdline_args = 32,\n    .max_cmdline_length = 256\n};\n\n/**\n * @brief go through all commands registered in the\n * memory section starting at _esp_cli_commands_start\n * and ending at _esp_cli_commands_end OR go through all\n * the commands listed in cmd_set if not NULL\n */\n#define FOR_EACH_STATIC_COMMAND(cmd_set, cmd)                       \\\n    for (size_t _i = 0;                                             \\\n         ((cmd_set) == NULL                                         \\\n              ? (((cmd) = &_esp_cli_commands_start + _i),               \\\n                 (&_esp_cli_commands_start + _i) < &_esp_cli_commands_end)  \\\n              : (((cmd) = (cmd_set)->cmd_ptr_set[_i]),              \\\n                 _i < (cmd_set)->cmd_set_size));                    \\\n         ++_i)\n\n/**\n * @brief Get the number of commands registered in the .esp_cli_commands section\n */\n#define ESP_CLI_COMMANDS_COUNT \\\n    (((uintptr_t)&_esp_cli_commands_end - (uintptr_t)&_esp_cli_commands_start) / sizeof(esp_cli_command_t))\n\n/**\n * @brief Lock access to the s_config static structure\n */\nstatic void esp_cli_commands_lock(void)\n{\n    if (s_esp_cli_commands_mutex == NULL) {\n        s_esp_cli_commands_mutex = xSemaphoreCreateMutexStatic(&s_esp_cli_commands_mutex_buf);\n        assert(s_esp_cli_commands_mutex != NULL);\n    }\n    xSemaphoreTake(s_esp_cli_commands_mutex, portMAX_DELAY);\n}\n\n/**\n * @brief Unlock access to the s_config static structure\n */\nstatic void esp_cli_commands_unlock(void)\n{\n    xSemaphoreGive(s_esp_cli_commands_mutex);\n}\n\n/**\n * @brief check the location of the pointer to esp_cli_command_t\n *\n * @param cmd the pointer to the command to check\n * @return true if the command was registered statically\n *         false if the command was registered dynamically\n */\nstatic inline __attribute__((always_inline)) bool command_is_static(esp_cli_command_t *cmd)\n{\n    if (cmd >= &_esp_cli_commands_start && cmd <= &_esp_cli_commands_end) {\n        return true;\n    }\n    return false;\n}\n\ntypedef bool (*walker_t)(void *walker_ctx, esp_cli_command_t *cmd);\nstatic inline __attribute__((always_inline))\nvoid go_through_commands(esp_cli_command_sets_t *cmd_sets, void *cmd_walker_ctx, walker_t cmd_walker)\n{\n    if (!cmd_walker) {\n        return;\n    }\n\n    esp_cli_command_t *cmd = NULL;\n    bool continue_walk = false;\n\n    /* cmd_sets is composed of 2 sets (static and dynamic).\n     * - If cmd_sets is NULL, go through all the statically AND dynamically registered commands.\n     * - If cmd_sets is not NULL and either the static or the dynamic set is empty, then the macros\n     * FOR_EACH_XX_COMMAND will not go through the whole list of static (resp. dynamic) commands but\n     * through the empty set, so no command will be walked.\n     */\n\n    esp_cli_command_set_t *static_set = cmd_sets ? &cmd_sets->static_set : NULL;\n    /* it is possible that the set is empty, in which case set static_set to NULL\n     * to prevent the for loop to try to access a list of commands pointer set to NULL */\n    if (static_set && !static_set->cmd_ptr_set) {\n        static_set = NULL;\n    }\n    FOR_EACH_STATIC_COMMAND(static_set, cmd) {\n        continue_walk = cmd_walker(cmd_walker_ctx, cmd);\n        if (!continue_walk) {\n            return;\n        }\n    }\n\n    esp_cli_command_set_t *dynamic_set = cmd_sets ? &cmd_sets->dynamic_set : NULL;\n    /* Note: unlike FOR_EACH_STATIC_COMMAND which uses the comma operator,\n     * FOR_EACH_DYNAMIC_COMMAND uses && short-circuit evaluation, so it is safe\n     * to pass a set with cmd_ptr_set == NULL and cmd_set_size == 0.\n     * We must NOT null out the set here, because FOR_EACH_DYNAMIC_COMMAND(NULL, ...)\n     * means \"walk ALL dynamic commands\", bypassing the set filter. */\n    esp_cli_dynamic_commands_lock();\n    FOR_EACH_DYNAMIC_COMMAND(dynamic_set, cmd) {\n        continue_walk = cmd_walker(cmd_walker_ctx, cmd);\n        if (!continue_walk) {\n            esp_cli_dynamic_commands_unlock();\n            return;\n        }\n    }\n    esp_cli_dynamic_commands_unlock();\n}\n\ntypedef struct find_cmd_ctx {\n    const char *name; /*!< the name to check commands against */\n    esp_cli_command_t *cmd; /*!< the command matching the name */\n} find_cmd_ctx_t;\n\nstatic inline __attribute__((always_inline))\nbool compare_command_name(void *ctx, esp_cli_command_t *cmd)\n{\n    /* called by esp_cli_commands_find_command through go_through_commands,\n     * ctx cannot be NULL */\n    find_cmd_ctx_t *cmd_ctx = (find_cmd_ctx_t *)ctx;\n\n    /* called by go_through_commands, thus cmd cannot be NULL */\n    if (strcmp(cmd->name, cmd_ctx->name) == 0) {\n        /* command found, store it in the ctx so esp_cli_commands_find_command\n         * can process it. Notify go_through_commands to stop the walk by\n         * returning false */\n        cmd_ctx->cmd = cmd;\n        return false;\n    }\n\n    /* command not matching with the name from the ctx, continue the walk */\n    return true;\n}\n\nvoid *esp_cli_commands_malloc(const size_t malloc_size)\n{\n    esp_cli_commands_lock();\n    const uint32_t caps = s_config.heap_caps_used;\n    esp_cli_commands_unlock();\n\n    return heap_caps_malloc(malloc_size, caps);\n}\n\nesp_err_t esp_cli_commands_update_config(const esp_cli_commands_config_t *config)\n{\n    if (!config ||\n            (config->max_cmdline_args == 0) ||\n            (config->max_cmdline_length == 0)) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    esp_cli_commands_lock();\n    memcpy(&s_config, config, sizeof(s_config));\n\n    /* if the heap_caps_used field is set to 0, set\n     * it to MALLOC_CAP_DEFAULT */\n    if (s_config.heap_caps_used == 0) {\n        s_config.heap_caps_used = MALLOC_CAP_DEFAULT;\n    }\n    esp_cli_commands_unlock();\n\n    return ESP_OK;\n}\n\nesp_err_t esp_cli_commands_register_cmd(esp_cli_command_t *cmd)\n{\n    if (cmd == NULL ||\n            (cmd->name == NULL || strchr(cmd->name, ' ') != NULL) ||\n            (cmd->func == NULL)) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    /* try to find the command in the static and dynamic lists.\n     * if the dynamic list is empty, the mutex locking will fail\n     * in esp_cli_commands_find_command and the function will return after\n     * checking the static list only. */\n    esp_cli_command_t *list_item_cmd = esp_cli_commands_find_command((esp_cli_command_sets_t *)NULL, cmd->name);\n    esp_err_t ret_val = ESP_FAIL;\n    if (!list_item_cmd) {\n        /* command with given name not found, it is a new command, we can allocate\n         * the list item and the command itself */\n        ret_val = esp_cli_dynamic_commands_add(cmd);\n    } else if (command_is_static(list_item_cmd)) {\n        /* a command with matching name is found in the list of commands\n         * that were registered at runtime, in which case it cannot be\n         * replaced with the new command */\n        ret_val = ESP_FAIL;\n    } else {\n        /* an item with matching name was found in the list of dynamically\n         * registered commands. Replace the command on spot with the new esp_cli_command_t. */\n        ret_val = esp_cli_dynamic_commands_replace(list_item_cmd, cmd);\n    }\n\n    return ret_val;\n}\n\nesp_err_t esp_cli_commands_unregister_cmd(const char *cmd_name)\n{\n    /* only items dynamically registered can be unregistered.\n     * try to remove the item with the given name from the list\n     * of dynamically registered commands */\n    esp_cli_command_t *cmd = esp_cli_commands_find_command((esp_cli_command_sets_t *)NULL, cmd_name);\n    if (!cmd) {\n        return ESP_ERR_NOT_FOUND;\n    } else if (command_is_static(cmd)) {\n        return ESP_ERR_INVALID_ARG;\n    } else {\n        return esp_cli_dynamic_commands_remove(cmd);\n    }\n}\n\nesp_err_t esp_cli_commands_execute(const char *cmdline, int *cmd_ret, esp_cli_command_set_handle_t cmd_set, esp_cli_commands_exec_arg_t *cmd_args)\n{\n    esp_cli_commands_lock();\n    const size_t copy_max_cmdline_args = s_config.max_cmdline_args;\n    const size_t opy_max_cmdline_length = s_config.max_cmdline_length;\n    esp_cli_commands_unlock();\n\n    /* the life time of those variables is not exceeding the scope of this function. Use the stack. */\n    char *argv[copy_max_cmdline_args];\n    memset(argv, 0x00, sizeof(argv));\n    char tmp_line_buf[opy_max_cmdline_length];\n    memset(tmp_line_buf, 0x00, sizeof(tmp_line_buf));\n\n    /* copy the raw command line into the temp buffer */\n    strlcpy(tmp_line_buf, cmdline, opy_max_cmdline_length);\n\n    /* parse and split the raw command line */\n    size_t argc = esp_cli_commands_split_argv(tmp_line_buf, argv, copy_max_cmdline_args);\n\n    if (argc == 0) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    /* try to find the command from the first argument in the command line */\n    const esp_cli_command_t *cmd = NULL;\n    esp_cli_command_sets_t *temp_set = cmd_set;\n    bool is_cmd_help = false;\n    if (strcmp(\"help\", argv[0]) == 0) {\n        /* set the set to NULL because the help is not in the set passed by the user\n         * since this command is registered by esp_cli_commands itself */\n        temp_set = (esp_cli_command_sets_t *)NULL;\n\n        /* keep in mind that the command being executed is the help. This is needed\n         * when calling the help command function, to pass a specific dynamic context */\n        is_cmd_help = true;\n    }\n    cmd = esp_cli_commands_find_command(temp_set, argv[0]);\n\n    if (cmd == NULL) {\n        return ESP_ERR_NOT_FOUND;\n    }\n\n    if (cmd->func) {\n        if (is_cmd_help) {\n            esp_cli_commands_exec_arg_t help_args;\n\n            /* reuse the out_fd and write_func received as parameter by esp_cli_commands_execute\n             * to allow the help command function to print information on the correct IO. Use\n             * default values in case the parameters provided are not set */\n            help_args.out_fd = (cmd_args && cmd_args->out_fd != -1) ? cmd_args->out_fd : STDOUT_FILENO;\n            help_args.write_func = (cmd_args && cmd_args->write_func) ? cmd_args->write_func : write;\n\n            /* the help command needs the cmd_set to be able to only print the help for commands\n             * in the user set of commands */\n            help_args.dynamic_ctx = cmd_set;\n\n            /* call the help command function with the specific dynamic context */\n            *cmd_ret = (*cmd->func)(cmd->func_ctx, &help_args, argc, argv);\n        } else {\n            /* regular command function has to be called, just passed the cmd_args as provided\n             * to the esp_cli_commands_execute function */\n            *cmd_ret = (*cmd->func)(cmd->func_ctx, cmd_args, argc, argv);\n        }\n    }\n    return ESP_OK;\n}\n\nesp_cli_command_t *esp_cli_commands_find_command(esp_cli_command_set_handle_t cmd_set, const char *name)\n{\n    /* no need to check that cmd_set is NULL, if it is, then FOR_EACH_XX_COMMAND\n     * will go through all registered commands */\n    if (!name) {\n        return NULL;\n    }\n\n    find_cmd_ctx_t ctx = { .cmd = NULL, .name = name };\n    go_through_commands(cmd_set, &ctx, compare_command_name);\n\n    /* The \"help\" command is a built-in registered by esp_cli_commands itself.\n     * It must always be found regardless of the command set passed by the user.\n     * If not found in the filtered set, search all commands. */\n    if (!ctx.cmd && cmd_set != NULL && strcmp(name, \"help\") == 0) {\n        go_through_commands(NULL, &ctx, compare_command_name);\n    }\n\n    /* if command was found during the walk, cmd field will be populated with\n     * the command matching the name given in parameter, otherwise it will still\n     * be NULL (value set as default value above) */\n    return ctx.cmd;\n}\ntypedef struct create_cmd_set_ctx {\n    esp_cli_commands_get_field_t get_field;\n    const char *cmd_set_name;\n    esp_cli_command_t **static_cmd_ptrs;\n    size_t static_cmd_count;\n    esp_cli_command_t **dynamic_cmd_ptrs;\n    size_t dynamic_cmd_count;\n} create_cmd_set_ctx_t;\n\nstatic inline __attribute__((always_inline))\nbool fill_temp_set_info(void *caller_ctx, esp_cli_command_t *cmd)\n{\n    /* called by esp_cli_commands_find_command through go_through_commands,\n     * ctx cannot be NULL */\n    create_cmd_set_ctx_t *ctx = (create_cmd_set_ctx_t *)caller_ctx;\n\n    /* called by go_through_commands, thus cmd cannot be NULL */\n    if (strcmp(ctx->get_field(cmd), ctx->cmd_set_name) == 0) {\n        // it's a match, add the pointer to command to the cmd ptr set\n        if (command_is_static(cmd)) {\n            ctx->static_cmd_ptrs[ctx->static_cmd_count] = cmd;\n            ctx->static_cmd_count++;\n        } else {\n            ctx->dynamic_cmd_ptrs[ctx->dynamic_cmd_count] = cmd;\n            ctx->dynamic_cmd_count++;\n        }\n    }\n\n    /* command not matching with the name from the ctx, continue the walk */\n    return true;\n}\n\nstatic inline __attribute__((always_inline))\nesp_err_t update_cmd_set_with_temp_info(esp_cli_command_set_t *cmd_set, size_t cmd_count, esp_cli_command_t **cmd_ptrs)\n{\n    if (cmd_count == 0) {\n        cmd_set->cmd_ptr_set = NULL;\n        cmd_set->cmd_set_size = 0;\n    } else {\n        const size_t alloc_cmd_ptrs_size = sizeof(esp_cli_command_t *) * cmd_count;\n        cmd_set->cmd_ptr_set = esp_cli_commands_malloc(alloc_cmd_ptrs_size);\n        if (!cmd_set->cmd_ptr_set) {\n            return ESP_ERR_NO_MEM;\n        } else {\n            /* copy the temp set of pointer in to the final destination */\n            memcpy(cmd_set->cmd_ptr_set, cmd_ptrs, alloc_cmd_ptrs_size);\n            cmd_set->cmd_set_size = cmd_count;\n        }\n    }\n    return ESP_OK;\n}\n\nesp_cli_command_set_handle_t esp_cli_commands_create_cmd_set(const char **cmd_set, const size_t cmd_set_size, esp_cli_commands_get_field_t get_field)\n{\n    if (!cmd_set || cmd_set_size == 0) {\n        return NULL;\n    }\n\n    esp_cli_command_sets_t *cmd_ptr_sets = esp_cli_commands_malloc(sizeof(esp_cli_command_sets_t));\n    if (!cmd_ptr_sets) {\n        return NULL;\n    }\n\n\n    esp_cli_command_t *static_cmd_ptrs_temp[ESP_CLI_COMMANDS_COUNT];\n    esp_cli_command_t *dynamic_cmd_ptrs_temp[esp_cli_dynamic_commands_get_number_of_cmd()];\n    create_cmd_set_ctx_t ctx = {\n        .cmd_set_name = NULL,\n        .get_field = get_field,\n        .static_cmd_ptrs = static_cmd_ptrs_temp,\n        .static_cmd_count = 0,\n        .dynamic_cmd_ptrs = dynamic_cmd_ptrs_temp,\n        .dynamic_cmd_count = 0\n    };\n\n    /* populate the temporary cmd pointer sets */\n    for (size_t i = 0; i < cmd_set_size; i++) {\n        ctx.cmd_set_name = cmd_set[i];\n        go_through_commands(NULL, &ctx, fill_temp_set_info);\n    }\n\n    /* if no static command was found, return a static set with 0 items in it */\n    esp_err_t ret_val = update_cmd_set_with_temp_info(&cmd_ptr_sets->static_set,\n                        ctx.static_cmd_count,\n                        ctx.static_cmd_ptrs);\n    if (ret_val == ESP_ERR_NO_MEM) {\n        free(cmd_ptr_sets);\n        return NULL;\n    }\n\n    /* if no dynamic command was found, return a dynamic set with 0 items in it */\n    ret_val = update_cmd_set_with_temp_info(&cmd_ptr_sets->dynamic_set,\n                                            ctx.dynamic_cmd_count,\n                                            ctx.dynamic_cmd_ptrs);\n    if (ret_val == ESP_ERR_NO_MEM) {\n        free(cmd_ptr_sets->static_set.cmd_ptr_set);\n        free(cmd_ptr_sets);\n        return NULL;\n    }\n\n    return (esp_cli_command_set_handle_t)cmd_ptr_sets;\n}\n\nesp_cli_command_set_handle_t esp_cli_commands_concat_cmd_set(esp_cli_command_set_handle_t cmd_set_a, esp_cli_command_set_handle_t cmd_set_b)\n{\n    if (!cmd_set_a && !cmd_set_b) {\n        return NULL;\n    } else if (cmd_set_a && !cmd_set_b) {\n        return cmd_set_a;\n    } else if (!cmd_set_a && cmd_set_b) {\n        return cmd_set_b;\n    }\n\n    /* Reaching this point, both cmd_set_a and cmd_set_b are set.\n     * Create a new cmd_set that can host the items from both sets,\n     * assign the items to the new set and free the input sets */\n    esp_cli_command_sets_t *concat_cmd_sets = esp_cli_commands_malloc(sizeof(esp_cli_command_sets_t));\n    if (!concat_cmd_sets) {\n        return NULL;\n    }\n    const size_t new_static_set_size = cmd_set_a->static_set.cmd_set_size + cmd_set_b->static_set.cmd_set_size;\n    concat_cmd_sets->static_set.cmd_ptr_set = calloc(new_static_set_size, sizeof(esp_cli_command_t *));\n    if (!concat_cmd_sets->static_set.cmd_ptr_set) {\n        free(concat_cmd_sets);\n        return NULL;\n    }\n\n    const size_t new_dynamic_set_size = cmd_set_a->dynamic_set.cmd_set_size + cmd_set_b->dynamic_set.cmd_set_size;\n    concat_cmd_sets->dynamic_set.cmd_ptr_set = calloc(new_dynamic_set_size, sizeof(esp_cli_command_t *));\n    if (!concat_cmd_sets->static_set.cmd_ptr_set) {\n        free(concat_cmd_sets->static_set.cmd_ptr_set);\n        free(concat_cmd_sets);\n        return NULL;\n    }\n\n    /* update the new cmd set sizes */\n    concat_cmd_sets->static_set.cmd_set_size = new_static_set_size;\n    concat_cmd_sets->dynamic_set.cmd_set_size = new_dynamic_set_size;\n\n    /* fill the list of command pointers */\n    memcpy(concat_cmd_sets->static_set.cmd_ptr_set,\n           cmd_set_a->static_set.cmd_ptr_set,\n           sizeof(esp_cli_command_t *) * cmd_set_a->static_set.cmd_set_size);\n    memcpy(concat_cmd_sets->static_set.cmd_ptr_set + cmd_set_a->static_set.cmd_set_size,\n           cmd_set_b->static_set.cmd_ptr_set,\n           sizeof(esp_cli_command_t *) * cmd_set_b->static_set.cmd_set_size);\n\n    memcpy(concat_cmd_sets->dynamic_set.cmd_ptr_set,\n           cmd_set_a->dynamic_set.cmd_ptr_set,\n           sizeof(esp_cli_command_t *) * cmd_set_a->dynamic_set.cmd_set_size);\n    memcpy(concat_cmd_sets->dynamic_set.cmd_ptr_set + cmd_set_a->dynamic_set.cmd_set_size,\n           cmd_set_b->dynamic_set.cmd_ptr_set,\n           sizeof(esp_cli_command_t *) * cmd_set_b->dynamic_set.cmd_set_size);\n\n    esp_cli_commands_destroy_cmd_set(&cmd_set_a);\n    esp_cli_commands_destroy_cmd_set(&cmd_set_b);\n\n    return (esp_cli_command_set_handle_t)concat_cmd_sets;\n}\n\nvoid esp_cli_commands_destroy_cmd_set(esp_cli_command_set_handle_t *cmd_set)\n{\n    if (!cmd_set || !*cmd_set) {\n        return;\n    }\n\n    if ((*cmd_set)->static_set.cmd_ptr_set) {\n        free((*cmd_set)->static_set.cmd_ptr_set);\n    }\n\n    if ((*cmd_set)->dynamic_set.cmd_ptr_set) {\n        free((*cmd_set)->dynamic_set.cmd_ptr_set);\n    }\n\n    free(*cmd_set);\n    *cmd_set = NULL;\n}\n\ntypedef struct call_completion_cb_ctx {\n    const char *buf;\n    const size_t buf_len;\n    void *cb_ctx;\n    esp_cli_command_get_completion_t completion_cb;\n} call_completion_cb_ctx_t;\n\nstatic bool call_completion_cb(void *caller_ctx, esp_cli_command_t *cmd)\n{\n    call_completion_cb_ctx_t *ctx = (call_completion_cb_ctx_t *)caller_ctx;\n\n    /* Check if command starts with buf */\n    if ((strlen(cmd->name) >= ctx->buf_len) &&\n            (strncmp(ctx->buf, cmd->name, ctx->buf_len) == 0)) {\n        ctx->completion_cb(ctx->cb_ctx, cmd->name);\n    }\n    return true;\n}\n\nvoid esp_cli_commands_get_completion(esp_cli_command_set_handle_t cmd_set, const char *buf, void *cb_ctx, esp_cli_command_get_completion_t completion_cb)\n{\n    size_t len = strlen(buf);\n    if (len == 0) {\n        return;\n    }\n\n    call_completion_cb_ctx_t ctx = {\n        .buf = buf,\n        .buf_len = len,\n        .cb_ctx = cb_ctx,\n        .completion_cb = completion_cb\n    };\n    go_through_commands(cmd_set, &ctx, call_completion_cb);\n\n    /* The \"help\" command is a built-in that must always be completable\n     * regardless of the command set */\n    if (cmd_set != NULL && len <= 4 && strncmp(buf, \"help\", len) == 0) {\n        completion_cb(cb_ctx, \"help\");\n    }\n}\n\nconst char *esp_cli_commands_get_hint(esp_cli_command_set_handle_t cmd_set, const char *buf, int *color, bool *bold)\n{\n    esp_cli_commands_lock();\n    *color = s_config.hint_color;\n    *bold = s_config.hint_bold;\n    esp_cli_commands_unlock();\n\n    esp_cli_command_t *cmd = esp_cli_commands_find_command(cmd_set, buf);\n    if (cmd && cmd->hint_cb != NULL) {\n        return cmd->hint_cb(cmd->func_ctx);\n    }\n\n    return NULL;\n}\n\nconst char *esp_cli_commands_get_glossary(esp_cli_command_set_handle_t cmd_set, const char *buf)\n{\n    esp_cli_command_t *cmd = esp_cli_commands_find_command(cmd_set, buf);\n    if (cmd && cmd->glossary_cb != NULL) {\n        return cmd->glossary_cb(cmd->func_ctx);\n    }\n\n    return NULL;\n}\n\n/* -------------------------------------------------------------- */\n/* help command related code */\n/* -------------------------------------------------------------- */\n\n#define ESP_CLI_COMMANDS_FD_PRINT(fd, write, fmt, ...) do {            \\\n    esp_cli_commands_lock();                                            \\\n    char _buf[s_config.max_cmdline_length];                             \\\n    esp_cli_commands_unlock();                                          \\\n    int _len = snprintf(_buf, sizeof(_buf), fmt, ##__VA_ARGS__);        \\\n    if (_len > 0) {                                                     \\\n        ssize_t _ignored __attribute__((unused));                       \\\n        _ignored = write(fd, _buf,                                      \\\n            _len < (int)sizeof(_buf) ? _len : (int)sizeof(_buf) - 1);   \\\n    }                                                                   \\\n} while (0)\n\nstatic void print_arg_help(esp_cli_commands_exec_arg_t *cmd_args, esp_cli_command_t *it)\n{\n    /* First line: command name and hint\n     * Pad all the hints to the same column\n     */\n    ESP_CLI_COMMANDS_FD_PRINT(cmd_args->out_fd, cmd_args->write_func, \"%s\",  it->name);\n\n    const char *hint = NULL;\n    if (it->hint_cb) {\n        hint = it->hint_cb(it->func_ctx);\n    }\n\n    if (hint) {\n        ESP_CLI_COMMANDS_FD_PRINT(cmd_args->out_fd, cmd_args->write_func, \" %s\\n\", it->hint_cb(it->func_ctx));\n    } else {\n        ESP_CLI_COMMANDS_FD_PRINT(cmd_args->out_fd, cmd_args->write_func, \" -\\n\");\n    }\n\n    /* Second line: print help */\n    /* TODO: replace the simple print with a function that\n     * replaces arg_print_formatted */\n    if (it->help) {\n        ESP_CLI_COMMANDS_FD_PRINT(cmd_args->out_fd, cmd_args->write_func, \" %s\\n\", it->help);\n    } else {\n        ESP_CLI_COMMANDS_FD_PRINT(cmd_args->out_fd, cmd_args->write_func, \" -\\n\");\n    }\n\n    /* Third line: print the glossary*/\n    const char *glossary = NULL;\n    if (it->glossary_cb) {\n        glossary = it->glossary_cb(it->func_ctx);\n    }\n\n    if (glossary) {\n        ESP_CLI_COMMANDS_FD_PRINT(cmd_args->out_fd, cmd_args->write_func, \" %s\\n\", it->glossary_cb(it->func_ctx));\n    } else {\n        ESP_CLI_COMMANDS_FD_PRINT(cmd_args->out_fd, cmd_args->write_func, \" -\\n\");\n    }\n\n    ESP_CLI_COMMANDS_FD_PRINT(cmd_args->out_fd, cmd_args->write_func, \"\\n\");\n}\n\nstatic void print_arg_command(esp_cli_commands_exec_arg_t *cmd_args, esp_cli_command_t *it)\n{\n    ESP_CLI_COMMANDS_FD_PRINT(cmd_args->out_fd, cmd_args->write_func, \"%-s\", it->name);\n    if (it->hint_cb) {\n        const char *hint = it->hint_cb(it->func_ctx);\n        if (hint) {\n            ESP_CLI_COMMANDS_FD_PRINT(cmd_args->out_fd, cmd_args->write_func, \" %s\", it->hint_cb(it->func_ctx));\n        }\n    }\n\n    ESP_CLI_COMMANDS_FD_PRINT(cmd_args->out_fd, cmd_args->write_func, \"\\n\");\n}\n\ntypedef enum {\n    HELP_VERBOSE_LEVEL_0       = 0,\n    HELP_VERBOSE_LEVEL_1       = 1,\n    HELP_VERBOSE_LEVEL_MAX_NUM = 2\n} help_verbose_level_e;\n\ntypedef void (*const fn_print_arg_t)(esp_cli_commands_exec_arg_t *cmd_args, esp_cli_command_t *);\n\nstatic fn_print_arg_t print_verbose_level_arr[HELP_VERBOSE_LEVEL_MAX_NUM] = {\n    print_arg_command,\n    print_arg_help,\n};\n\ntypedef struct call_cmd_ctx {\n    esp_cli_commands_exec_arg_t *cmd_args;\n    help_verbose_level_e verbose_level;\n    const char *command_name;\n    bool command_found;\n} call_cmd_ctx_t;\n\nstatic inline __attribute__((always_inline))\nbool call_command_funcs(void *caller_ctx, esp_cli_command_t *cmd)\n{\n    call_cmd_ctx_t *ctx = (call_cmd_ctx_t *)caller_ctx;\n\n    if (!ctx->command_name) {\n        /* ctx->command_name is empty, print all commands */\n        print_verbose_level_arr[ctx->verbose_level](ctx->cmd_args, cmd);\n    } else if (ctx->command_name &&\n               (strcmp(ctx->command_name, cmd->name) == 0)) {\n        /* we found the command name, print the help and return */\n        print_verbose_level_arr[ctx->verbose_level](ctx->cmd_args, cmd);\n        ctx->command_found = true;\n        return false;\n    }\n\n    return true;\n}\n\nstatic int help_command(void *context, esp_cli_commands_exec_arg_t *cmd_args, int argc, char **argv)\n{\n    (void)context; /* this is NULL and useless for the help command */\n\n    char *command_name = NULL;\n    help_verbose_level_e verbose_level = HELP_VERBOSE_LEVEL_1;\n\n    /* argc can never be superior to 4 given than the format is:\n     * help cmd_name -v 0 */\n    if (argc <= 0 || argc > 4) {\n        /* unknown issue, return error */\n        ESP_CLI_COMMANDS_FD_PRINT(cmd_args->out_fd, cmd_args->write_func, \"help: invalid number of arguments %d\\n\", argc);\n        return 1;\n    }\n\n    esp_cli_command_sets_t *cmd_sets = (esp_cli_command_sets_t *)cmd_args->dynamic_ctx;\n\n    if (argc > 1) {\n        /* more than 1 arg, figure out if only verbose level argument\n         * was passed and if a specific command was passed.\n         * start from the second argument since the first one is \"help\" */\n        for (int i = 1; i < argc; i++) {\n            if ((strcmp(argv[i], \"-v\") == 0) ||\n                    (strcmp(argv[i], \"--verbose\") == 0)) {\n                /* check if the following argument is either 0, or 1 */\n                if (i + 1 >= argc) {\n                    /* format error, return with error */\n                    ESP_CLI_COMMANDS_FD_PRINT(cmd_args->out_fd, cmd_args->write_func, \"help: arguments not provided in the right format\\n\");\n                    return 1;\n                } else if (strcmp(argv[i + 1], \"0\") == 0) {\n                    verbose_level = 0;\n                } else if (strcmp(argv[i + 1], \"1\") == 0) {\n                    verbose_level = 1;\n                } else {\n                    /* wrong command format, return error */\n                    ESP_CLI_COMMANDS_FD_PRINT(cmd_args->out_fd, cmd_args->write_func, \"help: invalid verbose level %s\\n\", argv[i + 1]);\n                    return 1;\n                }\n\n                /* we found the -v / --verbose, bump i to skip the value of\n                 * the verbose argument since it was just parsed */\n                i++;\n            } else {\n                /* the argument is not -v or --verbose, it is then the command name\n                 * of which we should print the hint, store it for latter */\n                command_name = argv[i];\n            }\n        }\n    }\n\n    /* at this point we should have figured out all the arguments of the help\n     * command. if command_name is NULL, then print all commands. if command_name\n     * is not NULL, find the command and only print the help for this command. if the\n     * command is not found, return with error */\n    call_cmd_ctx_t ctx = {\n        .cmd_args = cmd_args,\n        .verbose_level = verbose_level,\n        .command_name = command_name,\n        .command_found = false\n    };\n    go_through_commands(cmd_sets, &ctx, call_command_funcs);\n\n    /* The \"help\" command is a built-in that must always appear in listings\n     * regardless of the command set */\n    if (cmd_sets != NULL) {\n        esp_cli_command_t *help_cmd = esp_cli_commands_find_command(NULL, \"help\");\n        if (help_cmd) {\n            if (!command_name) {\n                /* Listing all commands: also print the help entry */\n                print_verbose_level_arr[verbose_level](cmd_args, help_cmd);\n            } else if (strcmp(command_name, \"help\") == 0) {\n                /* User asked specifically for \"help help\" */\n                print_verbose_level_arr[verbose_level](cmd_args, help_cmd);\n                ctx.command_found = true;\n            }\n        }\n    }\n\n    if (command_name && !ctx.command_found) {\n        ESP_CLI_COMMANDS_FD_PRINT(cmd_args->out_fd, cmd_args->write_func, \"help: invalid command name %s\\n\", command_name);\n        return 1;\n    }\n\n    return 0;\n}\n\nstatic const char *get_help_hint(void *context)\n{\n    (void)context;\n    return \"[<string>] [-v <0|1>]\";\n}\n\nstatic const char *get_help_glossary(void *context)\n{\n    (void)context;\n    return \"  <string>             Name of command\\n\"\n           \"  -v, --verbose <0|1>  If specified, list console commands with given verbose level\";;\n}\n\nstatic const char help_str[] = \"Print the summary of all registered commands if no arguments \"\n                               \"are given, otherwise print summary of given command.\";\n\nESP_CLI_COMMAND_REGISTER(help, /* name of the heap command */\n                         help, /* group of the help command */\n                         help_str, /* help string of the help command */\n                         help_command, /* func */\n                         NULL, /* the context is null here, it will provided by the exec function */\n                         get_help_hint, /* hint callback */\n                         get_help_glossary); /* glossary callback */\n"
  },
  {
    "path": "esp_cli_commands/src/esp_cli_commands_helpers.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <ctype.h>\n#include <string.h>\n#include <stddef.h>\n#include \"esp_cli_commands.h\"\n\n#define SS_FLAG_ESCAPE 0x8\n\ntypedef enum {\n    /* parsing the space between arguments */\n    SS_SPACE = 0x0,\n    /* parsing an argument which isn't quoted */\n    SS_ARG = 0x1,\n    /* parsing a quoted argument */\n    SS_QUOTED_ARG = 0x2,\n    /* parsing an escape sequence within unquoted argument */\n    SS_ARG_ESCAPED = SS_ARG | SS_FLAG_ESCAPE,\n    /* parsing an escape sequence within a quoted argument */\n    SS_QUOTED_ARG_ESCAPED = SS_QUOTED_ARG | SS_FLAG_ESCAPE,\n} split_state_t;\n\n/* helper macro, called when done with an argument */\n#define END_ARG() do { \\\n    char_out = 0; \\\n    argv[argc++] = next_arg_start; \\\n    state = SS_SPACE; \\\n} while(0)\n\nsize_t esp_cli_commands_split_argv(char *line, char **argv, size_t argv_size)\n{\n    const int QUOTE = '\"';\n    const int ESCAPE = '\\\\';\n    const int SPACE = ' ';\n    split_state_t state = SS_SPACE;\n    size_t argc = 0;\n    char *next_arg_start = line;\n    char *out_ptr = line;\n    for (char *in_ptr = line; argc < argv_size - 1; ++in_ptr) {\n        int char_in = (unsigned char) * in_ptr;\n        if (char_in == 0) {\n            break;\n        }\n        int char_out = -1;\n\n        switch (state) {\n        case SS_SPACE:\n            if (char_in == SPACE) {\n                /* skip space */\n            } else if (char_in == QUOTE) {\n                next_arg_start = out_ptr;\n                state = SS_QUOTED_ARG;\n            } else if (char_in == ESCAPE) {\n                next_arg_start = out_ptr;\n                state = SS_ARG_ESCAPED;\n            } else {\n                next_arg_start = out_ptr;\n                state = SS_ARG;\n                char_out = char_in;\n            }\n            break;\n\n        case SS_QUOTED_ARG:\n            if (char_in == QUOTE) {\n                END_ARG();\n            } else if (char_in == ESCAPE) {\n                state = SS_QUOTED_ARG_ESCAPED;\n            } else {\n                char_out = char_in;\n            }\n            break;\n\n        case SS_ARG_ESCAPED:\n        case SS_QUOTED_ARG_ESCAPED:\n            if (char_in == ESCAPE || char_in == QUOTE || char_in == SPACE) {\n                char_out = char_in;\n            } else {\n                /* unrecognized escape character, skip */\n            }\n            state = (split_state_t)(state & (~SS_FLAG_ESCAPE));\n            break;\n\n        case SS_ARG:\n            if (char_in == SPACE) {\n                END_ARG();\n            } else if (char_in == ESCAPE) {\n                state = SS_ARG_ESCAPED;\n            } else {\n                char_out = char_in;\n            }\n            break;\n        }\n        /* need to output anything? */\n        if (char_out >= 0) {\n            *out_ptr = char_out;\n            ++out_ptr;\n        }\n    }\n    /* make sure the final argument is terminated */\n    *out_ptr = 0;\n    /* finalize the last argument */\n    if (state != SS_SPACE && argc < argv_size - 1) {\n        argv[argc++] = next_arg_start;\n    }\n    /* add a NULL at the end of argv */\n    argv[argc] = NULL;\n\n    return argc;\n}\n"
  },
  {
    "path": "esp_cli_commands/src/esp_cli_dynamic_commands.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <ctype.h>\n#include <string.h>\n#include <stddef.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/semphr.h\"\n#include \"esp_cli_commands_internal.h\"\n#include \"esp_cli_dynamic_commands.h\"\n#include \"esp_cli_commands.h\"\n\n#define CONTAINER_OF(ptr, type, member) \\\n    ((type *)((char *)(ptr) - offsetof(type, member)))\n\nstatic esp_cli_command_internal_ll_t s_dynamic_cmd_list = SLIST_HEAD_INITIALIZER(esp_cli_command_internal);\nstatic size_t s_number_of_registered_commands = 0;\nstatic SemaphoreHandle_t s_esp_cli_commands_dyn_mutex = NULL;\nstatic StaticSemaphore_t s_esp_cli_commands_dyn_mutex_buf;\n\nvoid esp_cli_dynamic_commands_lock(void)\n{\n    /* check if the mutex needs to be initialized and initialized it only\n     * is requested in by the state of the create parameter */\n    if (s_esp_cli_commands_dyn_mutex == NULL) {\n        s_esp_cli_commands_dyn_mutex = xSemaphoreCreateMutexStatic(&s_esp_cli_commands_dyn_mutex_buf);\n        assert(s_esp_cli_commands_dyn_mutex != NULL);\n    }\n\n    xSemaphoreTake(s_esp_cli_commands_dyn_mutex, portMAX_DELAY);\n}\n\nvoid esp_cli_dynamic_commands_unlock(void)\n{\n    if (s_esp_cli_commands_dyn_mutex == NULL) {\n        return;\n    }\n    xSemaphoreGive(s_esp_cli_commands_dyn_mutex);\n}\n\nconst esp_cli_command_internal_ll_t *esp_cli_dynamic_commands_get_list(void)\n{\n    return &s_dynamic_cmd_list;\n}\n\nesp_err_t esp_cli_dynamic_commands_add(esp_cli_command_t *cmd)\n{\n    if (!cmd) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    esp_cli_command_internal_t *list_item = esp_cli_commands_malloc(sizeof(esp_cli_command_internal_t));\n    if (!list_item) {\n        return ESP_ERR_NO_MEM;\n    }\n\n    memcpy(&list_item->cmd, cmd, sizeof(esp_cli_command_t));\n\n    esp_cli_command_internal_t *last = NULL;\n    esp_cli_command_internal_t *it =  NULL;\n\n    /* this could be called on an empty list, make sure the\n     * mutex is initialized */\n    esp_cli_dynamic_commands_lock();\n\n    SLIST_FOREACH(it, &s_dynamic_cmd_list, next_item) {\n        if (strcmp(it->cmd.name, list_item->cmd.name) > 0) {\n            break;\n        }\n        last = it;\n    }\n\n    if (last == NULL) {\n        SLIST_INSERT_HEAD(&s_dynamic_cmd_list, list_item, next_item);\n    } else {\n        SLIST_INSERT_AFTER(last, list_item, next_item);\n    }\n\n    s_number_of_registered_commands++;\n\n    esp_cli_dynamic_commands_unlock();\n\n    return ESP_OK;\n}\n\nesp_err_t esp_cli_dynamic_commands_replace(esp_cli_command_t *old_cmd, esp_cli_command_t *new_cmd)\n{\n    esp_cli_dynamic_commands_lock();\n\n    esp_cli_command_internal_t *list_item = CONTAINER_OF(old_cmd, esp_cli_command_internal_t, cmd);\n    memcpy(&list_item->cmd, new_cmd, sizeof(esp_cli_command_t));\n\n    esp_cli_dynamic_commands_unlock();\n\n    return ESP_OK;\n}\n\nesp_err_t esp_cli_dynamic_commands_remove(esp_cli_command_t *item_cmd)\n{\n    esp_cli_dynamic_commands_lock();\n\n    esp_cli_command_internal_t *list_item = CONTAINER_OF(item_cmd, esp_cli_command_internal_t, cmd);\n    SLIST_REMOVE(&s_dynamic_cmd_list, list_item, esp_cli_command_internal, next_item);\n\n    s_number_of_registered_commands--;\n\n    esp_cli_dynamic_commands_unlock();\n\n    free(list_item);\n\n    return ESP_OK;\n}\n\nsize_t esp_cli_dynamic_commands_get_number_of_cmd(void)\n{\n    esp_cli_dynamic_commands_lock();\n    size_t nb_of_registered_cmd = s_number_of_registered_commands;\n    esp_cli_dynamic_commands_unlock();\n    return nb_of_registered_cmd;\n}\n"
  },
  {
    "path": "esp_cli_commands/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.22)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(esp_cli_commands_test)\n"
  },
  {
    "path": "esp_cli_commands/test_apps/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"test_esp_cli_commands.c\" \"test_main.c\"\n                    PRIV_INCLUDE_DIRS \".\" \"include\"\n                    PRIV_REQUIRES unity\n                    WHOLE_ARCHIVE)\n"
  },
  {
    "path": "esp_cli_commands/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/esp_cli_commands:\n    version: \"*\"\n    override_path: \"../..\"\n"
  },
  {
    "path": "esp_cli_commands/test_apps/main/include/test_esp_cli_commands_utils.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define NB_OF_REGISTERED_CMD 8\n\n#define GET_NAME(NAME, SUFFIX) NAME##SUFFIX\n#define GET_STR(STR) #STR\n\n#define CREATE_CMD_FUNC(NAME) \\\n    static int GET_NAME(NAME, _func)(void *ctx, esp_cli_commands_exec_arg_t *cmd_args, int argc, char **argv) { \\\n        printf(GET_STR(NAME) GET_STR(_func)); \\\n        printf(\"\\n\"); \\\n        return 0; \\\n    }\n\n#define CREATE_FUNC(NAME, SUFFIX) \\\n    static const char *GET_NAME(NAME, SUFFIX)(void *context) { \\\n        return #NAME #SUFFIX; \\\n    }\n\n/* static command functions*/\nCREATE_CMD_FUNC(cmd_a)\nCREATE_CMD_FUNC(cmd_b)\nCREATE_CMD_FUNC(cmd_c)\nCREATE_CMD_FUNC(cmd_d)\nCREATE_CMD_FUNC(cmd_e)\nCREATE_CMD_FUNC(cmd_f)\nCREATE_CMD_FUNC(cmd_g)\nCREATE_CMD_FUNC(cmd_h)\n\n/* static hint functions*/\nCREATE_FUNC(cmd_a, _hint)\nCREATE_FUNC(cmd_b, _hint)\nCREATE_FUNC(cmd_c, _hint)\nCREATE_FUNC(cmd_d, _hint)\nCREATE_FUNC(cmd_e, _hint)\nCREATE_FUNC(cmd_f, _hint)\nCREATE_FUNC(cmd_g, _hint)\nCREATE_FUNC(cmd_h, _hint)\n\n/* static glossary functions*/\nCREATE_FUNC(cmd_a, _glossary)\nCREATE_FUNC(cmd_b, _glossary)\nCREATE_FUNC(cmd_c, _glossary)\nCREATE_FUNC(cmd_d, _glossary)\nCREATE_FUNC(cmd_e, _glossary)\nCREATE_FUNC(cmd_f, _glossary)\nCREATE_FUNC(cmd_g, _glossary)\nCREATE_FUNC(cmd_h, _glossary)\n\n/* command registration */\nESP_CLI_COMMAND_REGISTER(cmd_a, group_1, GET_STR(cmd_a_help), cmd_a_func, NULL, cmd_a_hint, cmd_a_glossary);\nESP_CLI_COMMAND_REGISTER(cmd_b, group_1, GET_STR(cmd_b_help), cmd_b_func, NULL, cmd_b_hint, cmd_b_glossary);\nESP_CLI_COMMAND_REGISTER(cmd_c, group_2, GET_STR(cmd_c_help), cmd_c_func, NULL, cmd_c_hint, cmd_c_glossary);\nESP_CLI_COMMAND_REGISTER(cmd_d, group_2, GET_STR(cmd_d_help), cmd_d_func, NULL, cmd_d_hint, cmd_d_glossary);\nESP_CLI_COMMAND_REGISTER(cmd_e, group_3, GET_STR(cmd_e_help), cmd_e_func, NULL, cmd_e_hint, cmd_e_glossary);\nESP_CLI_COMMAND_REGISTER(cmd_f, group_3, GET_STR(cmd_f_help), cmd_f_func, NULL, cmd_f_hint, cmd_f_glossary);\nESP_CLI_COMMAND_REGISTER(cmd_g, group_4, GET_STR(cmd_g_help), cmd_g_func, NULL, cmd_g_hint, cmd_g_glossary);\nESP_CLI_COMMAND_REGISTER(cmd_h, group_4, GET_STR(cmd_h_help), cmd_h_func, NULL, cmd_h_hint, cmd_h_glossary);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_cli_commands/test_apps/main/test_esp_cli_commands.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include <stdio.h>\n#include <unistd.h>\n#include <pthread.h>\n#include \"unity.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_cli_commands.h\"\n#include \"test_esp_cli_commands_utils.h\"\n\n/*\n * IMPORTANT:\n * - 8 commands are created in test_esp_cli_commands_utils.h (cmd_a - cmd_h)\n * - the commands are divided in 4 groups (group_1 - group_4)\n * - each group contains 2 commands.\n *      - group_1 contains cmd_a and cmd_b,\n *      [...]\n *      - group_4 contains cmd_g and cmd_h\n */\n\nstatic void test_setup(void)\n{\n    const esp_cli_commands_config_t config = {\n        .heap_caps_used = MALLOC_CAP_DEFAULT,\n        .hint_bold = false,\n        .hint_color = 39,\n        .max_cmdline_args = 32,\n        .max_cmdline_length = 256\n    };\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_update_config(&config));\n}\n\nTEST_CASE(\"help command - called without command set\", \"[esp_cli_commands]\")\n{\n    test_setup();\n\n    /* call esp_cli_commands_execute to run help command with verbosity 0 */\n    int cmd_ret = -1;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_execute(\"help -v 0\", &cmd_ret, NULL, NULL));\n    TEST_ASSERT_EQUAL(0, cmd_ret);\n\n    /* call esp_cli_commands_execute to run help command with verbosity 1 */\n    cmd_ret = -1;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_execute(\"help -v 1\", &cmd_ret, NULL, NULL));\n    TEST_ASSERT_EQUAL(0, cmd_ret);\n\n    /* call esp_cli_commands_execute to run help command on a registered command */\n    cmd_ret = -1;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_execute(\"help cmd_a -v 0\", &cmd_ret, NULL, NULL));\n    TEST_ASSERT_EQUAL(0, cmd_ret);\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_execute(\"help cmd_a -v 1\", &cmd_ret, NULL, NULL));\n    TEST_ASSERT_EQUAL(0, cmd_ret);\n\n    /* call esp_cli_commands_execute to run help command on an unregistered command */\n    cmd_ret = -1;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_execute(\"help cmd_w\", &cmd_ret, NULL, NULL));\n    TEST_ASSERT_EQUAL(1, cmd_ret);\n\n    /* call esp_cli_commands_execute to run help command on a registered command with wrong\n     * verbosity syntax */\n    cmd_ret = -1;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_execute(\"help cmd_a -v=1\", &cmd_ret, NULL, NULL));\n    TEST_ASSERT_EQUAL(1, cmd_ret);\n\n    /* call esp_cli_commands_execute to run help command with too many command names */\n    cmd_ret = -1;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_execute(\"help cmd_a cmd_b -v 1\", &cmd_ret, NULL, NULL));\n    TEST_ASSERT_EQUAL(1, cmd_ret);\n}\n\nTEST_CASE(\"test command set error handling\", \"[esp_cli_commands]\")\n{\n    test_setup();\n\n    /* create a command set with NULL passed as list of command id */\n    TEST_ASSERT_NULL(esp_cli_commands_create_cmd_set(NULL, 2, ESP_CLI_COMMAND_FIELD_ACCESSOR(group)));\n\n    /* create a command set with 0 as size of list of command id */\n    const char *group_set_a[] = {\"b\", \"group_4\"};\n    TEST_ASSERT_NULL(esp_cli_commands_create_cmd_set(group_set_a, 0, ESP_CLI_COMMAND_FIELD_ACCESSOR(group)));\n\n    /* concatenate 2 NULL sets */\n    TEST_ASSERT_NULL(esp_cli_commands_concat_cmd_set(NULL, NULL));\n\n    /* redefinition of esp_cli_command_set_t so we can access the fields\n     *  and test their values */\n    typedef struct cmd_set {\n        esp_cli_command_t **cmd_ptr_set;\n        size_t cmd_set_size;\n    } cmd_set_t;\n\n    /* pass wrong command name in array, expect a non null command set handle with 0 items in it*/\n    const char *group_set_b[] = {\"group2\", \"group4\"};\n    esp_cli_command_set_handle_t group_set_handle_b = esp_cli_commands_create_cmd_set(group_set_b, 2, ESP_CLI_COMMAND_FIELD_ACCESSOR(group));\n    cmd_set_t *cmd_set = (cmd_set_t *)group_set_handle_b;\n    TEST_ASSERT_NOT_NULL(group_set_handle_b);\n    TEST_ASSERT_NULL(cmd_set->cmd_ptr_set);\n    TEST_ASSERT_EQUAL(0, cmd_set->cmd_set_size);\n\n    esp_cli_commands_destroy_cmd_set(&group_set_handle_b);\n}\n\ntypedef struct cmd_test_sequence {\n    const char *cmd_list[NB_OF_REGISTERED_CMD];\n    int expected_ret_val[NB_OF_REGISTERED_CMD];\n} cmd_test_sequence_t;\n\nstatic void run_cmd_test(esp_cli_command_set_handle_t handle, const char **cmd_list, const int *expected_ret_val, size_t nb_cmds)\n{\n    for (size_t i = 0; i < nb_cmds; i++) {\n        int cmd_ret = -1;\n        esp_err_t expected = expected_ret_val[i] == 0 ? ESP_OK : ESP_ERR_NOT_FOUND;\n        TEST_ASSERT_EQUAL(expected, esp_cli_commands_execute(cmd_list[i], &cmd_ret, handle, NULL));\n        TEST_ASSERT_EQUAL(expected_ret_val[i], cmd_ret);\n    }\n}\n\nTEST_CASE(\"test static command set\", \"[esp_cli_commands]\")\n{\n    test_setup();\n\n    const char *cmd_list[] = {\"cmd_a\", \"cmd_b\", \"cmd_c\", \"cmd_d\", \"cmd_e\", \"cmd_f\", \"cmd_g\", \"cmd_h\"};\n    const size_t nb_cmds = sizeof(cmd_list) / sizeof(cmd_list[0]);\n    int expected_ret_val[nb_cmds];\n\n    /* create sets by group */\n    const char *group_set_a[] = {\"group_1\", \"group_3\"};\n    esp_cli_command_set_handle_t handle_set_a = ESP_CLI_COMMANDS_CREATE_CMD_SET(group_set_a, ESP_CLI_COMMAND_FIELD_ACCESSOR(group));\n    TEST_ASSERT_NOT_NULL(handle_set_a);\n\n    const char *group_set_b[] = {\"group_2\", \"group_4\"};\n    esp_cli_command_set_handle_t handle_set_b = ESP_CLI_COMMANDS_CREATE_CMD_SET(group_set_b, ESP_CLI_COMMAND_FIELD_ACCESSOR(group));\n    TEST_ASSERT_NOT_NULL(handle_set_b);\n\n    /* test set_a by group */\n    int tmp_ret[] = {0, 0, -1, -1, 0, 0, -1, -1};\n    memcpy(expected_ret_val, tmp_ret, sizeof(tmp_ret));\n    run_cmd_test(handle_set_a, cmd_list, expected_ret_val, nb_cmds);\n\n    /* test set_b by group */\n    int tmp_ret_b[] = {-1, -1, 0, 0, -1, -1, 0, 0};\n    memcpy(expected_ret_val, tmp_ret_b, sizeof(tmp_ret_b));\n    run_cmd_test(handle_set_b, cmd_list, expected_ret_val, nb_cmds);\n\n    /* test help command with set of static commands */\n    int cmd_ret;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_execute(\"help\", &cmd_ret, handle_set_a, NULL));\n    TEST_ASSERT_EQUAL(0, cmd_ret);\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_execute(\"help\", &cmd_ret, handle_set_b, NULL));\n    TEST_ASSERT_EQUAL(0, cmd_ret);\n\n    /* destroy sets */\n    esp_cli_commands_destroy_cmd_set(&handle_set_a);\n    esp_cli_commands_destroy_cmd_set(&handle_set_b);\n\n    /* create sets by name */\n    const char *cmd_name_set_a[] = {\"cmd_a\", \"cmd_b\", \"cmd_c\"};\n    handle_set_a = esp_cli_commands_create_cmd_set(cmd_name_set_a, 3, ESP_CLI_COMMAND_FIELD_ACCESSOR(name));\n    TEST_ASSERT_NOT_NULL(handle_set_a);\n\n    const char *cmd_name_set_b[] = {\"cmd_f\", \"cmd_g\", \"cmd_h\"};\n    handle_set_b = esp_cli_commands_create_cmd_set(cmd_name_set_b, 3, ESP_CLI_COMMAND_FIELD_ACCESSOR(name));\n    TEST_ASSERT_NOT_NULL(handle_set_b);\n\n    int tmp_ret2[] = {0, 0, 0, -1, -1, -1, -1, -1};\n    memcpy(expected_ret_val, tmp_ret2, sizeof(tmp_ret2));\n    run_cmd_test(handle_set_a, cmd_list, expected_ret_val, nb_cmds);\n\n    int tmp_ret3[] = {-1, -1, -1, -1, -1, 0, 0, 0};\n    memcpy(expected_ret_val, tmp_ret3, sizeof(tmp_ret3));\n    run_cmd_test(handle_set_b, cmd_list, expected_ret_val, nb_cmds);\n\n    /* concatenate sets */\n    esp_cli_command_set_handle_t handle_set_c = esp_cli_commands_concat_cmd_set(handle_set_a, handle_set_b);\n    TEST_ASSERT_NOT_NULL(handle_set_c);\n\n    int tmp_ret4[] = {0, 0, 0, -1, -1, 0, 0, 0};\n    memcpy(expected_ret_val, tmp_ret4, sizeof(tmp_ret4));\n    run_cmd_test(handle_set_c, cmd_list, expected_ret_val, nb_cmds);\n\n    esp_cli_commands_destroy_cmd_set(&handle_set_c);\n}\n\nstatic int dummy_cmd_func(void *context, esp_cli_commands_exec_arg_t *cmd_args, int argc, char **argv)\n{\n    (void)cmd_args;\n    (void)context;\n    printf(\"dynamic command called\\n\");\n    return 0; // always return success\n}\n\nTEST_CASE(\"test dynamic command set\", \"[esp_cli_commands]\")\n{\n    test_setup();\n\n    const char *cmd_list[] = {\"cmd_1\", \"cmd_2\", \"cmd_3\", \"cmd_4\", \"cmd_5\", \"cmd_6\", \"cmd_7\", \"cmd_8\"};\n    const size_t nb_cmds = sizeof(cmd_list) / sizeof(cmd_list[0]);\n    int expected_ret_val[nb_cmds];\n\n    /* dynamically register commands */\n    for (size_t i = 0; i < nb_cmds; i++) {\n        esp_cli_command_t cmd = {\n            .name = cmd_list[i],\n            .group = (i % 2 == 0) ? \"group_a\" : \"group_b\",\n            .help = \"dummy help\",\n            .func = dummy_cmd_func,  // implement a simple dummy function returning i%2\n            .func_ctx = NULL,\n            .hint_cb = NULL,\n            .glossary_cb = NULL\n        };\n        TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_register_cmd(&cmd));\n    }\n\n    /* test execution by group_a */\n    const char *group_set[] = {\"group_a\"};\n    esp_cli_command_set_handle_t handle_set_1 = ESP_CLI_COMMANDS_CREATE_CMD_SET(group_set, ESP_CLI_COMMAND_FIELD_ACCESSOR(group));\n    TEST_ASSERT_NOT_NULL(handle_set_1);\n\n    int tmp_ret[] = {0, -1, 0, -1, 0, -1, 0, -1};\n    memcpy(expected_ret_val, tmp_ret, sizeof(tmp_ret));\n    run_cmd_test(handle_set_1, cmd_list, expected_ret_val, nb_cmds);\n\n    /* test execution by command name */\n    const char *cmd_name_set[] = {\"cmd_1\", \"cmd_2\", \"cmd_3\"};\n    esp_cli_command_set_handle_t handle_set_2 = esp_cli_commands_create_cmd_set(cmd_name_set, 3, ESP_CLI_COMMAND_FIELD_ACCESSOR(name));\n    TEST_ASSERT_NOT_NULL(handle_set_2);\n\n    int tmp_ret2[] = {0, 0, 0, -1, -1, -1, -1, -1};\n    memcpy(expected_ret_val, tmp_ret2, sizeof(tmp_ret2));\n    run_cmd_test(handle_set_2, cmd_list, expected_ret_val, nb_cmds);\n\n    /* test help command with set of dynamic commands */\n    int cmd_ret;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_execute(\"help\", &cmd_ret, handle_set_1, NULL));\n    TEST_ASSERT_EQUAL(0, cmd_ret);\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_execute(\"help\", &cmd_ret, handle_set_2, NULL));\n    TEST_ASSERT_EQUAL(0, cmd_ret);\n\n\n    /* unregister dynamically registered commands */\n    for (size_t i = 0; i < nb_cmds; i++) {\n        TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_unregister_cmd(cmd_list[i]));\n    }\n\n    esp_cli_commands_destroy_cmd_set(&handle_set_1);\n    esp_cli_commands_destroy_cmd_set(&handle_set_2);\n}\n\nTEST_CASE(\"test static and dynamic command sets\", \"[esp_cli_commands]\")\n{\n    test_setup();\n\n    // --- dynamic commands ---\n    const char *dyn_cmd_list[] = {\"cmd_1\", \"cmd_2\", \"cmd_3\", \"cmd_4\", \"cmd_5\", \"cmd_6\", \"cmd_7\", \"cmd_8\"};\n    const size_t nb_dyn_cmds = sizeof(dyn_cmd_list) / sizeof(dyn_cmd_list[0]);\n\n    for (size_t i = 0; i < nb_dyn_cmds; i++) {\n        esp_cli_command_t cmd = {\n            .name = dyn_cmd_list[i],\n            .group = (i % 2 == 0) ? \"group_a\" : \"group_b\",\n            .help = \"dummy help\",\n            .func = dummy_cmd_func,\n            .func_ctx = NULL,\n            .hint_cb = NULL,\n            .glossary_cb = NULL\n        };\n        TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_register_cmd(&cmd));\n    }\n\n    // --- create static command sets (already registered statically) ---\n    const char *static_groups[] = {\"group_1\", \"group_3\"};\n    esp_cli_command_set_handle_t handle_static_set = ESP_CLI_COMMANDS_CREATE_CMD_SET(static_groups, ESP_CLI_COMMAND_FIELD_ACCESSOR(group));\n    TEST_ASSERT_NOT_NULL(handle_static_set);\n\n    // --- create dynamic command sets ---\n    const char *dyn_groups[] = {\"group_a\"};\n    esp_cli_command_set_handle_t handle_dynamic_set = ESP_CLI_COMMANDS_CREATE_CMD_SET(dyn_groups, ESP_CLI_COMMAND_FIELD_ACCESSOR(group));\n    TEST_ASSERT_NOT_NULL(handle_dynamic_set);\n\n    // --- combine static and dynamic sets ---\n    esp_cli_command_set_handle_t handle_combined_set = esp_cli_commands_concat_cmd_set(handle_static_set, handle_dynamic_set);\n    TEST_ASSERT_NOT_NULL(handle_combined_set);\n\n    // --- run tests for combined set ---\n    const char *all_cmds[] = {\"cmd_a\", \"cmd_b\", \"cmd_c\", \"cmd_d\", \"cmd_e\", \"cmd_f\", \"cmd_g\", \"cmd_h\",\n                              \"cmd_1\", \"cmd_2\", \"cmd_3\", \"cmd_4\", \"cmd_5\", \"cmd_6\", \"cmd_7\", \"cmd_8\"\n                             };\n    int expected_ret[] = {0, 0, -1, -1, 0, 0, -1, -1,\n                          0, -1, 0, -1, 0, -1, 0, -1\n                         };\n\n    run_cmd_test(handle_combined_set, all_cmds, expected_ret, 16);\n\n    /* test help command with set of dynamic commands */\n    int cmd_ret;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_execute(\"help\", &cmd_ret, handle_combined_set, NULL));\n    TEST_ASSERT_EQUAL(0, cmd_ret);\n\n    // --- cleanup ---\n    esp_cli_commands_destroy_cmd_set(&handle_combined_set);\n\n    for (size_t i = 0; i < nb_dyn_cmds; i++) {\n        TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_unregister_cmd(dyn_cmd_list[i]));\n    }\n}\n\nstatic size_t completion_nb_of_calls = 0;\n\nstatic void test_completion_cb(void *cb_ctx, const char *completed_cmd_name)\n{\n    completion_nb_of_calls++;\n}\n\nTEST_CASE(\"test completion callback\", \"[esp_cli_commands]\")\n{\n    test_setup();\n\n    /* create sets by group */\n    const char *set_a[] = {\"group_1\", \"group_3\"};\n    esp_cli_command_set_handle_t handle_set_a = ESP_CLI_COMMANDS_CREATE_CMD_SET(set_a, ESP_CLI_COMMAND_FIELD_ACCESSOR(group));\n    TEST_ASSERT_NOT_NULL(handle_set_a);\n\n    /* register a command dynamically and add it to the set */\n    esp_cli_command_t cmd = {\n        .name = \"dyn_cmd\",\n        .group = \"dyn_cmd_group\",\n        .help = \"dummy help\",\n        .func = dummy_cmd_func,\n        .func_ctx = NULL,\n        .hint_cb = NULL,\n        .glossary_cb = NULL\n    };\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_register_cmd(&cmd));\n\n    const char *set_b[] = {\"dyn_cmd\"};\n    esp_cli_command_set_handle_t handle_set_b = ESP_CLI_COMMANDS_CREATE_CMD_SET(set_b, ESP_CLI_COMMAND_FIELD_ACCESSOR(name));\n    TEST_ASSERT_NOT_NULL(handle_set_b);\n    esp_cli_command_set_handle_t handle_concat_set = esp_cli_commands_concat_cmd_set(handle_set_a, handle_set_b);\n    TEST_ASSERT_NOT_NULL(handle_concat_set);\n\n    esp_cli_commands_get_completion(NULL, \"a\", NULL, test_completion_cb);\n    TEST_ASSERT_EQUAL(0, completion_nb_of_calls);\n\n    esp_cli_commands_get_completion(handle_concat_set, \"cmd_\", NULL, test_completion_cb);\n    TEST_ASSERT_EQUAL(4, completion_nb_of_calls);\n\n    /* reset the cb counter */\n    completion_nb_of_calls = 0;\n\n    esp_cli_commands_get_completion(NULL, \"cmd_\", NULL, test_completion_cb);\n    TEST_ASSERT_EQUAL(8, completion_nb_of_calls);\n\n    /* reset the cb counter */\n    completion_nb_of_calls = 0;\n\n    esp_cli_commands_get_completion(NULL, \"dyn\", NULL, test_completion_cb);\n    TEST_ASSERT_EQUAL(1, completion_nb_of_calls);\n\n    /* reset the cb counter */\n    completion_nb_of_calls = 0;\n\n    esp_cli_commands_get_completion(handle_concat_set, \"dyn\", NULL, test_completion_cb);\n    TEST_ASSERT_EQUAL(1, completion_nb_of_calls);\n\n    /* reset the cb counter */\n    completion_nb_of_calls = 0;\n\n    esp_cli_commands_destroy_cmd_set(&handle_concat_set);\n    TEST_ASSERT_NULL(handle_concat_set);\n\n    esp_cli_commands_unregister_cmd(\"dyn_cmd\");\n}\n\ntypedef struct hint_cb_ctx {\n    const char *message;\n} hint_cb_ctx_t;\n\nstatic const char *test_hint_cb(void *context)\n{\n    hint_cb_ctx_t *ctx = (hint_cb_ctx_t *)context;\n    return ctx->message;\n}\n\nstatic const char *test_glossary_cb(void *context)\n{\n    hint_cb_ctx_t *ctx = (hint_cb_ctx_t *)context;\n    return ctx->message;\n}\n\nTEST_CASE(\"test hint and glossary callbacks\", \"[esp_cli_commands]\")\n{\n    test_setup();\n\n    hint_cb_ctx_t ctx_a = { .message = \"msg_a\" };\n    hint_cb_ctx_t ctx_b = { .message = \"msg_b\" };\n\n    esp_cli_command_t cmd_a = {\n        .name = \"dyn_cmd_a\",\n        .group = \"dyn_cmd_group\",\n        .help = \"dummy help\",\n        .func = dummy_cmd_func,\n        .func_ctx = &ctx_a,\n        .hint_cb = test_hint_cb,\n        .glossary_cb = test_glossary_cb\n    };\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_register_cmd(&cmd_a));\n\n    esp_cli_command_t cmd_b = {\n        .name = \"dyn_cmd_b\",\n        .group = \"dyn_cmd_group\",\n        .help = \"dummy help\",\n        .func = dummy_cmd_func,\n        .func_ctx = &ctx_b,\n        .hint_cb = test_hint_cb,\n        .glossary_cb = test_glossary_cb\n    };\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_register_cmd(&cmd_b));\n\n    bool bold = true;\n    int color = 0;\n    const char *dyn_cmd_a_msg_hint = esp_cli_commands_get_hint(NULL, \"dyn_cmd_a\", &color, &bold);\n    TEST_ASSERT_EQUAL(0, strcmp(dyn_cmd_a_msg_hint, ctx_a.message));\n    TEST_ASSERT_EQUAL(false, bold); /* bold set a false by default in the component config */\n    TEST_ASSERT_EQUAL(39, color); /* color set to 39 by default in the component config */\n\n    const char *dyn_cmd_b_msg_hint = esp_cli_commands_get_hint(NULL, \"dyn_cmd_b\", &color, &bold);\n    TEST_ASSERT_EQUAL(0, strcmp(dyn_cmd_b_msg_hint, ctx_b.message));\n\n    const char *dyn_cmd_a_msg_glossary = esp_cli_commands_get_glossary(NULL, \"dyn_cmd_a\");\n    TEST_ASSERT_EQUAL(0, strcmp(dyn_cmd_a_msg_glossary, ctx_a.message));\n\n    const char *dyn_cmd_b_msg_glossary = esp_cli_commands_get_glossary(NULL, \"dyn_cmd_b\");\n    TEST_ASSERT_EQUAL(0, strcmp(dyn_cmd_b_msg_glossary, ctx_b.message));\n\n    /* create a set with only dyn_cmd_a and check that the hint cb is called for\n     * dyn_cmd_a but not for dyn_cmd_b */\n    const char *set[] = {\"dyn_cmd_a\"};\n    esp_cli_command_set_handle_t handle_set = ESP_CLI_COMMANDS_CREATE_CMD_SET(set, ESP_CLI_COMMAND_FIELD_ACCESSOR(name));\n    TEST_ASSERT_NOT_NULL(handle_set);\n\n    const char *dyn_cmd_a_msg_hint_bis = esp_cli_commands_get_hint(handle_set, \"dyn_cmd_a\", &color, &bold);\n    TEST_ASSERT_EQUAL(0, strcmp(dyn_cmd_a_msg_hint_bis, ctx_a.message));\n\n    const char *dyn_cmd_b_msg_hint_bis = esp_cli_commands_get_hint(handle_set, \"dyn_cmd_b\", &color, &bold);\n    TEST_ASSERT_NULL(dyn_cmd_b_msg_hint_bis);\n\n    const char *dyn_cmd_a_msg_glossary_bis = esp_cli_commands_get_glossary(handle_set, \"dyn_cmd_a\");\n    TEST_ASSERT_EQUAL(0, strcmp(dyn_cmd_a_msg_glossary_bis, ctx_a.message));\n\n    const char *dyn_cmd_b_msg_glossary_bis = esp_cli_commands_get_glossary(handle_set, \"dyn_cmd_b\");\n    TEST_ASSERT_NULL(dyn_cmd_b_msg_glossary_bis);\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_unregister_cmd(\"dyn_cmd_a\"));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_cli_commands_unregister_cmd(\"dyn_cmd_b\"));\n\n    esp_cli_commands_destroy_cmd_set(&handle_set);\n}\n"
  },
  {
    "path": "esp_cli_commands/test_apps/main/test_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"unity.h\"\n#include \"unity_test_runner.h\"\n#include \"esp_heap_caps.h\"\n#include \"unity_test_utils_memory.h\"\n\nvoid setUp(void)\n{\n    unity_utils_record_free_mem();\n}\n\nvoid tearDown(void)\n{\n    unity_utils_evaluate_leaks_direct(0);\n}\n\nvoid app_main(void)\n{\n    printf(\"Running esp_cli_commands component tests\\n\");\n    unity_run_menu();\n}\n"
  },
  {
    "path": "esp_cli_commands/test_apps/pytest_esp_cli_commands.py",
    "content": "import pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.utils import idf_parametrize\nimport glob\nfrom pathlib import Path\n\n\n@pytest.mark.host_test\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that did not build\"\n)\n@idf_parametrize('target', ['linux', 'esp32'], indirect=['target'])\ndef test_esp_cli_commands(dut) -> None:\n    dut.run_all_single_board_cases()\n"
  },
  {
    "path": "esp_cli_commands/test_apps/sdkconfig.defaults",
    "content": "CONFIG_ESP_TASK_WDT_EN=n"
  },
  {
    "path": "esp_daylight/.build-test-rules.yml",
    "content": "# Build and test rules for esp_daylight component\n# This file can be empty - the component will be built with default rules\n"
  },
  {
    "path": "esp_daylight/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to the ESP Daylight component will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## [1.0.1] - 2025-09-10\n\nMoved from esp-rainmaker to idf-extra-components\n\n## Added\n- Unit test suite and example application\n\n## [1.0.0] - 2025-09-09\n\n### Added\n- Initial release of ESP Daylight component\n- NOAA Solar Calculator implementation for sunrise/sunset calculations.\n  Reference: https://gml.noaa.gov/grad/solcalc/\n- Support for global locations including polar regions\n- Time offset functionality for scheduling applications\n"
  },
  {
    "path": "esp_daylight/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"src/esp_daylight.c\"\n                       INCLUDE_DIRS \"include\"\n                       REQUIRES \"esp_common\")\n"
  },
  {
    "path": "esp_daylight/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "esp_daylight/README.md",
    "content": "# ESP Daylight Component\n\nA standalone C library for calculating sunrise and sunset times using NOAA Solar Calculator equations. This component provides accurate solar calculations for any location and date, designed for integration with ESP-IDF projects.\n\n## Features\n\n- **Accurate NOAA calculations**: Uses proven NOAA Solar Calculator equations\n- **Global coverage**: Works for any location worldwide (handles polar regions)\n- **Lightweight**: Minimal memory footprint and dependencies\n- **ESP-IDF ready**: Designed for embedded systems\n- **Time zone agnostic**: Returns UTC timestamps for easy conversion\n\n## API Reference\n\n### Core Functions\n\n```c\nbool esp_daylight_calc_sunrise_sunset_utc(int year, int month, int day,\n                                          double latitude, double longitude,\n                                          time_t *sunrise_utc, time_t *sunset_utc);\n```\n\nCalculate sunrise and sunset times for a specific date and location.\n\n**Parameters:**\n- `year`: Year (e.g., 2024)\n- `month`: Month (1-12)\n- `day`: Day of month (1-31)\n- `latitude`: Latitude in decimal degrees (-90 to +90, positive North)\n- `longitude`: Longitude in decimal degrees (-180 to +180, positive East)\n- `sunrise_utc`: Output sunrise time as UTC timestamp\n- `sunset_utc`: Output sunset time as UTC timestamp\n\n**Returns:** `true` on success, `false` if sun doesn't rise/set (polar regions)\n\n### Helper Functions\n\n```c\ntime_t esp_daylight_apply_offset(time_t base_time, int offset_minutes);\n```\n\nApply time offset to a base timestamp.\n\n```c\nbool esp_daylight_get_sunrise_today(const esp_daylight_location_t *location, time_t *sunrise_utc);\nbool esp_daylight_get_sunset_today(const esp_daylight_location_t *location, time_t *sunset_utc);\n```\n\nGet sunrise/sunset for current date at given location.\n\n## Usage Example\n\n```c\n#include \"esp_daylight.h\"\n\nvoid calculate_solar_times(void) {\n    time_t sunrise_utc, sunset_utc;\n\n    // Calculate for Pune, India on August 29, 2025\n    bool ok = esp_daylight_calc_sunrise_sunset_utc(\n        2025, 8, 29,           // Date\n        18.5204, 73.8567,      // Pune coordinates\n        &sunrise_utc, &sunset_utc\n    );\n\n    if (ok) {\n        // Apply offset: 30 minutes before sunset\n        time_t light_on_time = esp_daylight_apply_offset(sunset_utc, -30);\n\n        struct tm *tm_info = gmtime(&light_on_time);\n        printf(\"Turn on light at: %02d:%02d:%02d UTC\\n\",\n               tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec);\n    } else {\n        printf(\"No sunrise/sunset for this location and date\\n\");\n    }\n}\n```\n\n## Location Coordinates\n\n### Popular Cities\n\n| City | Latitude | Longitude |\n|------|----------|-----------|\n| New York | 40.7128 | -74.0060 |\n| London | 51.5074 | -0.1278 |\n| Pune | 18.5204 | 73.8567 |\n| Shanghai | 31.2304 | 121.4737 |\n| Sydney | -33.8688 | 151.2093 |\n\n### Coordinate Format\n\n- **Latitude**: -90 to +90 degrees (positive = North, negative = South)\n- **Longitude**: -180 to +180 degrees (positive = East, negative = West)\n\n## Integration with ESP Schedule\n\nThis component integrates seamlessly with ESP Schedule for solar-based scheduling:\n\n```c\nesp_schedule_config_t schedule_config = {\n    .name = \"sunset_light\",\n    .trigger.type = ESP_SCHEDULE_TYPE_SUNSET,\n    .trigger.solar.latitude = 18.5204,\n    .trigger.solar.longitude = 73.8567,\n    .trigger.solar.offset_minutes = -30,  // 30 min before sunset\n    .trigger.solar.repeat_days = ESP_SCHEDULE_DAY_EVERYDAY,\n    .trigger_cb = light_control_callback,\n};\n```\n\n## Algorithm Details\n\nThe component implements the NOAA Solar Calculator algorithm with:\n\n- **Zenith angle**: 90.833° (accounts for atmospheric refraction)\n- **Precision**: Typically accurate to within 1-2 minutes\n- **Edge cases**: Handles polar day/night conditions gracefully\n\n## Dependencies\n\n- ESP-IDF (esp_common)\n- Standard C math library (`-lm`)\n\n## Component Structure\n\n```\nesp_daylight/\n├── CMakeLists.txt\n├── include/\n│   └── esp_daylight.h\n├── src/\n│   └── esp_daylight.c\n└── README.md\n```\n"
  },
  {
    "path": "esp_daylight/examples/get_started/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(esp_daylight_example)\n\n"
  },
  {
    "path": "esp_daylight/examples/get_started/README.md",
    "content": "# ESP Daylight Example\n\nThis example demonstrates how to use the ESP Daylight component to calculate sunrise and sunset times for various locations around the world.\n\n## What This Example Does\n\nThe example showcases several key features of the ESP Daylight component:\n\n1. **Basic Calculations**: Calculate sunrise/sunset for multiple cities worldwide\n2. **Seasonal Variations**: Show how daylight hours change throughout the year\n3. **Time Offsets**: Demonstrate scheduling events relative to sunrise/sunset\n4. **Polar Regions**: Handle special cases like midnight sun and polar night\n5. **Practical Scheduling**: Real-world smart home lighting automation example\n\n## How to Use\n\n### Build and Flash\n\nCreate the example project:\n\n```bash\nidf.py create-project-from-example \"espressif/esp_daylight:get_started\"\ncd get_started\nidf.py set-target esp32\nidf.py build flash monitor\n```\n\nAlternatively, if you have the component source locally:\n\n```bash\ncd examples/get_started\nidf.py set-target esp32\nidf.py build flash monitor\n```\n\n### Expected Output\n\nThe example will display sunrise and sunset times for various locations and demonstrate different use cases:\n\n```\nESP Daylight Component Example\n============================\n\n=== Basic Sunrise/Sunset Calculation ===\nCalculating sunrise/sunset for 2025-08-29:\n\nNew York, USA       : Sunrise 10:12:34 UTC, Sunset 23:45:12 UTC (Daylight: 13:32)\nLondon, UK          : Sunrise 05:23:45 UTC, Sunset 19:34:56 UTC (Daylight: 14:11)\nPune, India         : Sunrise 01:15:23 UTC, Sunset 13:02:45 UTC (Daylight: 11:47)\n...\n```\n\n## Key Locations Tested\n\nThe example includes calculations for these major cities:\n- New York, USA (40.7128°N, 74.0060°W)\n- London, UK (51.5074°N, 0.1278°W)\n- Pune, India (18.5204°N, 73.8567°E)\n- Shanghai, China (31.2304°N, 121.4737°E)\n- Sydney, Australia (33.8688°S, 151.2093°E)\n- Moscow, Russia (55.7558°N, 37.6173°E)\n- Tokyo, Japan (35.6762°N, 139.6503°E)\n- Rio de Janeiro, Brazil (22.9068°S, 43.1729°W)\n\n## Customization\n\n### Change Location\n\nModify the coordinates in the code to match your location:\n\n```c\nesp_daylight_location_t my_location = {\n    .latitude = YOUR_LATITUDE,\n    .longitude = YOUR_LONGITUDE,\n    .name = \"My Location\"\n};\n```\n\n### Change Date\n\nUpdate the date parameters in the calculation functions:\n\n```c\nint year = 2025, month = 8, day = 29;  // Change to your desired date\n```\n\n### Add Time Zone Support\n\nThe component returns UTC timestamps. To display local time, you can convert using standard C library functions or ESP-IDF timezone support.\n\n## Integration with Scheduling\n\nThe example shows how to integrate with scheduling systems:\n\n```c\n// Calculate sunset time\ntime_t sunset_utc;\nesp_daylight_calc_sunrise_sunset_utc(2025, 8, 29, lat, lon, NULL, &sunset_utc);\n\n// Schedule event 30 minutes before sunset\ntime_t light_on_time = esp_daylight_apply_offset(sunset_utc, -30);\n\n// Use with ESP Schedule component (if available)\nesp_schedule_config_t config = {\n    .trigger.type = ESP_SCHEDULE_TYPE_SUNSET,\n    .trigger.solar.latitude = lat,\n    .trigger.solar.longitude = lon,\n    .trigger.solar.offset_minutes = -30,\n    .callback = your_callback_function\n};\n```\n\n## Troubleshooting\n\n### No Output for Polar Regions\n\nIf you see \"No sunrise/sunset\" messages, this is normal for polar regions during certain times of year (midnight sun in summer, polar night in winter).\n\n### Accuracy\n\nThe calculations use NOAA Solar Calculator equations and are typically accurate to within 1-2 minutes for most locations.\n\n## Next Steps\n\n- Modify coordinates for your specific location\n- Integrate with your IoT scheduling system\n- Add timezone conversion for local time display\n- Implement automated device control based on solar events\n- Create recurring schedules that automatically adjust throughout the year\n\n"
  },
  {
    "path": "esp_daylight/examples/get_started/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"esp_daylight_example_main.c\"\n                       INCLUDE_DIRS \".\")\n\n"
  },
  {
    "path": "esp_daylight/examples/get_started/main/esp_daylight_example_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n\n#include <stdio.h>\n#include <time.h>\n#include <string.h>\n#include \"esp_log.h\"\n#include \"esp_daylight.h\"\n\nstatic const char *TAG = \"esp_daylight_example\";\n\n/* Example locations around the world */\nstatic const esp_daylight_location_t example_locations[] = {\n    {40.7128, -74.0060, \"New York, USA\"},\n    {51.5074, -0.1278, \"London, UK\"},\n    {18.5204, 73.8567, \"Pune, India\"},\n    {31.2304, 121.4737, \"Shanghai, China\"},\n    {-33.8688, 151.2093, \"Sydney, Australia\"},\n    {55.7558, 37.6173, \"Moscow, Russia\"},\n    {35.6762, 139.6503, \"Tokyo, Japan\"},\n    {-22.9068, -43.1729, \"Rio de Janeiro, Brazil\"}\n};\n\nstatic const size_t num_locations = sizeof(example_locations) / sizeof(example_locations[0]);\n\n/* Helper function to format time as string */\nstatic void format_time_string(time_t timestamp, char *buffer, size_t buffer_size)\n{\n    struct tm *time_info = gmtime(&timestamp);\n    strftime(buffer, buffer_size, \"%H:%M:%S UTC\", time_info);\n}\n\n/* Helper function to calculate and display daylight duration */\nstatic void display_daylight_info(const esp_daylight_location_t *location,\n                                  int year, int month, int day)\n{\n    time_t sunrise_utc, sunset_utc;\n    char sunrise_str[32], sunset_str[32];\n\n    bool result = esp_daylight_calc_sunrise_sunset_location(\n                      year, month, day, location, &sunrise_utc, &sunset_utc\n                  );\n\n    if (result) {\n        format_time_string(sunrise_utc, sunrise_str, sizeof(sunrise_str));\n        format_time_string(sunset_utc, sunset_str, sizeof(sunset_str));\n\n        /* Calculate daylight duration */\n        int daylight_seconds = (int)(sunset_utc - sunrise_utc);\n\n        /* Handle day boundary crossing (sunset next day) */\n        if (daylight_seconds < 0) {\n            daylight_seconds += 24 * 60 * 60; /* Add 24 hours */\n        }\n\n        int daylight_minutes = daylight_seconds / 60;\n        int hours = daylight_minutes / 60;\n        int minutes = daylight_minutes % 60;\n\n        ESP_LOGI(TAG, \"%-20s: Sunrise %s, Sunset %s (Daylight: %02d:%02d)\",\n                 location->name, sunrise_str, sunset_str, hours, minutes);\n    } else {\n        ESP_LOGI(TAG, \"%-20s: No sunrise/sunset (polar day/night)\", location->name);\n    }\n}\n\n/* Demonstrate basic sunrise/sunset calculation */\nstatic void example_basic_calculation(void)\n{\n    ESP_LOGI(TAG, \"=== Basic Sunrise/Sunset Calculation ===\");\n\n    /* Calculate for today's date (example: August 29, 2025) */\n    int year = 2025, month = 8, day = 29;\n\n    ESP_LOGI(TAG, \"Calculating sunrise/sunset for %04d-%02d-%02d:\", year, month, day);\n    ESP_LOGI(TAG, \"\");\n\n    for (size_t i = 0; i < num_locations; i++) {\n        display_daylight_info(&example_locations[i], year, month, day);\n    }\n    ESP_LOGI(TAG, \"\");\n}\n\n/* Demonstrate seasonal variations */\nstatic void example_seasonal_variations(void)\n{\n    ESP_LOGI(TAG, \"=== Seasonal Variations Example ===\");\n\n    /* Use London as example location */\n    const esp_daylight_location_t *london = &example_locations[1];\n\n    /* Test different seasons */\n    struct {\n        int month, day;\n        const char *season;\n    } seasons[] = {\n        {3, 21, \"Spring Equinox\"},\n        {6, 21, \"Summer Solstice\"},\n        {9, 23, \"Autumn Equinox\"},\n        {12, 21, \"Winter Solstice\"}\n    };\n\n    ESP_LOGI(TAG, \"Seasonal daylight variations in %s (2025):\", london->name);\n    ESP_LOGI(TAG, \"\");\n\n    for (size_t i = 0; i < 4; i++) {\n        ESP_LOGI(TAG, \"%s (%02d-%02d):\", seasons[i].season, seasons[i].month, seasons[i].day);\n        display_daylight_info(london, 2025, seasons[i].month, seasons[i].day);\n        ESP_LOGI(TAG, \"\");\n    }\n}\n\n/* Demonstrate time offset functionality */\nstatic void example_time_offsets(void)\n{\n    ESP_LOGI(TAG, \"=== Time Offset Example ===\");\n\n    /* Use Pune as example */\n    const esp_daylight_location_t *pune = &example_locations[2];\n    time_t sunrise_utc, sunset_utc;\n\n    bool result = esp_daylight_calc_sunrise_sunset_location(\n                      2025, 8, 29, pune, &sunrise_utc, &sunset_utc\n                  );\n\n    if (result) {\n        char time_str[32];\n\n        ESP_LOGI(TAG, \"Original times for %s:\", pune->name);\n        format_time_string(sunrise_utc, time_str, sizeof(time_str));\n        ESP_LOGI(TAG, \"  Sunrise: %s\", time_str);\n        format_time_string(sunset_utc, time_str, sizeof(time_str));\n        ESP_LOGI(TAG, \"  Sunset:  %s\", time_str);\n        ESP_LOGI(TAG, \"\");\n\n        /* Apply various offsets */\n        struct {\n            int offset_minutes;\n            const char *description;\n        } offsets[] = {\n            {-30, \"30 minutes before sunset (lights on)\"},\n            {30, \"30 minutes after sunrise (morning routine)\"},\n            {-60, \"1 hour before sunset (dinner prep)\"},\n            {15, \"15 minutes after sunrise (wake up)\"}\n        };\n\n        ESP_LOGI(TAG, \"Time offset examples:\");\n        for (size_t i = 0; i < 4; i++) {\n            time_t base_time = (i % 2 == 0) ? sunset_utc : sunrise_utc;\n            time_t offset_time = esp_daylight_apply_offset(base_time, offsets[i].offset_minutes);\n\n            format_time_string(offset_time, time_str, sizeof(time_str));\n            ESP_LOGI(TAG, \"  %s: %s\", offsets[i].description, time_str);\n        }\n        ESP_LOGI(TAG, \"\");\n    }\n}\n\n/* Demonstrate polar region handling */\nstatic void example_polar_regions(void)\n{\n    ESP_LOGI(TAG, \"=== Polar Region Example ===\");\n\n    /* Test Arctic locations */\n    esp_daylight_location_t arctic_locations[] = {\n        {71.0, 8.0, \"Svalbard, Norway\"},\n        {80.0, 0.0, \"High Arctic\"},\n        {-77.8, 166.7, \"McMurdo, Antarctica\"}\n    };\n\n    /* Test summer and winter conditions */\n    struct {\n        int month, day;\n        const char *season;\n    } polar_seasons[] = {\n        {6, 21, \"Summer (Midnight Sun)\"},\n        {12, 21, \"Winter (Polar Night)\"}\n    };\n\n    for (size_t s = 0; s < 2; s++) {\n        ESP_LOGI(TAG, \"%s conditions:\", polar_seasons[s].season);\n\n        for (size_t i = 0; i < 3; i++) {\n            time_t sunrise_utc, sunset_utc;\n            bool result = esp_daylight_calc_sunrise_sunset_location(\n                              2025, polar_seasons[s].month, polar_seasons[s].day,\n                              &arctic_locations[i], &sunrise_utc, &sunset_utc\n                          );\n\n            if (result) {\n                char sunrise_str[32], sunset_str[32];\n                format_time_string(sunrise_utc, sunrise_str, sizeof(sunrise_str));\n                format_time_string(sunset_utc, sunset_str, sizeof(sunset_str));\n                ESP_LOGI(TAG, \"  %-20s: Sunrise %s, Sunset %s\",\n                         arctic_locations[i].name, sunrise_str, sunset_str);\n            } else {\n                ESP_LOGI(TAG, \"  %-20s: No sunrise/sunset (24h %s)\",\n                         arctic_locations[i].name,\n                         (polar_seasons[s].month == 6) ? \"daylight\" : \"darkness\");\n            }\n        }\n        ESP_LOGI(TAG, \"\");\n    }\n}\n\n/* Demonstrate practical scheduling use case */\nstatic void example_practical_scheduling(void)\n{\n    ESP_LOGI(TAG, \"=== Practical Scheduling Example ===\");\n\n    /* Simulate a smart home lighting system */\n    const esp_daylight_location_t *home_location = &example_locations[2]; /* Pune */\n    time_t sunrise_utc, sunset_utc;\n\n    bool result = esp_daylight_calc_sunrise_sunset_location(\n                      2025, 8, 29, home_location, &sunrise_utc, &sunset_utc\n                  );\n\n    if (result) {\n        ESP_LOGI(TAG, \"Smart Home Lighting Schedule for %s:\", home_location->name);\n        ESP_LOGI(TAG, \"\");\n\n        /* Define lighting events */\n        struct {\n            time_t event_time;\n            const char *action;\n            const char *description;\n        } lighting_events[6];\n\n        /* Calculate event times */\n        lighting_events[0].event_time = esp_daylight_apply_offset(sunrise_utc, -30);\n        lighting_events[0].action = \"Turn OFF\";\n        lighting_events[0].description = \"30 min before sunrise\";\n\n        lighting_events[1].event_time = sunrise_utc;\n        lighting_events[1].action = \"Dim to 20%\";\n        lighting_events[1].description = \"At sunrise\";\n\n        lighting_events[2].event_time = esp_daylight_apply_offset(sunrise_utc, 60);\n        lighting_events[2].action = \"Turn OFF\";\n        lighting_events[2].description = \"1 hour after sunrise\";\n\n        lighting_events[3].event_time = esp_daylight_apply_offset(sunset_utc, -45);\n        lighting_events[3].action = \"Turn ON 50%\";\n        lighting_events[3].description = \"45 min before sunset\";\n\n        lighting_events[4].event_time = sunset_utc;\n        lighting_events[4].action = \"Turn ON 80%\";\n        lighting_events[4].description = \"At sunset\";\n\n        lighting_events[5].event_time = esp_daylight_apply_offset(sunset_utc, 120);\n        lighting_events[5].action = \"Turn ON 100%\";\n        lighting_events[5].description = \"2 hours after sunset\";\n\n        /* Display schedule */\n        for (size_t i = 0; i < 6; i++) {\n            char time_str[32];\n            format_time_string(lighting_events[i].event_time, time_str, sizeof(time_str));\n            ESP_LOGI(TAG, \"  %s - %-15s (%s)\",\n                     time_str, lighting_events[i].action, lighting_events[i].description);\n        }\n        ESP_LOGI(TAG, \"\");\n\n        /* Show integration with scheduling system */\n        ESP_LOGI(TAG, \"Integration with ESP Schedule:\");\n        ESP_LOGI(TAG, \"  esp_schedule_config_t config = {\");\n        ESP_LOGI(TAG, \"      .name = \\\"smart_lighting\\\",\");\n        ESP_LOGI(TAG, \"      .trigger.type = ESP_SCHEDULE_TYPE_SUNSET,\");\n        ESP_LOGI(TAG, \"      .trigger.solar.latitude = %.4f,\", home_location->latitude);\n        ESP_LOGI(TAG, \"      .trigger.solar.longitude = %.4f,\", home_location->longitude);\n        ESP_LOGI(TAG, \"      .trigger.solar.offset_minutes = -45,\");\n        ESP_LOGI(TAG, \"      .trigger_cb = lighting_control_callback,\");\n        ESP_LOGI(TAG, \"      .timestamp_cb = schedule_timestamp_callback\");\n        ESP_LOGI(TAG, \"  };\");\n        ESP_LOGI(TAG, \"  esp_schedule_handle_t handle = esp_schedule_create(&config);\");\n        ESP_LOGI(TAG, \"  esp_schedule_enable(handle);\");\n        ESP_LOGI(TAG, \"\");\n        // Note: The above is a demonstration of how to configure the schedule.\n        // Actual integration would require the esp_schedule component and real callback implementations.\n    }\n}\n\nvoid app_main(void)\n{\n    ESP_LOGI(TAG, \"ESP Daylight Component Example\");\n    ESP_LOGI(TAG, \"============================\");\n    ESP_LOGI(TAG, \"\");\n\n    /* Run all examples */\n    example_basic_calculation();\n    example_seasonal_variations();\n    example_time_offsets();\n    example_polar_regions();\n    example_practical_scheduling();\n\n    ESP_LOGI(TAG, \"Example completed successfully!\");\n    ESP_LOGI(TAG, \"\");\n    ESP_LOGI(TAG, \"Next steps:\");\n    ESP_LOGI(TAG, \"- Modify coordinates to match your location\");\n    ESP_LOGI(TAG, \"- Integrate with your scheduling system\");\n    ESP_LOGI(TAG, \"- Add timezone conversion for local time display\");\n    ESP_LOGI(TAG, \"- Implement automated lighting/irrigation control\");\n}\n"
  },
  {
    "path": "esp_daylight/examples/get_started/main/idf_component.yml",
    "content": "dependencies:\n  esp_daylight:\n    override_path: \"../../..\"\n\n"
  },
  {
    "path": "esp_daylight/examples/get_started/pytest_esp_daylight_example.py",
    "content": "#!/usr/bin/env python3\n# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n\nimport pytest\nfrom pytest_embedded import Dut\n\n\n@pytest.mark.generic\ndef test_esp_daylight_example(dut: Dut) -> None:\n    \"\"\"\n    Test esp_daylight example application\n    \"\"\"\n    # Wait for the example to start\n    dut.expect_exact('ESP Daylight Component Example')\n\n    # Check that basic calculations are performed\n    dut.expect('Basic Sunrise/Sunset Calculation', timeout=30)\n    dut.expect('New York, USA', timeout=10)\n    dut.expect('London, UK', timeout=10)\n    dut.expect('Pune, India', timeout=10)\n\n    # Check seasonal variations\n    dut.expect('Seasonal Variations Example', timeout=10)\n    dut.expect('Spring Equinox', timeout=10)\n    dut.expect('Summer Solstice', timeout=10)\n\n    # Check time offsets\n    dut.expect('Time Offset Example', timeout=10)\n    dut.expect('30 minutes before sunset', timeout=10)\n\n    # Check polar regions\n    dut.expect('Polar Region Example', timeout=10)\n    dut.expect('Midnight Sun', timeout=10)\n\n    # Check practical scheduling\n    dut.expect('Practical Scheduling Example', timeout=10)\n    dut.expect('Smart Home Lighting Schedule', timeout=10)\n\n    # Wait for completion\n    dut.expect('Example completed successfully!', timeout=30)\n\n"
  },
  {
    "path": "esp_daylight/idf_component.yml",
    "content": "## IDF Component Manager Manifest File\nversion: \"1.0.1\"\ndescription: NOAA-based sunrise/sunset calculation library for ESP-IDF\nurl: https://github.com/espressif/idf-extra-components/tree/master/esp_daylight\ndependencies:\n  idf: \">=5.1\"\n"
  },
  {
    "path": "esp_daylight/include/esp_daylight.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <time.h>\n\n/**\n * @brief Location information for daylight calculations\n */\ntypedef struct {\n    double latitude;        /**< Latitude in decimal degrees (-90 to +90, positive North) */\n    double longitude;       /**< Longitude in decimal degrees (-180 to +180, positive East) */\n    char name[32];         /**< Optional location name for reference */\n} esp_daylight_location_t;\n\n/**\n * @brief Calculate sunrise and sunset times for a given date and location\n *\n * Uses NOAA Solar Calculator equations with zenith angle of 90.833° for\n * geometric sunrise/sunset including atmospheric refraction.\n *\n * @param[in] year Year (e.g., 2024)\n * @param[in] month Month (1-12)\n * @param[in] day Day of month (1-31)\n * @param[in] latitude Latitude in decimal degrees (-90 to +90, positive North)\n * @param[in] longitude Longitude in decimal degrees (-180 to +180, positive East)\n * @param[out] sunrise_utc Sunrise time as UTC timestamp (seconds since epoch)\n * @param[out] sunset_utc Sunset time as UTC timestamp (seconds since epoch)\n *\n * @return true on success, false if sun doesn't rise/set (polar day/night)\n */\nbool esp_daylight_calc_sunrise_sunset_utc(int year, int month, int day,\n        double latitude, double longitude,\n        time_t *sunrise_utc, time_t *sunset_utc);\n\n/**\n * @brief Calculate sunrise and sunset times using location struct\n *\n * @param[in] year Year (e.g., 2024)\n * @param[in] month Month (1-12)\n * @param[in] day Day of month (1-31)\n * @param[in] location Location information\n * @param[out] sunrise_utc Sunrise time as UTC timestamp\n * @param[out] sunset_utc Sunset time as UTC timestamp\n *\n * @return true on success, false if sun doesn't rise/set (polar day/night)\n */\nbool esp_daylight_calc_sunrise_sunset_location(int year, int month, int day,\n        const esp_daylight_location_t *location,\n        time_t *sunrise_utc, time_t *sunset_utc);\n\n/**\n * @brief Apply time offset to a base timestamp\n *\n * @param[in] base_time Base timestamp in seconds since epoch\n * @param[in] offset_minutes Offset in minutes (positive = after, negative = before)\n *\n * @return Adjusted timestamp\n */\ntime_t esp_daylight_apply_offset(time_t base_time, int offset_minutes);\n\n/**\n * @brief Get sunrise time for current date at given location\n *\n * @param[in] location Location information\n * @param[out] sunrise_utc Sunrise time as UTC timestamp\n *\n * @return true on success, false on failure\n */\nbool esp_daylight_get_sunrise_today(const esp_daylight_location_t *location, time_t *sunrise_utc);\n\n/**\n * @brief Get sunset time for current date at given location\n *\n * @param[in] location Location information\n * @param[out] sunset_utc Sunset time as UTC timestamp\n *\n * @return true on success, false on failure\n */\nbool esp_daylight_get_sunset_today(const esp_daylight_location_t *location, time_t *sunset_utc);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_daylight/src/esp_daylight.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include <math.h>\n#include <time.h>\n#include \"esp_daylight.h\"\n\n#ifndef M_PI\n#define M_PI 3.14159265358979323846\n#endif\n\n/*\n * NOAA Solar Calculator Implementation\n * Reliable sunrise/sunset (UTC) calculations using NOAA equations\n * Reference: https://gml.noaa.gov/grad/solcalc/\n */\n\n/**\n * @brief Howard Hinnant's days_from_civil algorithm (public domain)\n * Convert civil date to days since Unix epoch\n */\nstatic int64_t days_from_civil(int y, unsigned m, unsigned d)\n{\n    y -= m <= 2;\n    const int era = (y >= 0 ? y : y - 399) / 400;\n    const unsigned yoe = (unsigned)(y - era * 400);                 // [0, 399]\n    const unsigned doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; // [0, 365]\n    const unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + yoe / 400 + doy; // [0, 146096]\n    return era * 146097 + (int)doe - 719468; // days since 1970-01-01\n}\n\n/**\n * @brief Get UTC midnight timestamp for given date\n */\nstatic time_t utc_midnight_epoch(int year, int month, int day)\n{\n    return (time_t)(days_from_civil(year, (unsigned)month, (unsigned)day) * 86400LL);\n}\n\n/**\n * @brief Clamp value between min and max\n */\nstatic double clamp(double v, double lo, double hi)\n{\n    return v < lo ? lo : (v > hi ? hi : v);\n}\n\n/**\n * @brief Calculate fractional year gamma in radians\n * Used for NOAA solar equations\n */\nstatic double fractional_year_gamma(int year, int month, int day)\n{\n    // Day-of-year N (1..365/366)\n    static const int mdays[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};\n    int ly = ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0));\n    int N = day;\n    for (int i = 1; i < month; i++) {\n        N += mdays[i];\n    }\n    if (ly && month > 2) {\n        N += 1;\n    }\n\n    // NOAA form with hour≈0 -> gamma ~= 2π/365 * (N-1 - 12/24)\n    return 2.0 * M_PI / (ly ? 366.0 : 365.0) * ((double)N - 1.0 - 0.5);\n}\n\n/**\n * @brief Calculate Equation of Time in minutes\n * NOAA polynomial approximation\n */\nstatic double equation_of_time_min(double gamma)\n{\n    double s  = sin(gamma);\n    double c  = cos(gamma);\n    double s2 = sin(2 * gamma);\n    double c2 = cos(2 * gamma);\n\n    // 229.18 * (0.000075 + 0.001868*cosγ - 0.032077*sinγ - 0.014615*cos2γ - 0.040849*sin2γ)\n    return 229.18 * (0.000075 + 0.001868 * c - 0.032077 * s - 0.014615 * c2 - 0.040849 * s2);\n}\n\n/**\n * @brief Calculate solar declination in radians\n * NOAA polynomial approximation\n */\nstatic double solar_declination_rad(double gamma)\n{\n    double s  = sin(gamma);\n    double c  = cos(gamma);\n    double s2 = sin(2 * gamma);\n    double c2 = cos(2 * gamma);\n    double s3 = sin(3 * gamma);\n    double c3 = cos(3 * gamma);\n\n    // δ = 0.006918 - 0.399912 cosγ + 0.070257 sinγ - 0.006758 cos2γ\n    //      + 0.000907 sin2γ - 0.002697 cos3γ + 0.00148 sin3γ\n    return 0.006918 - 0.399912 * c + 0.070257 * s - 0.006758 * c2\n           + 0.000907 * s2 - 0.002697 * c3 + 0.001480 * s3;\n}\n\nbool esp_daylight_calc_sunrise_sunset_utc(int year, int month, int day,\n        double latitude, double longitude,\n        time_t *sunrise_utc, time_t *sunset_utc)\n{\n    // Constants\n    const double ZENITH_DEG = 90.833; // geometric zenith for sunrise/sunset\n    const double Z = ZENITH_DEG * (M_PI / 180.0);\n    const double phi = latitude * (M_PI / 180.0);\n\n    // 1) Day parameters\n    double gamma = fractional_year_gamma(year, month, day);\n    double EoT_min = equation_of_time_min(gamma);\n    double decl = solar_declination_rad(gamma);\n\n    // 2) Hour angle at sunrise/sunset (rad)\n    // cos(H0) = (cos(Z) - sin(phi) sin(dec)) / (cos(phi) cos(dec))\n    double cosH0 = (cos(Z) - sin(phi) * sin(decl)) / (cos(phi) * cos(decl));\n\n    if (cosH0 < -1.0) {\n        // Sun above horizon all day (midnight sun) -> no distinct sunrise/sunset\n        return false;\n    }\n    if (cosH0 > 1.0) {\n        // Sun below horizon all day (polar night)\n        return false;\n    }\n\n    double H0 = acos(clamp(cosH0, -1.0, 1.0));     // radians\n    double H0_deg = H0 * 180.0 / M_PI;\n\n    // 3) Solar noon in UTC minutes\n    // NOAA: SolarNoon_UTC (minutes) = 720 - 4*longitude - EoT\n    // (longitude positive east, negative west)\n    double solar_noon_min_utc = 720.0 - 4.0 * longitude - EoT_min;\n\n    // 4) Sunrise/Sunset UTC minutes\n    // Daylength (minutes) = 8 * H0 (deg)   [since 1 deg hour angle = 4 minutes]\n    double delta_min = 4.0 * H0_deg; // minutes from noon to event\n    double sunrise_min_utc = solar_noon_min_utc - delta_min;\n    double sunset_min_utc  = solar_noon_min_utc + delta_min;\n\n    // Normalize to [0,1440) to stay within the same civil day in UTC.\n    // (Edge cases near poles can roll into prev/next day; we keep them bounded.)\n    while (sunrise_min_utc < 0) {\n        sunrise_min_utc += 1440.0;\n    }\n    while (sunrise_min_utc >= 1440.0) {\n        sunrise_min_utc -= 1440.0;\n    }\n    while (sunset_min_utc < 0) {\n        sunset_min_utc += 1440.0;\n    }\n    while (sunset_min_utc >= 1440.0) {\n        sunset_min_utc -= 1440.0;\n    }\n\n    // 5) Convert to epoch seconds (UTC)\n    time_t midnight_utc = utc_midnight_epoch(year, month, day);\n    if (sunrise_utc) {\n        *sunrise_utc = midnight_utc + (time_t)llround(sunrise_min_utc * 60.0);\n    }\n    if (sunset_utc) {\n        *sunset_utc  = midnight_utc + (time_t)llround(sunset_min_utc  * 60.0);\n    }\n\n    return true;\n}\n\nbool esp_daylight_calc_sunrise_sunset_location(int year, int month, int day,\n        const esp_daylight_location_t *location,\n        time_t *sunrise_utc, time_t *sunset_utc)\n{\n    if (!location) {\n        return false;\n    }\n\n    return esp_daylight_calc_sunrise_sunset_utc(year, month, day,\n            location->latitude, location->longitude,\n            sunrise_utc, sunset_utc);\n}\n\ntime_t esp_daylight_apply_offset(time_t base_time, int offset_minutes)\n{\n    return base_time + (offset_minutes * 60);\n}\n\nbool esp_daylight_get_sunrise_today(const esp_daylight_location_t *location, time_t *sunrise_utc)\n{\n    if (!location || !sunrise_utc) {\n        return false;\n    }\n\n    time_t now;\n    time(&now);\n    struct tm *tm_info = gmtime(&now);\n\n    return esp_daylight_calc_sunrise_sunset_location(\n               tm_info->tm_year + 1900,\n               tm_info->tm_mon + 1,\n               tm_info->tm_mday,\n               location,\n               sunrise_utc,\n               NULL\n           );\n}\n\nbool esp_daylight_get_sunset_today(const esp_daylight_location_t *location, time_t *sunset_utc)\n{\n    if (!location || !sunset_utc) {\n        return false;\n    }\n\n    time_t now;\n    time(&now);\n    struct tm *tm_info = gmtime(&now);\n\n    return esp_daylight_calc_sunrise_sunset_location(\n               tm_info->tm_year + 1900,\n               tm_info->tm_mon + 1,\n               tm_info->tm_mday,\n               location,\n               NULL,\n               sunset_utc\n           );\n}\n"
  },
  {
    "path": "esp_daylight/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nproject(esp_daylight_test)\n\n"
  },
  {
    "path": "esp_daylight/test_apps/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"test_app_main.c\"\n                            \"test_esp_daylight.c\"\n                       INCLUDE_DIRS \".\"\n                       PRIV_REQUIRES unity esp_daylight\n                       WHOLE_ARCHIVE)\n"
  },
  {
    "path": "esp_daylight/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  esp_daylight:\n    path: \"../..\"\n\n"
  },
  {
    "path": "esp_daylight/test_apps/main/test_app_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"unity.h\"\n#include \"unity_test_runner.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_newlib.h\"\n#include \"unity_test_utils_memory.h\"\n\nvoid setUp(void)\n{\n    unity_utils_record_free_mem();\n}\n\nvoid tearDown(void)\n{\n    esp_reent_cleanup();    /* clean up some of the newlib's lazy allocations */\n    unity_utils_evaluate_leaks_direct(50);\n}\n\nvoid app_main(void)\n{\n    printf(\"Running esp_daylight component tests\\n\");\n    unity_run_menu();\n}\n"
  },
  {
    "path": "esp_daylight/test_apps/main/test_esp_daylight.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <math.h>\n#include \"unity.h\"\n#include \"esp_log.h\"\n#include \"esp_daylight.h\"\n\nstatic const char *TAG = \"esp_daylight_test\";\n\n/* Test tolerance for time calculations (in seconds) */\n#define TIME_TOLERANCE_SEC 120  /* 2 minutes tolerance for sunrise/sunset calculations */\n\n/* Helper function to check if two timestamps are within tolerance */\n__attribute__((unused)) static bool time_within_tolerance(time_t actual, time_t expected, int tolerance_sec)\n{\n    int diff = abs((int)(actual - expected));\n    return diff <= tolerance_sec;\n}\n\nTEST_CASE(\"Test basic sunrise/sunset calculation\", \"[esp_daylight]\")\n{\n    time_t sunrise_utc, sunset_utc;\n    bool result;\n\n    /* Test for Pune, India on August 29, 2025 */\n    result = esp_daylight_calc_sunrise_sunset_utc(\n                 2025, 8, 29,           /* Date */\n                 18.5204, 73.8567,      /* Pune coordinates */\n                 &sunrise_utc, &sunset_utc\n             );\n\n    TEST_ASSERT_TRUE(result);\n    TEST_ASSERT_NOT_EQUAL(0, sunrise_utc);\n    TEST_ASSERT_NOT_EQUAL(0, sunset_utc);\n    /* Note: Don't assert sunset > sunrise due to potential day boundary crossing in UTC */\n\n    /* Convert to readable format for logging */\n    struct tm sunrise_tm_buf, sunset_tm_buf;\n    struct tm *sunrise_tm = gmtime_r(&sunrise_utc, &sunrise_tm_buf);\n    struct tm *sunset_tm = gmtime_r(&sunset_utc, &sunset_tm_buf);\n\n    ESP_LOGI(TAG, \"Pune 2025-08-29: Sunrise %02d:%02d UTC, Sunset %02d:%02d UTC\",\n             sunrise_tm->tm_hour, sunrise_tm->tm_min,\n             sunset_tm->tm_hour, sunset_tm->tm_min);\n\n    /* Sanity check: sunrise should be around 01:00 UTC (06:30 IST) */\n    /* sunset should be around 13:00 UTC (18:30 IST) */\n    TEST_ASSERT_TRUE(sunrise_tm->tm_hour >= 0 && sunrise_tm->tm_hour <= 3);\n    TEST_ASSERT_TRUE(sunset_tm->tm_hour >= 12 && sunset_tm->tm_hour <= 15);\n}\n\nTEST_CASE(\"Test location struct interface\", \"[esp_daylight]\")\n{\n    esp_daylight_location_t location = {\n        .latitude = 40.7128,\n        .longitude = -74.0060,\n        .name = \"New York\"\n    };\n\n    time_t sunrise_utc, sunset_utc;\n    bool result;\n\n    result = esp_daylight_calc_sunrise_sunset_location(\n                 2025, 6, 21,  /* Summer solstice */\n                 &location,\n                 &sunrise_utc, &sunset_utc\n             );\n\n    TEST_ASSERT_TRUE(result);\n    TEST_ASSERT_NOT_EQUAL(0, sunrise_utc);\n    TEST_ASSERT_NOT_EQUAL(0, sunset_utc);\n    TEST_ASSERT_GREATER_THAN(sunset_utc, sunrise_utc);\n\n    struct tm sunrise_tm_buf, sunset_tm_buf;\n    struct tm *sunrise_tm = gmtime_r(&sunrise_utc, &sunrise_tm_buf);\n    struct tm *sunset_tm = gmtime_r(&sunset_utc, &sunset_tm_buf);\n\n    ESP_LOGI(TAG, \"New York 2025-06-21: Sunrise %02d:%02d UTC, Sunset %02d:%02d UTC\",\n             sunrise_tm->tm_hour, sunrise_tm->tm_min,\n             sunset_tm->tm_hour, sunset_tm->tm_min);\n}\n\nTEST_CASE(\"Test polar regions - midnight sun\", \"[esp_daylight]\")\n{\n    time_t sunrise_utc, sunset_utc;\n    bool result;\n\n    /* Test Arctic location during summer (midnight sun) */\n    result = esp_daylight_calc_sunrise_sunset_utc(\n                 2025, 6, 21,           /* Summer solstice */\n                 80.0, 0.0,             /* High Arctic latitude */\n                 &sunrise_utc, &sunset_utc\n             );\n\n    /* Should return false for midnight sun conditions */\n    TEST_ASSERT_FALSE(result);\n    ESP_LOGI(TAG, \"Arctic midnight sun test: correctly returned false\");\n}\n\nTEST_CASE(\"Test polar regions - polar night\", \"[esp_daylight]\")\n{\n    time_t sunrise_utc, sunset_utc;\n    bool result;\n\n    /* Test Arctic location during winter (polar night) */\n    result = esp_daylight_calc_sunrise_sunset_utc(\n                 2025, 12, 21,          /* Winter solstice */\n                 80.0, 0.0,             /* High Arctic latitude */\n                 &sunrise_utc, &sunset_utc\n             );\n\n    /* Should return false for polar night conditions */\n    TEST_ASSERT_FALSE(result);\n    ESP_LOGI(TAG, \"Arctic polar night test: correctly returned false\");\n}\n\nTEST_CASE(\"Test time offset functionality\", \"[esp_daylight]\")\n{\n    time_t base_time = 1640995200; /* 2022-01-01 00:00:00 UTC */\n    time_t offset_time;\n\n    /* Test positive offset (30 minutes after) */\n    offset_time = esp_daylight_apply_offset(base_time, 30);\n    TEST_ASSERT_EQUAL(base_time + 1800, offset_time);\n\n    /* Test negative offset (45 minutes before) */\n    offset_time = esp_daylight_apply_offset(base_time, -45);\n    TEST_ASSERT_EQUAL(base_time - 2700, offset_time);\n\n    /* Test zero offset */\n    offset_time = esp_daylight_apply_offset(base_time, 0);\n    TEST_ASSERT_EQUAL(base_time, offset_time);\n\n    ESP_LOGI(TAG, \"Time offset tests passed\");\n}\n\nTEST_CASE(\"Test input validation\", \"[esp_daylight]\")\n{\n    time_t sunrise_utc, sunset_utc;\n\n    /* Test invalid date */\n    (void) esp_daylight_calc_sunrise_sunset_utc(\n        2025, 13, 1,           /* Invalid month */\n        18.5204, 73.8567,\n        &sunrise_utc, &sunset_utc\n    );\n    /* Implementation should handle this gracefully */\n\n    /* Test extreme latitudes */\n    (void) esp_daylight_calc_sunrise_sunset_utc(\n        2025, 6, 21,\n        91.0, 0.0,             /* Invalid latitude > 90 */\n        &sunrise_utc, &sunset_utc\n    );\n    /* Should handle gracefully */\n\n    /* Test extreme longitudes */\n    (void) esp_daylight_calc_sunrise_sunset_utc(\n        2025, 6, 21,\n        0.0, 181.0,            /* Invalid longitude > 180 */\n        &sunrise_utc, &sunset_utc\n    );\n    /* Should handle gracefully */\n\n    ESP_LOGI(TAG, \"Input validation tests completed\");\n}\n\nTEST_CASE(\"Test known reference values\", \"[esp_daylight]\")\n{\n    time_t sunrise_utc, sunset_utc;\n    bool result;\n\n    /* Test London on summer solstice 2025 */\n    result = esp_daylight_calc_sunrise_sunset_utc(\n                 2025, 6, 21,\n                 51.5074, -0.1278,      /* London coordinates */\n                 &sunrise_utc, &sunset_utc\n             );\n\n    TEST_ASSERT_TRUE(result);\n\n    struct tm sunrise_tm_buf, sunset_tm_buf;\n    struct tm *sunrise_tm = gmtime_r(&sunrise_utc, &sunrise_tm_buf);\n    struct tm *sunset_tm = gmtime_r(&sunset_utc, &sunset_tm_buf);\n\n    ESP_LOGI(TAG, \"London 2025-06-21: Sunrise %02d:%02d UTC, Sunset %02d:%02d UTC\",\n             sunrise_tm->tm_hour, sunrise_tm->tm_min,\n             sunset_tm->tm_hour, sunset_tm->tm_min);\n\n    /* London summer solstice: sunrise around 04:43 UTC, sunset around 20:21 UTC */\n    TEST_ASSERT_TRUE(sunrise_tm->tm_hour >= 3 && sunrise_tm->tm_hour <= 6);\n    TEST_ASSERT_TRUE(sunset_tm->tm_hour >= 19 && sunset_tm->tm_hour <= 22);\n}\n\nTEST_CASE(\"Test equatorial location\", \"[esp_daylight]\")\n{\n    time_t sunrise_utc, sunset_utc;\n    bool result;\n\n    /* Test Singapore (near equator) */\n    result = esp_daylight_calc_sunrise_sunset_utc(\n                 2025, 3, 21,           /* Equinox */\n                 1.3521, 103.8198,      /* Singapore coordinates */\n                 &sunrise_utc, &sunset_utc\n             );\n\n    TEST_ASSERT_TRUE(result);\n\n    struct tm sunrise_tm_buf, sunset_tm_buf;\n    struct tm *sunrise_tm = gmtime_r(&sunrise_utc, &sunrise_tm_buf);\n    struct tm *sunset_tm = gmtime_r(&sunset_utc, &sunset_tm_buf);\n\n    ESP_LOGI(TAG, \"Singapore 2025-03-21: Sunrise %02d:%02d UTC, Sunset %02d:%02d UTC\",\n             sunrise_tm->tm_hour, sunrise_tm->tm_min,\n             sunset_tm->tm_hour, sunset_tm->tm_min);\n\n    /* Near equator, day length should be close to 12 hours */\n    /* Handle day boundary crossing - if sunset appears before sunrise, add 24 hours */\n    int day_length_minutes;\n    if (sunset_utc >= sunrise_utc) {\n        day_length_minutes = (sunset_utc - sunrise_utc) / 60;\n    } else {\n        /* Day boundary crossing - sunset is next day */\n        day_length_minutes = ((sunset_utc + 24 * 3600) - sunrise_utc) / 60;\n    }\n    TEST_ASSERT_INT_WITHIN(30, 12 * 60, day_length_minutes); /* Within 30 minutes of 12 hours */\n}\n\nTEST_CASE(\"Test southern hemisphere\", \"[esp_daylight]\")\n{\n    time_t sunrise_utc, sunset_utc;\n    bool result;\n\n    /* Test Sydney, Australia */\n    result = esp_daylight_calc_sunrise_sunset_utc(\n                 2025, 12, 21,          /* Summer solstice in southern hemisphere */\n                 -33.8688, 151.2093,   /* Sydney coordinates */\n                 &sunrise_utc, &sunset_utc\n             );\n\n    TEST_ASSERT_TRUE(result);\n\n    struct tm sunrise_tm_buf, sunset_tm_buf;\n    struct tm *sunrise_tm = gmtime_r(&sunrise_utc, &sunrise_tm_buf);\n    struct tm *sunset_tm = gmtime_r(&sunset_utc, &sunset_tm_buf);\n\n    ESP_LOGI(TAG, \"Sydney 2025-12-21: Sunrise %02d:%02d UTC, Sunset %02d:%02d UTC\",\n             sunrise_tm->tm_hour, sunrise_tm->tm_min,\n             sunset_tm->tm_hour, sunset_tm->tm_min);\n\n    /* Should have valid sunrise/sunset times */\n    TEST_ASSERT_NOT_EQUAL(0, sunrise_utc);\n    TEST_ASSERT_NOT_EQUAL(0, sunset_utc);\n    TEST_ASSERT_GREATER_THAN(sunset_utc, sunrise_utc);\n}\n\nTEST_CASE(\"Test NULL pointer handling\", \"[esp_daylight]\")\n{\n    time_t sunrise_utc, sunset_utc;\n    bool result;\n\n    /* Test NULL location pointer */\n    result = esp_daylight_calc_sunrise_sunset_location(\n                 2025, 6, 21,\n                 NULL,\n                 &sunrise_utc, &sunset_utc\n             );\n    TEST_ASSERT_FALSE(result);\n\n    /* Test NULL output pointers (should not crash) */\n    (void) esp_daylight_calc_sunrise_sunset_utc(\n        2025, 6, 21,\n        0.0, 0.0,\n        NULL, NULL\n    );\n    /* Should handle gracefully */\n\n    ESP_LOGI(TAG, \"NULL pointer handling tests completed\");\n}\n"
  },
  {
    "path": "esp_daylight/test_apps/pytest_esp_daylight.py",
    "content": "#!/usr/bin/env python3\n# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n\nimport pytest\nfrom pytest_embedded import Dut\n\n\n@pytest.mark.generic\ndef test_esp_daylight(dut: Dut) -> None:\n    \"\"\"\n    Test esp_daylight component functionality\n    \"\"\"\n    dut.run_all_single_board_cases(timeout=60)\n\n"
  },
  {
    "path": "esp_daylight/test_apps/sdkconfig.defaults",
    "content": "# This file was generated using idf.py save-defconfig. It can be edited manually.\n# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration\n#\nCONFIG_ESP_TASK_WDT_INIT=n\n"
  },
  {
    "path": "esp_delta_ota/.build-test-rules.yml",
    "content": "esp_delta_ota/examples:\n  enable:\n    - if: IDF_TARGET == \"esp32\"\n      reason: Delta OTA example currently only tested on ESP32\n\nesp_delta_ota/test_apps:\n  enable:\n    - if: IDF_TARGET == \"esp32\"\n      reason: Delta OTA test app currently only tested on ESP32\n"
  },
  {
    "path": "esp_delta_ota/CHANGELOG.md",
    "content": "## 1.1.4\n\n### Enhancements:\n- Added support to pass user data to read callback with new callback function: `src_read_cb_with_user_ctx_t`\n\n## 1.1.3\n\n### Bugfixes:\n- Fixed `esp_delta_ota_patch_gen.py` patch generation, by ignoring the case in regex which is used to get validation hash of binary through esptool command, caused due to breaking change in esptool.\n\n## 1.1.2\n\n### Bugfixes:\n- Fixed `esp_delta_ota_patch_gen.py` python command for creating patch in README.md file of esp_delta_ota/https_delta_ota example.\n- Added `Verifying patch` section in the README.md and corresponding python command.\n\n## 1.1.1\n\n### Bugfixes:\n- Fixed issue causing `esp_delta_ota_patch_gen.py` to be non-functional on Windows OS.\n- Replaced earlier use of subprocess commands with direct `esptool` module import based method for handling ESP chip-specific operations across all platforms.\n- Replaced earlier use of subprocess commands with direct `detools` module import based method for creating and applying patches.\n\n## 1.1.0\n\n### Enhancements:\n- Added support to pass user data to write callback with new callback function: `merged_stream_write_cb_with_user_ctx_t`\n- The older write callback function: `merged_stream_write_cb_t` has been deprecated and will be removed in the next major release.\n"
  },
  {
    "path": "esp_delta_ota/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"src/esp_delta_ota.c\" \"detools/c/detools.c\" \"detools/c/heatshrink/heatshrink_decoder.c\"\n                       INCLUDE_DIRS \"include\" \n                       PRIV_INCLUDE_DIRS \"detools/c\" \"detools/c/heatshrink\")\n\ntarget_compile_options(${COMPONENT_LIB} PRIVATE \"-DDETOOLS_CONFIG_FILE_IO=0\")\ntarget_compile_options(${COMPONENT_LIB} PRIVATE \"-DDETOOLS_CONFIG_COMPRESSION_NONE=0\")\ntarget_compile_options(${COMPONENT_LIB} PRIVATE \"-DDETOOLS_CONFIG_COMPRESSION_LZMA=0\")\ntarget_compile_options(${COMPONENT_LIB} PRIVATE \"-DDETOOLS_CONFIG_COMPRESSION_CRLE=0\")\n"
  },
  {
    "path": "esp_delta_ota/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2020 Thesis projects\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "esp_delta_ota/README.md",
    "content": "# ESP Delta OTA\n\n## Getting Started\nCompressed Delta OTA Updates aims at enabling Over-the-Air firmware update with compressed delta binaries. \n\n### Compressed Delta Image for OTA\n![Image Format](https://raw.githubusercontent.com/espressif/idf-extra-components/master/esp_delta_ota/image_format.png)\n\n### Advantages of using this design for OTA update:\n* Patch file have smaller size than the original firmware file. This reduces the time and network usage to download the file from server.\n* No additional storage partition is required for the \"patch\".\n* Only firmware level changes are required for integrating this component. No bootloader related changes required.\n* This scheme can be implemented for the existing devices in the field.\n\n## Workflow Block diagram\n![ESP Delta OTA Block Diagram](https://raw.githubusercontent.com/espressif/idf-extra-components/master/esp_delta_ota/esp_delta_ota_block_diagram.png)\n\n## Prerequisites\n\n* **ESP-IDF v4.3 and above**\n\n  You can visit the [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html#installation-step-by-step) for the installation steps.\n\n* **detools v0.49.0 and above**\n\n  Binary delta encoding in Python 3.6+. You can install detools using the following command: \n  ```\n  pip install -r examples/https_delta_ota/tools/requirements.txt\n  ```\n  More information about the package [here](https://pypi.org/project/detools/).\n\n## Usage\n\nRefer to the [https_delta_ota](https://github.com/espressif/idf-extra-components/blob/master/esp_delta_ota/examples/https_delta_ota/) example to see the use of `esp_delta_ota` component for OTA updates.\n\n## API Reference\nTo learn more about how to use this component, please check API Documentation from header file [esp_delta_ota.h](https://github.com/espressif/idf-extra-components/blob/master/esp_delta_ota/include/esp_delta_ota.h)\n\n## License\n\n* Distributed under the Apache-2.0 License. Refer [esp_delta_ota LICENSE](https://github.com/espressif/idf-extra-components/blob/master/esp_delta_ota/LICENSE) for more information.\n* `detools` : Distributed under the BSD 2-Clause License. Refer [detools LICENSE](https://github.com/eerimoq/detools/blob/master/LICENSE) for more information.\n* `heatshrink` : Distributed under the ISC License. Refer [heatshrink LICENSE](https://github.com/eerimoq/detools/blob/master/c/heatshrink/README.rst) for more information.\n"
  },
  {
    "path": "esp_delta_ota/examples/https_delta_ota/CMakeLists.txt",
    "content": "# The following lines of boilerplate have to be in your project's CMakeLists\n# in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nproject(https_delta_ota)\n"
  },
  {
    "path": "esp_delta_ota/examples/https_delta_ota/README.md",
    "content": "# HTTPS Delta OTA\n\nCompressed Delta OTA Updates aims at enabling Over-the-Air firmware update with compressed delta binaries. Instead of the original binary to be hosted on the OTA update server, a patch file is hosted which is the difference between the base firmware and the new firmware in compressed form. This reduces the size of the file to be downloaded when performing OTA updates thus reducing the network usage. This also reduces the time taken to complete the OTA process.\n\nThis example demonstrates OTA updates with compressed patch binary using `esp_delta_ota` component's APIs and tool.\n\nCompressed patch generated for the new firmware must be hosted on OTA update server. See [How to generate the patch](#creating-patch).\n\nThis patch will be downloaded and then applied on the current running firmware on device. The new firmware after applying the patch will be written in a new partition.\n\n## ESP Delta OTA Abstraction Layer\n\nThis example uses `esp_delta_ota` component hosted at [idf-extra-components/esp_delta_ota](https://github.com/espressif/idf-extra-components/blob/master/esp_delta_ota) and available though the [IDF component manager](https://components.espressif.com/component/espressif/esp_delta_ota).\n\nPlease refer to its documentation [here](https://github.com/espressif/idf-extra-components/blob/master/esp_delta_ota/README.md) for more details.\n\n\n## How to use the example\n\n### Configure the project\nOpen the project configuration menu(`idf.py menuconfig`)\n\nIn the `Example Connection Configuration` menu:\n* Choose the network interface in the `Connect using` option based on your board. Currently both Wi-Fi and Ethernet are supported\n* If the Wi-Fi interface is used, provide the Wi-Fi SSID and password of the AP you wish to connect to\n* If using the Ethernet interface, set the PHY model under `Ethernet PHY Device` option, e.g. `IP101`\n\nIn the `Example Configuration` menu:\n* Set the URL of the firmware to download in the `Firmware Upgrade URL` option. The format should be `https://<host-ip-address>:<host-port>/<firmware-image-filename>`, e.g. `https://192.168.2.106:8070/hello_world.bin`\n\n### Build and Flash example\n\n```\nidf.py build flash\n```\n\n### Creating Patch\n\nNow we will consider this firmware as the base firmware which we will flash into the device. We need a new firmware to which we want to upgrade to. You can try building the `hello_world` example present in ESP-IDF.\nWe need to create a patch file for this new firmware.\n\nInstall required packages:\n```\npip install -r tools/requirements.txt\n```\n\nTo create a patch file, use the [python tool](./tools/esp_delta_ota_patch_gen.py)\n```\npython esp_delta_ota_patch_gen.py create_patch --chip <target> --base_binary <base_binary> --new_binary <new_binary> --patch_file_name <patch_file_name>\n```\n\nThis will generate the patch file for the new binary which needs to be hosted on the OTA update server.\n\n> **_NOTE:_** Make sure that the firmware present in the device is used as `base_binary` while creating the patch file. For this purpose, user should keep backup of the firmware running in the device as it is required for creating the patch file.\n\n### Verifying Patch\n\nTo verify that the patch file is correctly created from the provided base binary and new binary, use the following command:\n```\npython esp_delta_ota_patch_gen.py verify_patch --chip <target> --base_binary <base_binary> --new_binary <new_binary> --patch_file_name <patch_file_name>\n```\n\n"
  },
  {
    "path": "esp_delta_ota/examples/https_delta_ota/main/CMakeLists.txt",
    "content": "set(SRCS \"main.c\")\nset(INCLUDE_DIRS \".\")\nset(EMBED_TXTFILES \"tests/certs/servercert.pem\")\nset(PRIV_REQS \"esp_http_client esp_partition nvs_flash app_update esp_timer esp_wifi console\")\n\nif(CONFIG_EXAMPLE_ENABLE_CI_TEST)\n    list(APPEND SRCS\n        \"tests/test_local_server_ota.c\")\n    list(APPEND INCLUDE_DIRS \"tests\")\n    list(APPEND EMBED_TXTFILES \"tests/certs/prvtkey.pem\")\nendif()\n\nidf_component_register(SRCS ${SRCS}\n                    INCLUDE_DIRS ${INCLUDE_DIRS}\n                    EMBED_TXTFILES ${EMBED_TXTFILES}\n                    PRIV_REQUIRES ${PRIV_REQS})\n\n\nif(CONFIG_EXAMPLE_ENABLE_CI_TEST)\n    target_link_libraries(${COMPONENT_LIB} PRIVATE idf::esp_https_server)\nendif()\n"
  },
  {
    "path": "esp_delta_ota/examples/https_delta_ota/main/Kconfig.projbuild",
    "content": "menu \"Example Configuration\"\n\n    config EXAMPLE_FIRMWARE_UPG_URL\n        string \"Firmware Upgrade URL\"\n        default \"https://192.168.20.194:8070/patch.bin\"\n        help\n            URL of server which hosts the firmware image.\n\n    config EXAMPLE_SKIP_COMMON_NAME_CHECK\n        bool \"Skip server certificate CN fieldcheck\"\n        default n\n        help\n            This allows you to skip the validation of OTA server certificate CN field.\n\n    config EXAMPLE_SKIP_VERSION_CHECK\n        bool \"Skip firmware version check\"\n        default n\n        help\n            This allows you to skip the firmware version check.\n\n    config EXAMPLE_OTA_RECV_TIMEOUT\n        int \"OTA Receive Timeout\"\n        default 5000\n        help\n            Maximum time for reception\n\n    config EXAMPLE_FIRMWARE_UPG_URL_FROM_STDIN\n        bool\n        default y if EXAMPLE_FIRMWARE_UPG_URL = \"FROM_STDIN\"\n\n    config EXAMPLE_ENABLE_CI_TEST\n        bool \"Enable the CI test code\"\n        default n\n        help\n            This enables the CI test code i.e. https local server code.\n\nendmenu\n"
  },
  {
    "path": "esp_delta_ota/examples/https_delta_ota/main/ca_cert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDWDCCAkACCQCbF4+gVh/MLjANBgkqhkiG9w0BAQsFADBuMQswCQYDVQQGEwJJ\nTjELMAkGA1UECAwCTUgxDDAKBgNVBAcMA1BVTjEMMAoGA1UECgwDRVNQMQwwCgYD\nVQQLDANFU1AxDDAKBgNVBAMMA0VTUDEaMBgGCSqGSIb3DQEJARYLZXNwQGVzcC5j\nb20wHhcNMjEwNzEyMTIzNjI3WhcNNDEwNzA3MTIzNjI3WjBuMQswCQYDVQQGEwJJ\nTjELMAkGA1UECAwCTUgxDDAKBgNVBAcMA1BVTjEMMAoGA1UECgwDRVNQMQwwCgYD\nVQQLDANFU1AxDDAKBgNVBAMMA0VTUDEaMBgGCSqGSIb3DQEJARYLZXNwQGVzcC5j\nb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDhxF/y7bygndxPwiWL\nSwS9LY3uBMaJgup0ufNKVhx+FhGQOu44SghuJAaH3KkPUnt6SOM8jC97/yQuc32W\nukI7eBZoA12kargSnzdv5m5rZZpd+NznSSpoDArOAONKVlzr25A1+aZbix2mKRbQ\nS5w9o1N2BriQuSzd8gL0Y0zEk3VkOWXEL+0yFUT144HnErnD+xnJtHe11yPO2fEz\nYaGiilh0ddL26PXTugXMZN/8fRVHP50P2OG0SvFpC7vghlLp4VFM1/r3UJnvL6Oz\n3ALc6dhxZEKQucqlpj8l1UegszQToopemtIj0qXTHw2+uUnkUyWIPjPC+wdOAoap\nrFTRAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAItw24y565k3C/zENZlxyzto44ud\nIYPQXN8Fa2pBlLe1zlSIyuaA/rWQ+i1daS8nPotkCbWZyf5N8DYaTE4B0OfvoUPk\nB5uGDmbuk6akvlB5BGiYLfQjWHRsK9/4xjtIqN1H58yf3QNROuKsPAeywWS3Fn32\n3//OpbWaClQePx6udRYMqAitKR+QxL7/BKZQsX+UyShuq8hjphvXvk0BW8ONzuw9\nRcoORxM0FzySYjeQvm4LhzC/P3ZBhEq0xs55aL2a76SJhq5hJy7T/Xz6NFByvlrN\nlFJJey33KFrAf5vnV9qcyWFIo7PYy2VsaaEjFeefr7q3sTFSMlJeadexW2Y=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "esp_delta_ota/examples/https_delta_ota/main/idf_component.yml",
    "content": "## IDF Component Manager Manifest File\nversion: \"1.0.0\"\ndescription: Delta OTA Example\ndependencies:\n  espressif/esp_delta_ota:\n    version: '1.*'\n    override_path: '../../../'\n  protocol_examples_common:\n    path: ${IDF_PATH}/examples/common_components/protocol_examples_common\n"
  },
  {
    "path": "esp_delta_ota/examples/https_delta_ota/main/main.c",
    "content": "/* HTTPS Delta OTA example\n\n   This example code is in the Public Domain (or CC0 licensed, at your option.)\n\n   Unless required by applicable law or agreed to in writing, this\n   software is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n   CONDITIONS OF ANY KIND, either express or implied.\n*/\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/param.h>\n\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"freertos/event_groups.h\"\n\n#include \"esp_system.h\"\n#include \"esp_log.h\"\n#include \"esp_err.h\"\n#include \"esp_timer.h\"\n#include \"esp_event.h\"\n\n#include \"nvs_flash.h\"\n#include \"esp_wifi.h\"\n#include \"esp_netif.h\"\n#include \"protocol_examples_common.h\"\n#include \"esp_ota_ops.h\"\n#include \"esp_app_format.h\"\n#include \"esp_app_desc.h\"\n#include \"esp_partition.h\"\n\n#include \"esp_http_client.h\"\n#include \"esp_delta_ota.h\"\n\n#define BUFFSIZE 1024\n#define PATCH_HEADER_SIZE 64\n#define DIGEST_SIZE 32\n#define OTA_URL_SIZE 256\nstatic uint32_t esp_delta_ota_magic = 0xfccdde10;\n\nstatic const char *TAG = \"https_delta_ota_example\";\n\nstatic char ota_write_data[BUFFSIZE + 1] = { 0 };\nextern const uint8_t server_cert_pem_start[] asm(\"_binary_servercert_pem_start\");\nextern const uint8_t server_cert_pem_end[] asm(\"_binary_servercert_pem_end\");\n\n#ifdef CONFIG_EXAMPLE_ENABLE_CI_TEST\n#include \"test_local_server_ota.h\"\n#endif\n\nconst esp_partition_t *current_partition, *destination_partition;\nstatic esp_ota_handle_t ota_handle;\n\n#define IMG_HEADER_LEN sizeof(esp_image_header_t)\n\nstatic bool verify_chip_id(void *bin_header_data)\n{\n    esp_image_header_t *header = (esp_image_header_t *)bin_header_data;\n    if (header->chip_id != CONFIG_IDF_FIRMWARE_CHIP_ID) {\n        ESP_LOGE(TAG, \"Mismatch chip id, expected %d, found %d\", CONFIG_IDF_FIRMWARE_CHIP_ID, header->chip_id);\n        return false;\n    }\n    return true;\n}\n\n#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0))\nstatic esp_err_t write_cb(const uint8_t *buf_p, size_t size, void *user_data)\n#else\nstatic esp_err_t write_cb(const uint8_t *buf_p, size_t size)\n#endif\n{\n    if (size <= 0) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    static char header_data[IMG_HEADER_LEN];\n    static bool chip_id_verified = false;\n    static int header_data_read = 0;\n    int index = 0;\n\n    if (!chip_id_verified) {\n        if (header_data_read + size <= IMG_HEADER_LEN) {\n            memcpy(header_data + header_data_read, buf_p, size);\n            header_data_read += size;\n            return ESP_OK;\n        } else {\n            index = IMG_HEADER_LEN - header_data_read;\n            memcpy(header_data + header_data_read, buf_p, index);\n\n            if (!verify_chip_id(header_data)) {\n                return ESP_ERR_INVALID_VERSION;\n            }\n            chip_id_verified = true;\n\n            // Write data in header_data buffer.\n            esp_err_t err = esp_ota_write(ota_handle, header_data, IMG_HEADER_LEN);\n            if (err != ESP_OK) {\n                return err;\n            }\n        }\n    }\n    return esp_ota_write(ota_handle, buf_p + index, size - index);\n}\n\nstatic esp_err_t read_cb(uint8_t *buf_p, size_t size, int src_offset)\n{\n    if (size <= 0) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    return esp_partition_read(current_partition, src_offset, buf_p, size);\n}\n\nstatic void reboot(void)\n{\n    for (int i = 5; i > 0; i--) {\n        ESP_LOGI(TAG, \"Rebooting in %d seconds...\", i);\n        vTaskDelay(1000 / portTICK_PERIOD_MS);\n    }\n    esp_restart();\n}\n\nstatic void http_cleanup(esp_http_client_handle_t client)\n{\n    esp_http_client_close(client);\n    esp_http_client_cleanup(client);\n}\n\nstatic bool verify_patch_header(void *img_hdr_data)\n{\n    if (!img_hdr_data) {\n        return false;\n    }\n    uint32_t recv_magic = *(uint32_t *)img_hdr_data;\n    uint8_t *digest = (uint8_t *)(img_hdr_data + 4);\n\n    if (recv_magic != esp_delta_ota_magic) {\n        ESP_LOGE(TAG, \"Invalid magic word in patch\");\n        return false;\n    }\n    uint8_t sha_256[DIGEST_SIZE] = { 0 };\n    esp_partition_get_sha256(esp_ota_get_running_partition(), sha_256);\n    if (memcmp(sha_256, digest, DIGEST_SIZE) != 0) {\n        ESP_LOGE(TAG, \"SHA256 of current firmware differs from than in patch header. Invalid patch for current firmware\");\n        return false;\n    }\n    return true;\n}\n\nstatic void ota_example_task(void *pvParameter)\n{\n    esp_err_t err;\n\n    esp_http_client_config_t config = {\n        .url = CONFIG_EXAMPLE_FIRMWARE_UPG_URL,\n        .cert_pem = (char *)server_cert_pem_start,\n        .timeout_ms = CONFIG_EXAMPLE_OTA_RECV_TIMEOUT,\n        .keep_alive_enable = true,\n    };\n#ifdef CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK\n    config.skip_cert_common_name_check = true;\n#endif\n\n#ifdef CONFIG_EXAMPLE_ENABLE_CI_TEST\n    ESP_LOGI(TAG, \"Reading OTA URL from stdin\");\n    delta_ota_test_firmware_data_from_stdin(&config.url);\n#elif defined(CONFIG_EXAMPLE_FIRMWARE_UPG_URL_FROM_STDIN)\n    if (strcmp(config.url, \"FROM_STDIN\") == 0) {\n        ESP_LOGI(TAG, \"Reading OTA URL from stdin\");\n        char url_buf[OTA_URL_SIZE];\n        example_configure_stdin_stdout();\n        fgets(url_buf, OTA_URL_SIZE, stdin);\n        int len = strlen(url_buf);\n        url_buf[len - 1] = '\\0';\n        config.url = url_buf;\n    } else {\n        ESP_LOGE(TAG, \"Configuration mismatch: wrong firmware upgrade image url\");\n        abort();\n    }\n#endif\n\n    esp_http_client_handle_t client = esp_http_client_init(&config);\n    if (client == NULL) {\n        ESP_LOGE(TAG, \"Failed to initialise HTTP connection\");\n        vTaskDelete(NULL);\n    }\n    err = esp_http_client_open(client, 0);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to open HTTP connection: %s\", esp_err_to_name(err));\n        esp_http_client_cleanup(client);\n        vTaskSuspend(NULL);\n    }\n    esp_http_client_fetch_headers(client);\n\n    current_partition = esp_ota_get_running_partition();\n    destination_partition = esp_ota_get_next_update_partition(NULL);\n\n    if (current_partition == NULL || destination_partition == NULL) {\n        ESP_LOGE(TAG, \"Error getting partition information\");\n        goto error;\n    }\n\n    if (current_partition->subtype >= ESP_PARTITION_SUBTYPE_APP_OTA_MAX ||\n            destination_partition->subtype >= ESP_PARTITION_SUBTYPE_APP_OTA_MAX) {\n        goto error;\n    }\n\n    err = esp_ota_begin(destination_partition, OTA_SIZE_UNKNOWN, &(ota_handle));\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"esp_ota_begin failed: %s\", esp_err_to_name(err));\n        goto error;\n    }\n    esp_delta_ota_cfg_t cfg = {\n        .read_cb = &read_cb,\n    };\n\n#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0))\n    char *user_data = \"https_delta_ota\";\n    cfg.write_cb_with_user_data = &write_cb;\n    cfg.user_data = user_data;\n#else\n    cfg.write_cb = &write_cb;\n#endif\n\n    esp_delta_ota_handle_t handle = esp_delta_ota_init(&cfg);\n    if (handle == NULL) {\n        ESP_LOGE(TAG, \"delta_ota_set_cfg failed\");\n        goto error;\n    }\n\n    // Read size equal to patch header to verify the header\n    int data_read = esp_http_client_read(client, ota_write_data, PATCH_HEADER_SIZE);\n    if (data_read != PATCH_HEADER_SIZE) {\n        ESP_LOGE(TAG, \"Patch Header not received\");\n        goto error;\n    }\n    if (!verify_patch_header(ota_write_data)) {\n        ESP_LOGE(TAG, \"Patch Header verification failed\");\n        goto error;\n    }\n\n    while (1) {\n        int data_read = esp_http_client_read(client, ota_write_data, BUFFSIZE);\n        if (data_read < 0) {\n            ESP_LOGE(TAG, \"Error: SSL data read error\");\n            goto error;\n        } else if (data_read > 0) {\n            if (esp_delta_ota_feed_patch(handle, (const uint8_t *)ota_write_data, data_read) < 0) {\n                ESP_LOGE(TAG, \"Error while applying patch\");\n                goto error;\n            }\n        } else if (data_read == 0) {\n            if (esp_http_client_is_complete_data_received(client) == true) {\n                ESP_LOGI(TAG, \"Connection closed\");\n                break;\n            }\n            if (errno == ECONNRESET || errno == ENOTCONN) {\n                ESP_LOGE(TAG, \"Connection closed, errno = %d\", errno);\n                break;\n            }\n        }\n    }\n    err = esp_delta_ota_finalize(handle);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"esp_delta_ota_finalize() failed : %s\", esp_err_to_name(err));\n    }\n    err = esp_delta_ota_deinit(handle);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"esp_delta_ota_deinit() failed : %s\", esp_err_to_name(err));\n    }\n    err = esp_ota_end(ota_handle);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"esp_ota_end() failed : %s\", esp_err_to_name(err));\n    }\n    err = esp_ota_set_boot_partition(destination_partition);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"esp_ota_set_boot_partition() failed : %s\", esp_err_to_name(err));\n    }\n    http_cleanup(client);\n    reboot();\nerror:\n    http_cleanup(client);\n    vTaskDelete(NULL);\n}\n\nvoid app_main(void)\n{\n    ESP_LOGI(TAG, \"Initialising WiFi Connection...\");\n\n    ESP_ERROR_CHECK(nvs_flash_init());\n    ESP_ERROR_CHECK(esp_netif_init());\n    ESP_ERROR_CHECK(esp_event_loop_create_default());\n\n    /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.\n     * Read \"Establishing Wi-Fi or Ethernet Connection\" section in\n     * examples/protocols/README.md for more information about this function.\n     */\n    ESP_ERROR_CHECK(example_connect());\n\n#ifdef CONFIG_EXAMPLE_ENABLE_CI_TEST\n    /* Start the local HTTPS server for CI test */\n    ESP_ERROR_CHECK(delta_ota_test_start_webserver());\n    ESP_LOGI(TAG, \"Local HTTPS server started for CI test\");\n#endif\n\n    xTaskCreate(&ota_example_task, \"ota_example_task\", 8192, NULL, 5, NULL);\n}\n"
  },
  {
    "path": "esp_delta_ota/examples/https_delta_ota/main/tests/certs/prvtkey.pem",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDhxF/y7bygndxP\nwiWLSwS9LY3uBMaJgup0ufNKVhx+FhGQOu44SghuJAaH3KkPUnt6SOM8jC97/yQu\nc32WukI7eBZoA12kargSnzdv5m5rZZpd+NznSSpoDArOAONKVlzr25A1+aZbix2m\nKRbQS5w9o1N2BriQuSzd8gL0Y0zEk3VkOWXEL+0yFUT144HnErnD+xnJtHe11yPO\n2fEzYaGiilh0ddL26PXTugXMZN/8fRVHP50P2OG0SvFpC7vghlLp4VFM1/r3UJnv\nL6Oz3ALc6dhxZEKQucqlpj8l1UegszQToopemtIj0qXTHw2+uUnkUyWIPjPC+wdO\nAoaprFTRAgMBAAECggEAE0HCxV/N1Q1h+1OeDDGL5+74yjKSFKyb/vTVcaPCrmaH\nfPvp0ddOvMZJ4FDMAsiQS6/n4gQ7EKKEnYmwTqj4eUYW8yxGUn3f0YbPHbZT+Mkj\nz5woi3nMKi/MxCGDQZX4Ow3xUQlITUqibsfWcFHis8c4mTqdh4qj7xJzehD2PVYF\ngNHZsvVj6MltjBDAVwV1IlGoHjuElm6vuzkfX7phxcA1B4ZqdYY17yCXUnvui46z\nXn2kUTOOUCEgfgvGa9E+l4OtdXi5IxjaSraU+dlg2KsE4TpCuN2MEVkeR5Ms3Y7Q\njgJl8vlNFJDQpbFukLcYwG7rO5N5dQ6WWfVia/5XgQKBgQD74at/bXAPrh9NxPmz\ni1oqCHMDoM9sz8xIMZLF9YVu3Jf8ux4xVpRSnNy5RU1gl7ZXbpdgeIQ4v04zy5aw\n8T4tu9K3XnR3UXOy25AK0q+cnnxZg3kFQm+PhtOCKEFjPHrgo2MUfnj+EDddod7N\nJQr9q5rEFbqHupFPpWlqCa3QmQKBgQDldWUGokNaEpmgHDMnHxiibXV5LQhzf8Rq\ngJIQXb7R9EsTSXEvsDyqTBb7PHp2Ko7rZ5YQfyf8OogGGjGElnPoU/a+Jij1gVFv\nkZ064uXAAISBkwHdcuobqc5EbG3ceyH46F+FBFhqM8KcbxJxx08objmh58+83InN\nP9Qr25Xw+QKBgEGXMHuMWgQbSZeM1aFFhoMvlBO7yogBTKb4Ecpu9wI5e3Kan3Al\npZYltuyf+VhP6XG3IMBEYdoNJyYhu+nzyEdMg8CwXg+8LC7FMis/Ve+o7aS5scgG\n1to/N9DK/swCsdTRdzmc/ZDbVC+TuVsebFBGYZTyO5KgqLpezqaIQrTxAoGALFCU\n10glO9MVyl9H3clap5v+MQ3qcOv/EhaMnw6L2N6WVT481tnxjW4ujgzrFcE4YuxZ\nhgwYu9TOCmeqopGwBvGYWLbj+C4mfSahOAs0FfXDoYazuIIGBpuv03UhbpB1Si4O\nrJDfRnuCnVWyOTkl54gKJ2OusinhjztBjcrV1XkCgYEA3qNi4uBsPdyz9BZGb/3G\nrOMSw0CaT4pEMTLZqURmDP/0hxvTk1polP7O/FYwxVuJnBb6mzDa0xpLFPTpIAnJ\nYXB8xpXU69QVh+EBbemdJWOd+zp5UCfXvb2shAeG3Tn/Dz4cBBMEUutbzP+or0nG\nvSXnRLaxQhooWm+IuX9SuBQ=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "esp_delta_ota/examples/https_delta_ota/main/tests/certs/servercert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDWDCCAkACCQCbF4+gVh/MLjANBgkqhkiG9w0BAQsFADBuMQswCQYDVQQGEwJJ\nTjELMAkGA1UECAwCTUgxDDAKBgNVBAcMA1BVTjEMMAoGA1UECgwDRVNQMQwwCgYD\nVQQLDANFU1AxDDAKBgNVBAMMA0VTUDEaMBgGCSqGSIb3DQEJARYLZXNwQGVzcC5j\nb20wHhcNMjEwNzEyMTIzNjI3WhcNNDEwNzA3MTIzNjI3WjBuMQswCQYDVQQGEwJJ\nTjELMAkGA1UECAwCTUgxDDAKBgNVBAcMA1BVTjEMMAoGA1UECgwDRVNQMQwwCgYD\nVQQLDANFU1AxDDAKBgNVBAMMA0VTUDEaMBgGCSqGSIb3DQEJARYLZXNwQGVzcC5j\nb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDhxF/y7bygndxPwiWL\nSwS9LY3uBMaJgup0ufNKVhx+FhGQOu44SghuJAaH3KkPUnt6SOM8jC97/yQuc32W\nukI7eBZoA12kargSnzdv5m5rZZpd+NznSSpoDArOAONKVlzr25A1+aZbix2mKRbQ\nS5w9o1N2BriQuSzd8gL0Y0zEk3VkOWXEL+0yFUT144HnErnD+xnJtHe11yPO2fEz\nYaGiilh0ddL26PXTugXMZN/8fRVHP50P2OG0SvFpC7vghlLp4VFM1/r3UJnvL6Oz\n3ALc6dhxZEKQucqlpj8l1UegszQToopemtIj0qXTHw2+uUnkUyWIPjPC+wdOAoap\nrFTRAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAItw24y565k3C/zENZlxyzto44ud\nIYPQXN8Fa2pBlLe1zlSIyuaA/rWQ+i1daS8nPotkCbWZyf5N8DYaTE4B0OfvoUPk\nB5uGDmbuk6akvlB5BGiYLfQjWHRsK9/4xjtIqN1H58yf3QNROuKsPAeywWS3Fn32\n3//OpbWaClQePx6udRYMqAitKR+QxL7/BKZQsX+UyShuq8hjphvXvk0BW8ONzuw9\nRcoORxM0FzySYjeQvm4LhzC/P3ZBhEq0xs55aL2a76SJhq5hJy7T/Xz6NFByvlrN\nlFJJey33KFrAf5vnV9qcyWFIo7PYy2VsaaEjFeefr7q3sTFSMlJeadexW2Y=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "esp_delta_ota/examples/https_delta_ota/main/tests/test_local_server_ota.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n/* Delta OTA HTTPS example's test file\n *\n * This example code is in the Public Domain (or CC0 licensed, at your option.)\n *\n * Unless required by applicable law or agreed to in writing, this\n * software is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n * CONDITIONS OF ANY KIND, either express or implied.\n */\n#include \"esp_https_server.h\"\n#include \"esp_log.h\"\n#include \"nvs_flash.h\"\n#include \"test_local_server_ota.h\"\n#include \"protocol_examples_common.h\"\n#include \"esp_partition.h\"\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#define OTA_URL_SIZE 256\n#define PARTITION_READ_BUFFER_SIZE 256\n#define PARTITION_READ_SIZE PARTITION_READ_BUFFER_SIZE\n\nstatic const char *TAG = \"test_local_server_ota\";\nstatic size_t patch_size = 0;\n\n#ifdef CONFIG_EXAMPLE_FIRMWARE_UPG_URL_FROM_STDIN\nvoid delta_ota_test_firmware_data_from_stdin(const char **data)\n{\n    char input_buf[OTA_URL_SIZE];\n    if (strcmp(*data, \"FROM_STDIN\") == 0) {\n        example_configure_stdin_stdout();\n        fflush(stdin);\n        char *url = NULL;\n        char *tokens[OTA_URL_SIZE];\n        char *saveptr;\n        int token_count = 0;\n\n        if (fgets(input_buf, OTA_URL_SIZE, stdin) == NULL) {\n            ESP_LOGE(TAG, \"Failed to read URL from stdin\");\n            abort();\n        }\n        int len = strlen(input_buf);\n        if (len == 0) {\n            ESP_LOGE(TAG, \"Empty URL read from stdin\");\n            abort();\n        }\n        if (input_buf[len - 1] == '\\n') {\n            input_buf[len - 1] = '\\0';\n            len--;\n        }\n        char *token = strtok_r(input_buf, \" \", &saveptr);\n        if (token == NULL) {\n            ESP_LOGE(TAG, \"No URL token found in input\");\n            return;\n        }\n        // First token is the URL\n        url = token;\n        tokens[token_count++] = url;\n        // Process remaining tokens\n        while ((token = strtok_r(NULL, \" \", &saveptr)) != NULL) {\n            tokens[token_count++] = token;\n        }\n        // Require patch_size to be provided (at least 2 tokens: URL and patch_size)\n        if (token_count < 2) {\n            ESP_LOGE(TAG, \"Expected URL and patch_size, but only got %d token(s)\", token_count);\n            return;\n        }\n        *data = strdup(tokens[0]);\n        // Assign the URL and additional data after the loop\n        if (token_count > 1) {\n            ESP_LOGI(TAG, \"patch_size: %s\\n\", tokens[1]);\n            patch_size = atoi(tokens[1]); // Assuming the next token is the patch size\n        }\n        // Tokens are collected in the tokens array\n    } else {\n        ESP_LOGE(TAG, \"Configuration mismatch: wrong firmware upgrade image url\");\n        abort();\n    }\n}\n#endif\n\n/* An HTTP GET handler */\nstatic esp_err_t root_get_handler(httpd_req_t *req)\n{\n    httpd_resp_set_type(req, \"application/octet-stream\");\n\n    // Find the patch_data partition where pytest writes the patch\n    const esp_partition_t *p = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,\n                               ESP_PARTITION_SUBTYPE_ANY, \"patch_data\");\n\n    if (p == NULL) {\n        ESP_LOGE(TAG, \"patch_data partition not found\");\n        httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, \"Partition not found\");\n        return ESP_FAIL;\n    }\n\n    if (patch_size == 0) {\n        ESP_LOGE(TAG, \"Patch size is 0\");\n        return ESP_FAIL;\n    }\n\n    int image_len = patch_size;\n    char buffer[PARTITION_READ_BUFFER_SIZE];\n    int size = PARTITION_READ_SIZE;\n    int offset = 0;\n\n    do {\n        /* Read file in chunks into the scratch buffer */\n        if (offset + size > image_len) {\n            size = image_len - offset;\n        }\n        if (size == 0) {\n            break;\n        }\n        esp_err_t ret = esp_partition_read(p, offset, buffer, size);\n        if (ret == ESP_OK) {\n            /* Send the buffer contents as HTTP response chunk */\n            if (httpd_resp_send_chunk(req, buffer, size) != ESP_OK) {\n                ESP_LOGE(TAG, \"File sending failed!\");\n                /* Abort sending file */\n                httpd_resp_sendstr_chunk(req, NULL);\n                /* Respond with 500 Internal Server Error */\n                httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, \"Failed to send file\");\n                return ESP_FAIL;\n            }\n        } else {\n            ESP_LOGE(TAG, \"Partition read failed: %s\", esp_err_to_name(ret));\n            httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, \"Failed to read partition\");\n            return ESP_FAIL;\n        }\n        offset += size;\n\n        /* Keep looping till the whole file is sent */\n    } while (offset < image_len);\n\n    ESP_LOGI(TAG, \"Patch file sending complete\");\n\n    // Set headers\n    httpd_resp_set_hdr(req, \"Accept-Ranges\", \"bytes\");\n    httpd_resp_set_hdr(req, \"Connection\", \"close\");\n    httpd_resp_send_chunk(req, NULL, 0);\n\n    return ESP_OK;\n}\n\nstatic esp_err_t root_head_handler(httpd_req_t *req)\n{\n    const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,\n                                       ESP_PARTITION_SUBTYPE_ANY, \"patch_data\");\n\n    if (partition == NULL) {\n        ESP_LOGE(TAG, \"Partition not found\");\n        httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, \"Partition not found\");\n        return ESP_FAIL;\n    }\n\n    if (patch_size == 0) {\n        return ESP_FAIL;\n    }\n\n    // Get the size of the patch\n    httpd_resp_set_type(req, \"application/octet-stream\");\n    httpd_resp_set_hdr(req, \"Accept-Ranges\", \"bytes\");\n    httpd_resp_set_hdr(req, \"Connection\", \"close\");\n\n    // Complete HEAD response with no body\n    return httpd_resp_send(req, NULL, patch_size); // No body for HEAD method\n}\n\nstatic const httpd_uri_t get_root = {\n    .uri       = \"/patch.bin\",\n    .method    = HTTP_GET,\n    .handler   = root_get_handler\n};\n\nstatic const httpd_uri_t head_root = {\n    .uri       = \"/patch.bin\",\n    .method    = HTTP_HEAD,\n    .handler   = root_head_handler\n};\n\nesp_err_t delta_ota_test_start_webserver(void)\n{\n    httpd_handle_t server = NULL;\n    // Start the httpd server\n    ESP_LOGI(TAG, \"Starting HTTPS server for CI test\");\n\n    httpd_ssl_config_t conf = HTTPD_SSL_CONFIG_DEFAULT();\n\n    extern const unsigned char servercert_start[] asm(\"_binary_servercert_pem_start\");\n    extern const unsigned char servercert_end[]   asm(\"_binary_servercert_pem_end\");\n    conf.servercert = servercert_start;\n    conf.servercert_len = servercert_end - servercert_start;\n\n    extern const unsigned char prvtkey_pem_start[] asm(\"_binary_prvtkey_pem_start\");\n    extern const unsigned char prvtkey_pem_end[]   asm(\"_binary_prvtkey_pem_end\");\n    conf.prvtkey_pem = prvtkey_pem_start;\n    conf.prvtkey_len = prvtkey_pem_end - prvtkey_pem_start;\n\n    esp_err_t ret = httpd_ssl_start(&server, &conf);\n    if (ESP_OK != ret) {\n        ESP_LOGE(TAG, \"Error starting server!\");\n        return ret;\n    }\n\n    // Set URI handlers\n    ESP_LOGI(TAG, \"Registering URI handlers\");\n    httpd_register_uri_handler(server, &get_root);\n    httpd_register_uri_handler(server, &head_root);\n    return ESP_OK;\n}\n"
  },
  {
    "path": "esp_delta_ota/examples/https_delta_ota/main/tests/test_local_server_ota.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n#pragma once\n\n#ifdef CONFIG_EXAMPLE_ENABLE_CI_TEST\n\n/**\n * @brief starts the https server\n *\n * The server will serve the patch file from the patch_data partition.\n * The patch_size must be set via delta_ota_test_firmware_data_from_stdin()\n * before starting the server. NOTE - patch_size cannot be 0.\n */\nesp_err_t delta_ota_test_start_webserver(void);\n\n/**\n * @brief Takes the firmware URL from the STDIN (if want to send\n *         other data write the data in just one line by adding \" \" delimiter).\n *\n * @param data pointer to the firmware URL (or URL including other data)\n */\nvoid delta_ota_test_firmware_data_from_stdin(const char **data);\n#endif\n"
  },
  {
    "path": "esp_delta_ota/examples/https_delta_ota/partitions.csv",
    "content": "# Name,   Type, SubType,  Offset,   Size,  Flags\nnvs,      data, nvs,      0x9000,   20K\notadata,  data, ota,      0xE000,   8K\nphy_init, data, phy,      0x10000,  4K\nota_0,    app,  ota_0,    0x20000, 1280K\nota_1,    app,  ota_1,    0x160000, 1280K\npatch_data, data, 0x40,   0x2A0000, 512K\n"
  },
  {
    "path": "esp_delta_ota/examples/https_delta_ota/pytest_https_delta_ota.py",
    "content": "# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\n\nimport contextlib\nimport io\nimport os\nimport subprocess\nimport sys\nimport pexpect\nfrom typing import Any\n\nimport esptool\nimport pytest\nfrom pytest_embedded import Dut\n\nPATCH_DATA_PARTITION_OFFSET = 0x2A0000 # Hardcoded offset for patch_data partition from partitions.csv\n\ndef get_env_config_variable(env_name, var_name):\n    return os.environ.get(f'{env_name}_{var_name}'.upper())\n\ndef _ensure_requirements_installed():\n    example_dir = os.path.dirname(os.path.abspath(__file__))\n    requirements_path = os.path.join(example_dir, 'tools', 'requirements.txt')\n\n    if not os.path.exists(requirements_path):\n        raise Exception(f'Requirements file not found at {requirements_path}')\n\n    result = subprocess.run(\n        [sys.executable, '-m', 'pip', 'install', '-r', requirements_path],\n        cwd=os.path.dirname(requirements_path),\n        check=False,\n        capture_output=True,\n        text=True,\n    )\n\n    if result.returncode != 0:\n        raise RuntimeError(\n            f'Failed to install requirements from {requirements_path} (exit code {result.returncode}):\\n'\n            f'{result.stderr}'\n        )\n\ndef setting_connection(dut: Dut, env_name: str | None = None) -> Any:\n    if env_name is not None and dut.app.sdkconfig.get('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN') is True:\n        dut.expect('Please input ssid password:')\n        ap_ssid = get_env_config_variable(env_name, 'ap_ssid')\n        ap_password = get_env_config_variable(env_name, 'ap_password')\n        dut.write(f'{ap_ssid} {ap_password}')\n    try:\n        ip_address = dut.expect(r'IPv4 address: (\\d+\\.\\d+\\.\\d+\\.\\d+)[^\\d]', timeout=60)[1].decode()\n        print(f'Connected to AP/Ethernet with IP: {ip_address}')\n    except pexpect.exceptions.TIMEOUT:\n        raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')\n    return ip_address\n\n\ndef find_hello_world_binary(base_dir, chip_target='esp32'):\n    \"\"\"\n    Find the pre-built hello_world binary for the target chip.\n    \n    This function looks for hello_world_<target>.bin in the tests directory\n    under the given base directory (e.g., main/tests/).\n    These binaries are pre-built and checked into the repository for testing.\n    \n    Args:\n        base_dir: Base directory that contains the tests subdirectory (e.g., main/)\n        chip_target: Target chip (default: 'esp32')\n    \n    Returns:\n        Path to the hello_world binary file\n    \"\"\"\n    # Look for hello_world binary in tests directory\n    binary_name = f'hello_world_{chip_target}.bin'\n    binary_path = os.path.join(base_dir, 'tests', binary_name)\n    \n    if os.path.exists(binary_path):\n        return binary_path\n    \n    # Fallback: try generic hello_world.bin\n    fallback_path = os.path.join(base_dir, 'tests', 'hello_world.bin')\n    if os.path.exists(fallback_path):\n        print(f'Warning: Using generic hello_world.bin instead of {binary_name}')\n        return fallback_path\n    \n    raise Exception(f'Hello world binary not found at {binary_path}. '\n                   f'Expected pre-built binary: {binary_name} in tests/ directory. '\n                   f'Base dir: {base_dir}')\n\n\ndef generate_patch(base_binary, new_binary, patch_output, chip='esp32'):\n    \"\"\"Generate delta OTA patch using the esp_delta_ota_patch_gen.py tool.\"\"\"\n    _ensure_requirements_installed()\n\n    # Find the tool in the tools directory\n    example_dir = os.path.dirname(os.path.abspath(__file__))\n    tool_path = os.path.join(example_dir, 'tools', 'esp_delta_ota_patch_gen.py')\n    \n    if not os.path.exists(tool_path):\n        raise Exception(f'Patch generation tool not found at {tool_path}')\n    \n    # Verify input files exist\n    if not os.path.exists(base_binary):\n        raise Exception(f'Base binary not found at {base_binary}')\n    if not os.path.exists(new_binary):\n        raise Exception(f'New binary not found at {new_binary}')\n    \n    # Use the tool to generate patch\n    cmd = [\n        sys.executable,\n        tool_path,\n        'create_patch',\n        '--chip', chip,\n        '--base_binary', base_binary,\n        '--new_binary', new_binary,\n        '--patch_file_name', patch_output\n    ]\n    \n    result = subprocess.run(cmd, capture_output=True, text=True)\n    \n    # Print output\n    if result.stdout:\n        print(result.stdout)\n    if result.stderr:\n        print('STDERR:', result.stderr)\n    \n    if result.returncode != 0:\n        raise Exception(f'Patch generation failed with return code {result.returncode}')\n    \n    if not os.path.exists(patch_output):\n        raise Exception(f'Patch file not created at {patch_output}')\n    \n    print(f'Patch created successfully: {patch_output} ({os.path.getsize(patch_output)} bytes)')\n\ndef write_patch_to_partition(dut: Dut, patch_file: str):\n    \"\"\"Write the patch file to the patch_data partition on the device.\n\n    Uses the existing esptool connection managed by pytest-embedded to avoid\n    serial port conflicts. The device is hard-reset after writing so it\n    boots fresh with the patch available on the partition.\n    \"\"\"\n    patch_size = os.path.getsize(patch_file)\n\n    # Hardcoded offset for patch_data partition from partitions.csv\n    # OTA partitions must be aligned to 0x10000 boundaries\n    # Calculated as: phy_init ends at 0x11000, ota_0 aligned to 0x20000, ota_1 at 0x160000, patch_data at 0x2A0000\n    offset = PATCH_DATA_PARTITION_OFFSET\n    print(f'Writing patch ({patch_size} bytes) to patch_data partition at offset {hex(offset)}')\n\n    serial = dut.serial\n\n    # Reuse the same pattern as EspSerial.use_esptool() decorator:\n    #   1. stop the serial redirect thread (releases the pyserial port)\n    #   2. let esptool reuse the existing connection\n    #   3. resume the redirect thread when done\n    # Use a local buffer instead of private attribute to avoid brittleness\n    with serial.disable_redirect_thread():\n        esptool_output = io.StringIO()\n        with contextlib.redirect_stdout(esptool_output):\n            settings = serial.proc.get_settings() # Save the current serial settings\n            serial.esp.connect() # Connect to the device using esptool\n            esptool.main(\n                ['--after', 'no-reset', 'write-flash', hex(offset), patch_file],\n                esp=serial.esp,\n            )\n            serial.proc.apply_settings(settings) # Restore the original serial settings\n        # Log esptool output for debugging\n        output = esptool_output.getvalue()\n        if output:\n            print(f'esptool output: {output}')\n\n        # Hard-reset inside the disabled-redirect context so that when the redirect\n        # thread resumes, the pexpect buffer only contains messages from this new boot\n        # (no stale messages from earlier boots that would cause early pattern matches).\n        serial.hard_reset()\n\n    print('Successfully wrote patch to patch_data partition')\n\n\n@pytest.mark.parametrize('target', ['esp32'])\n@pytest.mark.generic\ndef test_esp_delta_ota(dut: Dut):\n    example_dir = os.path.dirname(os.path.abspath(__file__))\n    build_dir = dut.app.binary_path\n    chip_target = getattr(dut, 'target', None) or os.environ.get('IDF_TARGET', 'esp32')\n    \n    try:\n        # Step 1: Get base and new binaries\n        base_binary = os.path.join(build_dir, 'https_delta_ota.bin')\n        if not os.path.exists(base_binary):\n            raise Exception(f'Base binary not found at {base_binary}. Device was flashed from build directory: {build_dir}')\n\n        # Use find_hello_world_binary helper to locate the test binary\n        new_binary = find_hello_world_binary(os.path.join(example_dir, 'main'), chip_target)\n\n        # Step 2: Generate patch\n        patch_file = os.path.join(build_dir, 'patch.bin')\n        generate_patch(base_binary, new_binary, patch_file, chip_target)\n\n        # Step 3: Write patch to the patch_data partition\n        write_patch_to_partition(dut, patch_file)\n        \n        # Step 4: Wait for device to boot, start local server, and signal ready for stdin.\n        # Same pattern as pre_encrypted_ota: expect the log right before fgets(), then write.\n        patch_size = os.path.getsize(patch_file)\n        device_ip = '127.0.0.1'\n        ota_url = f'https://{device_ip}:443/patch.bin'\n\n        dut.expect('Reading OTA URL from stdin', timeout=30)\n        print(f'Providing OTA URL to device: {ota_url} {patch_size}')\n        dut.write(f'{ota_url} {patch_size}\\n')\n\n        # Step 5: Wait for reboot and new firmware to boot\n        dut.expect('Hello world!', timeout=60)\n        \n        print('Delta OTA test PASSED: Successfully updated from https_delta_ota to hello_world')\n        \n    except Exception as e:\n        print(f'HTTPS Delta OTA test FAILED: {str(e)}')\n        raise\n"
  },
  {
    "path": "esp_delta_ota/examples/https_delta_ota/sdkconfig.ci",
    "content": "CONFIG_EXAMPLE_FIRMWARE_UPG_URL=\"FROM_STDIN\"\nCONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y\nCONFIG_EXAMPLE_CONNECT_IPV6=n\nCONFIG_EXAMPLE_ENABLE_CI_TEST=y\n\nCONFIG_EXAMPLE_CONNECT_ETHERNET=n\nCONFIG_EXAMPLE_CONNECT_WIFI=n\n\nCONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y\nCONFIG_ESP_HTTPS_SERVER_ENABLE=y\n"
  },
  {
    "path": "esp_delta_ota/examples/https_delta_ota/sdkconfig.defaults",
    "content": "CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y\nCONFIG_PARTITION_TABLE_CUSTOM=y\nCONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions.csv\"\nCONFIG_PARTITION_TABLE_FILENAME=\"partitions.csv\"\n"
  },
  {
    "path": "esp_delta_ota/examples/https_delta_ota/tools/esp_delta_ota_patch_gen.py",
    "content": "#!/usr/bin/env python\n#\n# ESP Delta OTA Patch Generator Tool. This tool helps in generating the compressed patch file\n# using BSDiff and Heatshrink algorithms\n#\n# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n\nimport argparse\nimport os\nimport re\nimport tempfile\nimport hashlib\nimport sys\nimport esptool\n\ntry:\n    import detools\nexcept ImportError:\n    print(\"Please install 'detools'. Use command `pip install -r tools/requirements.txt`\")\n    sys.exit(1)\n\n# Magic Byte is created using command: echo -n \"esp_delta_ota\" | sha256sum\nesp_delta_ota_magic = 0xfccdde10\n\nMAGIC_SIZE = 4 # This is the size of the magic byte\nDIGEST_SIZE = 32 # This is the SHA256 of the base binary    \nHEADER_SIZE = 64\nRESERVED_HEADER = HEADER_SIZE - (MAGIC_SIZE + DIGEST_SIZE) # This is the reserved header size\n\ndef calculate_sha256(file_path: str) -> str:\n    \"\"\"Calculate the SHA-256 hash of a file.\"\"\"\n    sha256_hash = hashlib.sha256()\n    \n    with open(file_path, \"rb\") as f:\n        # Read the file in chunks to avoid memory issues for large files\n        for byte_block in iter(lambda: f.read(4096), b\"\"):\n            sha256_hash.update(byte_block)\n    \n    # Return the hex representation of the hash\n    return sha256_hash.hexdigest()\n\ndef create_patch(chip: str, base_binary: str, new_binary: str, patch_file_name: str) -> None:\n    command = ['--chip', chip, 'image_info', base_binary]\n    output = sys.stdout\n    sys.stdout = tempfile.TemporaryFile(mode='w+')\n    try:\n        esptool.main(command)\n        sys.stdout.seek(0)\n        content = sys.stdout.read()\n    except Exception as e:\n        print(f\"Error during esptool command execution: {e}\")\n    finally:\n        sys.stdout.close()\n        sys.stdout = output\n\n    x = re.search(r\"Validation Hash: ([A-Za-z0-9]+) \\(valid\\)\", content, re.IGNORECASE)\n    \n    if x is None:\n        print(\"Failed to find validation hash in base binary.\")\n        return\n    patch_file_without_header = \"patch_file_temp.bin\"\n    try:\n        with open(base_binary, 'rb') as b_binary, open(new_binary, 'rb') as n_binary, open(patch_file_without_header, 'wb') as p_binary:\n            detools.create_patch(b_binary, n_binary, p_binary, compression='heatshrink') # b_binary is the base binary, n_binary is the new binary, p_binary is the patch file without header\n\n        with open(patch_file_without_header, \"rb\") as p_binary, open(patch_file_name, \"wb\") as patch_file:\n            patch_file.write(esp_delta_ota_magic.to_bytes(MAGIC_SIZE, 'little'))\n            patch_file.write(bytes.fromhex(x[1]))\n            patch_file.write(bytearray(RESERVED_HEADER))\n            patch_file.write(p_binary.read())    \n    except Exception as e:\n        print(f\"Error during patch creation: {e}\")\n    finally:\n        if os.path.exists(patch_file_without_header):\n            os.remove(patch_file_without_header)\n\n    print(\"Patch created successfully.\")\n    # Verifying the created patch file\n    verify_patch(base_binary, patch_file_name, new_binary)\n\n# This API applies the patch file over the base_binary file and generates the binary.new file. Then it compares \n# the hash of new_binary and binary.new, if they are the same then the verification is successful, otherwise it fails.\ndef verify_patch(base_binary: str, patch_to_verify: str, new_binary: str) -> None:\n\n    with open(patch_to_verify, \"rb\") as original_file:\n        original_file.seek(HEADER_SIZE)\n        patch_content = original_file.read()\n\n    temp_file_name = None\n    try:\n        with tempfile.NamedTemporaryFile(delete=False) as temp_file:\n            temp_file.write(patch_content)\n            temp_file.flush()\n            temp_file_name = temp_file.name\n\n        detools.apply_patch_filenames(base_binary, temp_file_name, \"binary.new\")\n    except Exception as e:\n        print(f\"Failed to apply patch: {e}\")\n    finally:\n        if temp_file_name and os.path.exists(temp_file_name):\n            os.remove(temp_file_name)\n\n    sha_of_new_created_binary = calculate_sha256(\"binary.new\")\n    sha_of_new_binary = calculate_sha256(new_binary)\n    \n    if sha_of_new_created_binary == sha_of_new_binary:\n        print(\"Patch file verified successfully\")\n    else:\n        print(\"Failed to verify the patch\")\n    os.remove(\"binary.new\")\n\ndef main() -> None:\n    if len(sys.argv) < 2:\n        print(\"Usage: python esp_delta_ota_patch_gen.py create_patch/verify_patch [arguments]\")\n        sys.exit(1)\n\n    command = sys.argv[1]\n    parser = argparse.ArgumentParser('Delta OTA Patch Generator Tool')\n\n    if command == 'create_patch':\n        parser.add_argument('--chip', help=\"Target\", default=\"esp32\")\n        parser.add_argument('--base_binary', help=\"Path of Base Binary for creating the patch\", required=True)\n        parser.add_argument('--new_binary', help=\"Path of New Binary for which patch has to be created\", required=True)\n        parser.add_argument('--patch_file_name', help=\"Patch file path\", default=\"patch.bin\")\n        args = parser.parse_args(sys.argv[2:])\n        create_patch(args.chip, args.base_binary, args.new_binary, args.patch_file_name)\n    elif command == 'verify_patch':\n        parser.add_argument('--base_binary', help=\"Path of Base Binary for verifying the patch\", required=True)\n        parser.add_argument('--patch_file_name', help=\"Patch file path\", required=True)\n        parser.add_argument('--new_binary', help=\"Path of New Binary for verifying the patch\", required=True)\n        args = parser.parse_args(sys.argv[2:])\n        verify_patch(args.base_binary, args.patch_file_name, args.new_binary)\n    else:\n        print(\"Invalid command. Use 'create_patch' or 'verify_patch'.\")\n        sys.exit(1)\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "esp_delta_ota/examples/https_delta_ota/tools/requirements.txt",
    "content": "detools>=0.49.0\nesptool\n"
  },
  {
    "path": "esp_delta_ota/idf_component.yml",
    "content": "version: \"1.1.4\"\ndescription: \"ESP Delta OTA Library\"\nurl: https://github.com/espressif/idf-extra-components/tree/master/esp_delta_ota\ndependencies:\n  idf: \">=4.3\"\n"
  },
  {
    "path": "esp_delta_ota/include/esp_delta_ota.h",
    "content": "/*\n * SPDX-License-Identifier: Apache 2.0 License\n *\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n */\n\n#pragma once\n\n#include \"esp_err.h\"\n#include <esp_idf_version.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0))\n#define DEPRECATED_ATTRIBUTE __attribute__((deprecated))\n#else\n#define DEPRECATED_ATTRIBUTE\n#endif\n\ntypedef void *esp_delta_ota_handle_t;\n\n// Callback for reading the source data\ntypedef esp_err_t (*src_read_cb_t)(uint8_t *buf_p, size_t size, int src_offset);\ntypedef esp_err_t (*src_read_cb_with_user_ctx_t)(uint8_t *buf_p, size_t size, int src_offset, void *user_data);\n\n// Callback for working on the data generated by applying patch on the source data\ntypedef esp_err_t (*merged_stream_write_cb_t)(const uint8_t *buf_p, size_t size);\ntypedef esp_err_t (*merged_stream_write_cb_with_user_ctx_t)(const uint8_t *buf_p, size_t size, void *user_data);\n\ntypedef struct esp_delta_ota_cfg {\n    void *user_data;              /*!< User Data */\n    union {\n        src_read_cb_t read_cb;        /*!< Read Callback */\n        src_read_cb_with_user_ctx_t read_cb_with_user_data; /*!< Read Callback with user data */\n    };\n    union {\n        merged_stream_write_cb_with_user_ctx_t write_cb_with_user_data;     /*!< Write Callback with user data */\n        merged_stream_write_cb_t write_cb DEPRECATED_ATTRIBUTE;             /*!< Write Callback */\n    };\n} esp_delta_ota_cfg_t;\n\n#undef DEPRECATED_ATTRIBUTE\n\n/**\n * @brief Initializes the delta OTA process\n *\n * @param[in] cfg pointer to esp_delta_ota_cfg_t structure.\n * @return - NULL   On failure\n *         - esp_delta_ota_handle_t handle\n */\nesp_delta_ota_handle_t esp_delta_ota_init(esp_delta_ota_cfg_t *cfg);\n\n/**\n * @brief This function performs the patch applying operation on the source data.\n *\n * @param[in] handle    esp_delta_ota_handle_t handle\n * @param[in] buf       pointer to patch buffer\n * @param[in] size      size of patch buffer.\n * @return - ESP_OK\n *         - ESP_ERR_INVALID_ARG\n *         - ESP_FAIL\n */\nesp_err_t esp_delta_ota_feed_patch(esp_delta_ota_handle_t handle, const uint8_t *buf, int size);\n\n/**\n * @brief This function finishes the patch applying operation.\n *\n * @param[in] handle    esp_delta_ota_handle_t\n * @return int\n */\nesp_err_t esp_delta_ota_finalize(esp_delta_ota_handle_t handle);\n\n/**\n * @brief Clean-up delta ota process\n *\n * @param[in] handle    esp_delta_ota_handle_t\n */\nesp_err_t esp_delta_ota_deinit(esp_delta_ota_handle_t handle);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_delta_ota/src/esp_delta_ota.c",
    "content": "/*\n * SPDX-License-Identifier: Apache 2.0 License\n *\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n */\n\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n#include <inttypes.h>\n\n#include \"esp_err.h\"\n#include \"esp_log.h\"\n\n#include \"esp_delta_ota.h\"\n#include \"detools.h\"\n\nstatic const char *TAG = \"esp_delta_ota\";\n\ntypedef struct esp_delta_ota_ctx {\n    void *user_data;\n    union {\n        src_read_cb_t read_cb;        /*!< Read Callback */\n        src_read_cb_with_user_ctx_t read_cb_with_user_data; /*!< Read Callback with user data */\n    };\n    union {\n        merged_stream_write_cb_with_user_ctx_t write_cb_with_user_data;\n        merged_stream_write_cb_t write_cb;\n    };\n    struct detools_apply_patch_t *apply_patch;\n    int src_offset;\n} esp_delta_ota_ctx;\n\nstatic int esp_delta_ota_write_cb(void *arg_p, const uint8_t *buf_p, size_t size)\n{\n    if (size <= 0) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    esp_delta_ota_ctx *handle = (esp_delta_ota_ctx *)arg_p;\n    esp_err_t err = ESP_OK;\n    if (!handle->user_data) {\n        err = handle->write_cb(buf_p, size);\n        if (err != ESP_OK) {\n            ESP_LOGE(TAG, \"Error in write_cb(): %s\", esp_err_to_name(err));\n            return ESP_FAIL;\n        }\n    } else {\n        err = handle->write_cb_with_user_data(buf_p, size, handle->user_data);\n        if (err != ESP_OK) {\n            ESP_LOGE(TAG, \"Error in write_cb_with_user_data(): %s\", esp_err_to_name(err));\n            return ESP_FAIL;\n        }\n    }\n    return ESP_OK;\n}\n\nstatic int esp_delta_ota_read_cb(void *arg_p, uint8_t *buf_p, size_t size)\n{\n    if (size <= 0 || !arg_p) {\n        return -ESP_ERR_INVALID_ARG;\n    }\n    esp_delta_ota_ctx *handle = (esp_delta_ota_ctx *)arg_p;\n    esp_err_t err = ESP_OK;\n    if (!handle->user_data) {\n        err = handle->read_cb(buf_p, size, handle->src_offset);\n        if (err != ESP_OK) {\n            ESP_LOGE(TAG, \"Error in read_cb(): %s\", esp_err_to_name(err));\n            return ESP_FAIL;\n        }\n    } else {\n        err = handle->read_cb_with_user_data(buf_p, size, handle->src_offset, handle->user_data);\n        if (err != ESP_OK) {\n            ESP_LOGE(TAG, \"Error in read_cb_with_user_data(): %s\", esp_err_to_name(err));\n            return ESP_FAIL;\n        }\n    }\n\n    handle->src_offset += size;\n    return ESP_OK;\n}\n\nstatic int esp_delta_ota_seek_cb(void *arg_p, int offset)\n{\n    esp_delta_ota_ctx *handle = (esp_delta_ota_ctx *)arg_p;\n    handle->src_offset += offset;\n    return ESP_OK;\n}\n\nesp_delta_ota_handle_t esp_delta_ota_init(esp_delta_ota_cfg_t *cfg)\n{\n    esp_delta_ota_ctx *ctx = calloc(1, sizeof(esp_delta_ota_ctx));\n    if (!ctx) {\n        ESP_LOGE(TAG, \"Unable to allocate memory\");\n        return NULL;\n    }\n    ctx->user_data = cfg->user_data;\n    ctx->read_cb = cfg->read_cb;\n    ctx->write_cb_with_user_data = cfg->write_cb_with_user_data;\n    ctx->apply_patch = calloc(1, sizeof(struct detools_apply_patch_t));\n    if (!ctx->apply_patch) {\n        ESP_LOGE(TAG, \"Unable to allocate memory\");\n        free(ctx);\n        ctx = NULL;\n        return NULL;\n    }\n    int ret = detools_apply_patch_init(ctx->apply_patch, &esp_delta_ota_read_cb, &esp_delta_ota_seek_cb, 0, &esp_delta_ota_write_cb, ctx);\n    if (ret < 0) {\n        ESP_LOGE(TAG, \"Error while initializing delta_ota: %s\", detools_error_as_string(ret));\n        free(ctx->apply_patch);\n        ctx->apply_patch = NULL;\n        free(ctx);\n        ctx = NULL;\n        return NULL;\n    }\n    return (esp_delta_ota_handle_t)ctx;\n}\n\nesp_err_t esp_delta_ota_feed_patch(esp_delta_ota_handle_t handle, const uint8_t *buf, int size)\n{\n    if (handle == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    esp_delta_ota_ctx *ctx = (esp_delta_ota_ctx *)handle;\n\n    int err = detools_apply_patch_process(ctx->apply_patch, (const uint8_t *)buf, size);\n    if (err != 0) {\n        ESP_LOGE(TAG, \"Error while applying patch: %s\", detools_error_as_string(err));\n        return ESP_FAIL;\n    }\n    return ESP_OK;\n}\n\nesp_err_t esp_delta_ota_finalize(esp_delta_ota_handle_t handle)\n{\n    if (handle == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    esp_delta_ota_ctx *ctx = (esp_delta_ota_ctx *)handle;\n\n    int err = detools_apply_patch_finalize(ctx->apply_patch);\n    if (err < 0) {\n        ESP_LOGE(TAG, \"Error while finishing the patching: %s\", detools_error_as_string(err));\n        return ESP_FAIL;\n    }\n    return ESP_OK;\n}\n\nesp_err_t esp_delta_ota_deinit(esp_delta_ota_handle_t handle)\n{\n    if (handle == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    esp_delta_ota_ctx *ctx = (esp_delta_ota_ctx *)handle;\n\n    free(ctx->apply_patch);\n    ctx->apply_patch = NULL;\n    free(ctx);\n    ctx = NULL;\n    return ESP_OK;\n}\n"
  },
  {
    "path": "esp_delta_ota/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(esp_delta_ota_test)\n"
  },
  {
    "path": "esp_delta_ota/test_apps/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"esp_delta_ota_test_main.c\" \"test_esp_delta_ota.c\"\n                    PRIV_INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES unity\n                    EMBED_FILES assets/base.bin assets/new.bin assets/patch.bin assets/bad_patch.bin\n                    WHOLE_ARCHIVE)\n"
  },
  {
    "path": "esp_delta_ota/test_apps/main/esp_delta_ota_test_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"unity.h\"\n#include \"unity_test_runner.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_newlib.h\"\n\n#include \"unity_test_utils_memory.h\"\n\nvoid setUp(void)\n{\n    unity_utils_record_free_mem();\n}\n\nvoid tearDown(void)\n{\n    esp_reent_cleanup();    //clean up some of the newlib's lazy allocations\n    unity_utils_evaluate_leaks_direct(0);\n}\n\nvoid app_main(void)\n{\n    printf(\"Running esp_delta_ota component tests\\n\");\n    unity_run_menu();\n}\n"
  },
  {
    "path": "esp_delta_ota/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/esp_delta_ota:\n    version: \"*\"\n    override_path: \"../..\"\n"
  },
  {
    "path": "esp_delta_ota/test_apps/main/test_esp_delta_ota.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <freertos/FreeRTOS.h>\n\n#include \"unity.h\"\n#include \"esp_delta_ota.h\"\n\n\nextern const uint8_t base_bin_start[] asm(\"_binary_base_bin_start\");\nextern const uint8_t base_bin_end[]   asm(\"_binary_base_bin_end\");\nextern const uint8_t new_bin_end[]   asm(\"_binary_new_bin_end\");\nextern const uint8_t new_bin_start[] asm(\"_binary_new_bin_start\");\nextern const uint8_t patch_bin_start[] asm(\"_binary_patch_bin_start\");\nextern const uint8_t patch_bin_end[]   asm(\"_binary_patch_bin_end\");\nextern const uint8_t bad_patch_bin_start[] asm(\"_binary_bad_patch_bin_start\");\nextern const uint8_t bad_patch_bin_end[]   asm(\"_binary_bad_patch_bin_end\");\n\nstatic uint8_t output_buffer[1300] = {0};\nstatic int output_index = 0;\nstatic esp_err_t write_cb(const uint8_t *buf_p, size_t size)\n{\n    if (size <= 0) {\n        return ESP_OK;\n    }\n    memcpy(output_buffer + output_index, buf_p, size);\n    output_index += size;\n    return ESP_OK;\n}\n\nstatic esp_err_t read_cb(uint8_t *buf_p, size_t size, int src_offset)\n{\n\n    if (size <= 0) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    memcpy(buf_p, base_bin_start + src_offset, size);\n    return ESP_OK;\n}\n\nTEST_CASE(\"Sending full patch at once\", \"[esp_delta_ota]\")\n{\n    memset(output_buffer, 0, 1000);\n    output_index = 0;\n    esp_delta_ota_cfg_t cfg = {\n        .read_cb = &read_cb,\n        .write_cb = &write_cb,\n    };\n\n    esp_delta_ota_handle_t handle = esp_delta_ota_init(&cfg);\n    TEST_ASSERT_NOT_NULL(handle);\n\n    esp_err_t err = esp_delta_ota_feed_patch(handle, patch_bin_start, patch_bin_end - patch_bin_start);\n    TEST_ESP_OK(err);\n\n    err = esp_delta_ota_finalize(handle);\n    TEST_ESP_OK(err);\n\n    err = esp_delta_ota_deinit(handle);\n    TEST_ESP_OK(err);\n\n    TEST_ASSERT_EQUAL_INT(0, memcmp(new_bin_start, output_buffer, new_bin_end - new_bin_start));\n}\n\nTEST_CASE(\"Applying wrong patch\", \"[esp_delta_ota]\")\n{\n    memset(output_buffer, 0, 1000);\n    output_index = 0;\n    esp_delta_ota_cfg_t cfg = {\n        .read_cb = &read_cb,\n        .write_cb = &write_cb,\n    };\n\n    esp_delta_ota_handle_t handle = esp_delta_ota_init(&cfg);\n    TEST_ASSERT_NOT_NULL(handle);\n\n    esp_err_t err = esp_delta_ota_feed_patch(handle, bad_patch_bin_start, bad_patch_bin_end - bad_patch_bin_start);\n    TEST_ESP_OK(err);\n\n    err = esp_delta_ota_finalize(handle);\n    TEST_ESP_OK(err);\n\n    err = esp_delta_ota_deinit(handle);\n    TEST_ESP_OK(err);\n\n    TEST_ASSERT_NOT_EQUAL(0, memcmp(new_bin_start, output_buffer, new_bin_end - new_bin_start));\n}\n\nTEST_CASE(\"Sending 1 byte of patch at once\", \"[esp_delta_ota]\")\n{\n    memset(output_buffer, 0, 1000);\n    output_index = 0;\n    esp_delta_ota_cfg_t cfg = {\n        .read_cb = &read_cb,\n        .write_cb = &write_cb,\n    };\n\n    esp_delta_ota_handle_t handle = esp_delta_ota_init(&cfg);\n    TEST_ASSERT_NOT_NULL(handle);\n    esp_err_t err = ESP_OK;\n\n    for (int i = 0; i < patch_bin_end - patch_bin_start; i++) {\n        err = esp_delta_ota_feed_patch(handle, patch_bin_start + i, 1);\n        TEST_ESP_OK(err);\n    }\n    err = esp_delta_ota_finalize(handle);\n    TEST_ESP_OK(err);\n\n    err = esp_delta_ota_deinit(handle);\n    TEST_ESP_OK(err);\n\n    TEST_ASSERT_EQUAL_INT(0, memcmp(new_bin_start, output_buffer, output_index));\n}\n"
  },
  {
    "path": "esp_delta_ota/test_apps/pytest_esp_delta_ota.py",
    "content": "import pytest\n\n\n@pytest.mark.generic\ndef test_esp_delta_ota(dut) -> None:\n    dut.run_all_single_board_cases()\n"
  },
  {
    "path": "esp_delta_ota/test_apps/sdkconfig.defaults",
    "content": "# This file was generated using idf.py save-defconfig. It can be edited manually.\n# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration\n#\nCONFIG_ESP_TASK_WDT_INIT=n\n"
  },
  {
    "path": "esp_encrypted_img/.build-test-rules.yml",
    "content": "esp_encrypted_img/examples:\n  disable:\n    - if: CONFIG_NAME == \"CONFIG_PRE_ENCRYPTED_RSA_USE_DS\" and (IDF_VERSION < \"5.3\" or SOC_HMAC_SUPPORTED != 1)\n      temporary: true\n      reason: IDF Version < 5.3 is not supported yet to use DS peripheral. Also skipping targets that do not support HMAC peripheral\n\nesp_encrypted_img/test_apps:\n  disable:\n    - if: CONFIG_NAME == \"ds_peripheral\" and (IDF_VERSION < \"5.3\" or SOC_HMAC_SUPPORTED != 1)\n      temporary: true\n      reason: IDF Version < 5.3 is not supported yet to use DS peripheral. Also skipping targets that do not support HMAC peripheral\n"
  },
  {
    "path": "esp_encrypted_img/CHANGELOG.md",
    "content": "## 2.7.1\n\n### Enhancements:\n- Added support for ESP-IDF v6.0 release\n\n## 2.7.0\n\n### Features:\n- Added support for PSA Crypto API and hence compatibility with ESP-IDF 6.0 release\n\n## 2.6.0\n\n### Enhancements:\n- Added support to use DS peripheral for RSA based encrypted OTA scheme\n\n## 2.5.1\n\n## Bugfixes:\n- Fixed the format of Kconfig file\n\n## 2.5.0\n\n### Enhancements:\n- Added an API to export the public key from the private key: `esp_encrypted_img_export_public_key`\n\n## 2.4.0\n\n### Enhancements:\n- Added support for ECIES based OTA encryption scheme\n\n## 2.3.0\n\n### Enhancements:\n- Added pre_encrypted_ota example, which demonstrates the OTA using encrypted image file.\n\n## 2.2.1\n\n- Build system: fix the dependency for generating pre encrypted image\n\n## 2.2.0\n\n### Enhancements:\n- Added an API to get the size of pre encrypted binary image header, this could be useful while computing entire decrypted image length: `esp_encrypted_img_get_header_size`\n\n## 2.1.0\n\n### Enhancements:\n- Added an API to abort the decryption process: `esp_encrypted_img_decrypt_abort`\n- Added an API to check if the complete data has been received: `esp_encrypted_img_is_complete_data_received`\n\n## 2.0.4\n\n- `rsa_pub_key` member of `esp_decrypt_cfg_t` structure is now deprecated. Please use `rsa_priv_key` instead. \n- `rsa_pub_key_len` member of `esp_decrypt_cfg_t` structure is now deprecated. Please use `rsa_priv_key_len` instead. \n"
  },
  {
    "path": "esp_encrypted_img/CMakeLists.txt",
    "content": "set(ESP_ENCRYPT_SRCS \"src/esp_encrypted_img.c\")\n\nif(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\n    list(APPEND ESP_ENCRYPT_SRCS \"src/esp_encrypted_img_utilities.c\")\nendif()\n\nidf_component_register(SRCS \"${ESP_ENCRYPT_SRCS}\"\n                    INCLUDE_DIRS \"include\"\n                    PRIV_INCLUDE_DIRS \"private_include\"\n                    PRIV_REQUIRES mbedtls)\n\nif(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\n    idf_component_optional_requires(PRIVATE efuse)\nendif()\n"
  },
  {
    "path": "esp_encrypted_img/Kconfig",
    "content": "menu \"Pre Encrypted OTA Configuration\"\n\n    choice PRE_ENCRYPTED_OTA_SCHEME\n        prompt \"Pre-encrypted OTA Scheme\"\n        default PRE_ENCRYPTED_OTA_USE_RSA\n        help\n            Select the cryptographic scheme to use for pre-encrypted Over-The-Air updates.\n\n        config PRE_ENCRYPTED_OTA_USE_RSA\n            bool \"RSA-3072 encryption\"\n            help\n                Use RSA for encrypting the GCM key.\n                The device will decrypt the GCM key using its private RSA key.\n\n        config PRE_ENCRYPTED_RSA_USE_DS\n            depends on PRE_ENCRYPTED_OTA_USE_RSA\n            depends on SOC_DIG_SIGN_SUPPORTED\n            select MBEDTLS_HARDWARE_RSA_DS_PERIPHERAL\n            bool \"Use DS Peripheral\"\n            help\n                Use DS Peripheral for RSA OTA Encryption Scheme. The DS peripheral is used\n                for decrypting the AES-GCM key\n\n        config PRE_ENCRYPTED_OTA_USE_ECIES\n            depends on SOC_HMAC_SUPPORTED\n            select MBEDTLS_HKDF_C\n            bool \"ECIES encryption\"\n            help\n                Use Elliptic Curve Cryptography (ECC) for key agreement.\n                The GCM key will be derived using ECDH with a server public key\n                and a device private key (potentially derived via HMAC).\n\n    endchoice\nendmenu"
  },
  {
    "path": "esp_encrypted_img/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "esp_encrypted_img/README.md",
    "content": "# ESP Encrypted Image Abstraction Layer\n\n[![Component Registry](https://components.espressif.com/components/espressif/esp_encrypted_img/badge.svg)](https://components.espressif.com/components/espressif/esp_encrypted_img)\n\nThis component provides an API interface to decrypt data defined in \"ESP Encrypted Image\" format. This format is as specified at [Image Format](#image-format)\n\nThis component can help in integrating pre encrypted firmware in over-the-air updates. Additionally, this component can also be used for other use-cases which requires addition of encryption layer for custom data.\n\n## Image Format\n\nThe ESP Encrypted Image format supports two primary cryptographic schemes: RSA-3072 and ECIES-P256.\n\nIt consists of a header followed by the encrypted binary data. The total header size is 512 bytes for both RSA and ECIES-P256 schemes, but the internal layout of the header differs.\n\n### RSA-3072 Image Header\n\n```mermaid\nblock-beta\n    columns 3\n    magic[\"Magic (0–3) [4 bytes]\"]:3\n    enc_gcm_key[\"AES-GCM key (4–387) [384 bytes]\"]:3\n    iv[\"AES-GCM IV (388–403) [16 bytes]\"]:3\n    bin_size[\"Binary Size (404–407) [4 bytes]\"]:3\n    auth_tag[\"Auth Tag (408–423) [16 bytes]\"]:3\n    reserved_rsa[\"Reserver Header (424–511) [88 bytes]\"]:3\n    app_binary[\"Application binary\"]:3\n    space:3\n    space:2 plain_text[\"Plain Text\"]:1\n    space:2 rsa_enc[\"Encrypted by RSA-3072\"]:1\n    space:2 aes_enc[\"Encrypted by AES-GCM key\"]:1\nstyle app_binary fill:#565\nstyle enc_gcm_key fill:#356\nstyle rsa_enc fill:#356\nstyle aes_enc fill:#565\n```\n\nThe header for an image encrypted using the RSA-3072 scheme is structured as follows:\n\n```c\ntypedef struct {\n    uint8_t magic[4];             // Magic bytes (e.g., derived from SHA256(\"esp_encrypted_img\"))\n    uint8_t enc_gcm_key[384];     // AES-GCM key encrypted with RSA-3072 public key\n    uint8_t iv[16];               // Initialization Vector for AES-GCM\n    uint8_t bin_size[4];          // Size of the original binary (little-endian)\n    uint8_t auth_tag[16];         // AES-GCM authentication tag\n    uint8_t reserved_rsa[88];     // Reserved for future use\n} esp_enc_img_rsa_header_t;\n```\n\n* **Magic (4 bytes):** Identifies the file type.\n* **Encrypted GCM Key (384 bytes):** The 32-byte AES-GCM key, encrypted using the RSA-3072 public key (PKCS#1 v1.5 padding).\n* **IV (16 bytes):** The Initialization Vector used for AES-GCM encryption.\n* **Binary Size (4 bytes):** The size of the original, unencrypted binary data, in little-endian format.\n* **Auth Tag (16 bytes):** The authentication tag generated by AES-GCM.\n* **Reserved (88 bytes):** Padding to make the header 512 bytes.\n\n### ECIES-P256 Image Header\n\nThe header for an image encrypted using the ECIES-P256 scheme is structured as follows:\n\n```mermaid\nblock-beta\n    columns 3\n    magic[\"Magic (0–3) [4 bytes]\"]:3\n    server_pub_key[\"Server Public Key (4–67) [64 bytes]\"]:3\n    kdf_salt[\"KDF Salt (68–99) [32 bytes]\"]:3\n    reserved_key_params[\"Reserved (100–387) [288 bytes]\"]:3\n    iv[\"AES-GCM IV (388–403) [16 bytes]\"]:3\n    bin_size[\"Binary Size (404–407) [4 bytes]\"]:3\n    auth_tag[\"Auth Tag (408–423) [16 bytes]\"]:3\n    reserved_final_padding[\"Reserved Header (424–511) [88 bytes]\"]:3\n    app_binary[\"Encrypted app binary \\nEncrypted with AES GCM key\"]:3\n    space:3\n    space:2 plain_text[\"Plain Text\"]:1\n    space:2 aes_enc[\"Encrypted by AES-GCM key\"]:1\nstyle app_binary fill:#565\nstyle aes_enc fill:#565\n```\n\n```c\ntypedef struct {\n    uint8_t magic[4];             // Magic bytes (e.g., derived from SHA256(\"esp_encrypted_img_ecc\"))\n    uint8_t server_pub_key[64];   // Server's uncompressed ECC public key (P-256, X and Y coordinates)\n    uint8_t kdf_salt[32];         // Salt used for KDF (HKDF) to derive AES-GCM key\n    uint8_t reserved_key_params[288]; // Reserved to make the key parameters block (server_pub_key, kdf_salt, this field) 384 bytes\n    uint8_t iv[16];               // Initialization Vector for AES-GCM\n    uint8_t bin_size[4];          // Size of the original binary (little-endian)\n    uint8_t auth_tag[16];         // AES-GCM authentication tag\n    uint8_t reserved_final_padding[88]; // Reserved padding to make the total header 512 bytes\n} esp_enc_img_ecc_header_t;\n```\n\n* **Magic (4 bytes):** Identifies the file type.\n* **Server Public Key (64 bytes):** The uncompressed public key of the server/script (P-256 curve). This consists of the X and Y coordinates (32 bytes each). This key is used by the device, along with its own private key, to perform ECDH and derive the shared secret.\n* **KDF Salt (32 bytes):** The salt used with HKDF (based on SHA256) to derive the AES-GCM encryption key from the ECDH shared secret.\n* **Reserved (288 bytes):** Padding to align the key parameters section (server public key, KDF salt, and this field) to 384 bytes so that the offset of the encryption-related parameters is unchanged.\n* **AES-GCM IV (16 bytes):** The Initialization Vector used for AES-GCM encryption.\n* **Binary Size (4 bytes):** The size of the original, unencrypted binary data, in little-endian format.\n* **Auth Tag (16 bytes):** The authentication tag generated by AES-GCM.\n* **Reserved Header (88 bytes):** Additional padding to ensure the total header size is 512 bytes.\n\nThe device's private key (required for ECDH on the device side) is typically derived on the device from an HMAC key. The `esp_enc_img_gen.py` script includes the *server's* public key in the header so the device can complete the ECDH handshake.\n\nNote:\n\n* RSA-3072 key is provided to the tool externally. You can generate an RSA key pair using the `esp_enc_img_gen.py` tool (recommended) or OpenSSL:\n  * Using `esp_enc_img_gen.py`:\n    ```bash\n    python esp_enc_img_gen.py --generate_rsa_key\n    ```\n    This will create `rsa_pub_key.pem` and `rsa_priv_key.pem`.\n  * Using OpenSSL:\n    ```bash\n    openssl genrsa -out rsa_key/private.pem 3072\n    ```\n* AES-GCM key and IV are generated by the tool itself.\n\n### RSA with Digital Signature (DS) Peripheral\n\nFor ESP32 devices that support the Digital Signature peripheral (such as ESP32-S2, ESP32-S3, ESP32-C3, etc.), you can enable hardware-accelerated RSA operations by selecting the `PRE_ENCRYPTED_RSA_USE_DS` configuration option. This provides enhanced security and performance compared to software-based RSA operations.\n\n**ESP-IDF Version Requirement:**\n\nThe Digital Signature (DS) peripheral support for decryption was introduced in ESP-IDF v5.3. To use DS peripheral functionality with esp_encrypted_img, you must use ESP-IDF v5.3 or above. Projects using ESP-IDF versions prior to v5.3 cannot use the DS peripheral option.\n\n**Configuration:**\n\nIn your project's menuconfig, navigate to:\n```\nComponent config → Pre Encrypted OTA Configuration → Pre-encrypted OTA Scheme → RSA-3072 encryption → Use DS Peripheral\n```\n\n**Key Requirements:**\n\nWhen using the DS peripheral, the RSA private key must be securely provisioned using the ESP Secure Certificate Manager. The key is stored in a special format that can only be used by the DS peripheral.\n\n**Device Provisioning:**\n\nUse the `configure_esp_secure_cert.py` tool to provision the DS context:\n\n```bash\npython configure_esp_secure_cert.py --target_chip <chip> --private-key <private_key.pem> --priv_key_algo RSA 3072 --configure_ds\n```\n\nThis command generates the DS context and creates an `esp_secure_cert.bin` file that contains the encrypted private key and DS parameters.\n\n**Partition Table Setup:**\n\nYour project must include an `esp_secure_cert` partition in the partition table. The example project provides a reference partition table (`examples/pre_encrypted_ota/partitions.csv`) that includes:\n\n```csv\nesp_secure_cert,0x3F,,,0x2000,\n```\n\nYou can use this as a template for your own project's partition table.\n\n**Flashing the Secure Certificate:**\n\nAfter generating the DS context, you must flash the `esp_secure_cert.bin` file to the device. You need to determine the correct partition offset first:\n\n```bash\n# Check your partition table to find the esp_secure_cert partition offset\nidf.py partition-table\n\n# Flash the secure certificate to the correct offset\nesptool.py write_flash <esp_secure_cert_partition_offset> esp_secure_cert.bin\n```\n\n**Note:** Replace `<esp_secure_cert_partition_offset>` with the actual offset shown in your partition table output. For the example partition table provided, this is 0x9000, but always verify with your specific partition table.\n\nCheck the esp_secure_cert_manager documentation for more information on how to use the tool.\n\n**Important Notes:**\n\n- **ESP-IDF v5.3+ Required:** DS peripheral support requires ESP-IDF v5.3 or above\n- The DS peripheral requires the private key to be in a specific format managed by ESP Secure Certificate Manager\n- Public key export via `esp_encrypted_img_export_public_key()` is not supported when using DS peripheral (returns `ESP_ERR_NOT_SUPPORTED`)\n- This option is only available on ESP32 variants that support the Digital Signature peripheral\n- Enhanced security as the private key never leaves the secure hardware peripheral\n- The private key is stored securely in eFuse and cannot be read back in plaintext\n\n## Tool Info\n\nThe `esp_encrypted_img` component includes a Python script, `esp_enc_img_gen.py`, designed for generating and managing encrypted images. This tool supports two primary cryptographic schemes for image encryption: RSA-3072 and ECIES-P256. The script requires a key file for all encryption and decryption operations. If keys are not available, they must be generated beforehand using the appropriate `--generate_..._key` options.\n\n**Core Functionality:**\n\n* **Encryption**: Secures binary files using either RSA or ECC. Requires a public key file.\n* **Decryption**: Decrypts images. Requires the corresponding private key file.\n* **Key Management**: Assists in generating cryptographic keys via `--generate_ecc_key` and `--generate_rsa_key` options.\n\n### Key Generation\n\nThe tool provides options to generate cryptographic key pairs for both ECIES-P256 and RSA schemes.\n\n* **Generate ECIES-P256 Key Pair**:\n  Use the `--generate_ecc_key` option to generate an ECC key pair. This will create `device_pub_key.pem` (device public key) and `device_hmac_key.bin` (HMAC key for deriving device key).\n\n  ```bash\n  python esp_enc_img_gen.py --generate_ecc_key\n  ```\n\n* **Generate RSA Key Pair**:\n  Use the `--generate_rsa_key` option to generate an RSA-3072 key pair. This will create `rsa_pub_key.pem` (public key) and `rsa_priv_key.pem` (private key).\n\n  ```bash\n  python esp_enc_img_gen.py --generate_rsa_key\n  ```\n\n### Encryption Schemes\n\n#### 1. RSA-3072\n\nThis scheme uses an RSA public key to encrypt an AES-GCM key, which is then used to encrypt the image. The corresponding RSA private key is required for decryption.\n\n**Key Generation:**\n\nAn RSA-3072 key pair (public and private keys) is required. You can generate one using OpenSSL or the tool itself:\n\nUsing OpenSSL:\n\n```bash\nopenssl genrsa -out rsa_private_key.pem 3072\nopenssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem\n```\n\nUsing the tool:\n\n```bash\npython esp_enc_img_gen.py --generate_rsa_key\n```\n\nThis will create `rsa_pub_key.pem` and `rsa_priv_key.pem`.\n\n* The `rsa_public_key.pem` is used for encryption.\n* The `rsa_private_key.pem` is used for decryption.\n\n**Encrypting the image:**\n\n```bash\npython esp_enc_img_gen.py encrypt <input_file.bin> /path/to/rsa_public_key.pem <output_encrypted.bin>\n```\n\n**Decrypting the image:**\n\n```bash\npython esp_enc_img_gen.py decrypt <output_encrypted.bin> <key_file.pem> <decrypted_output.bin>\n```\n\n#### 2. ECIES-P256\n\nThis scheme utilizes Elliptic Curve Cryptography (ECC) with a 256-bit curve. It employs an Elliptic Curve Diffie-Hellman (ECDH) key exchange to establish a shared secret. This shared secret is then used to derive an AES-GCM key for encrypting the image.\nA device public key file must be provided for encryption. The script will then generate an ephemeral server key pair for the ECDH process, and the server's public key is included in the image header. This allows the device (which possesses the corresponding device private key) to reconstruct the shared secret and decrypt the image.\n\n**General Encryption Command Structure:**\n\n```bash\npython esp_enc_img_gen.py encrypt <input_file.bin> <path_to_device_public_key.pem> <output_encrypted.bin>\n```\n\n**Key Generation and Management Files (ECIES-P256):**\n\nDuring ECIES-P256 encryption, various key-related files may be generated or used by the script:\n\n* `device_hmac_key.bin`: An HMAC key used to derive the device's ECC key pair. This file is saved if an HMAC key is generated by `--generate_ecc_key`.\n* `device_pub_key.pem`: The device's public ECC key (in PEM format). This is generated by `--generate_ecc_key` or can be provided by the user.\n* The server's public ECC key is generated by the script during encryption and included in the encrypted image header. It is not saved as a separate file.\n\n**Device Provisioning for ECIES-P256 with HMAC Key (Example: `pre_encrypted_ota`)**\n\nWhen using an HMAC-derived device key for ECIES-P256, the device hmac key must be securely provisioned onto the device. This is typically done by burning it into an eFuse key block.\n\n1. **Burn the HMAC Key to eFuse:**\n\n    Use the `idf.py` command to burn the `device_hmac_key.bin` to a specific eFuse key block. For example:\n\n    ```bash\n    idf.py efuse-burn-key BLOCK_KEY<N> device_hmac_key.bin HMAC_UP\n    ```\n\n    Replace `BLOCK_KEY<N>` with the actual eFuse block you intend to use (e.g., `BLOCK_KEY0`, `BLOCK_KEY1`, etc., up to `BLOCK_KEY5` typically).\n\n2. **Code Configuration:**\n\n    The eFuse block chosen in the command above must match the HMAC key ID used in your application code. In the `pre_encrypted_ota` example, the HMAC key ID is defined in the source code and should be updated to match your chosen eFuse block.\n\n    ```c\n    #define HMAC_UP_KEY_ID 2\n    esp_decrypt_cfg_t cfg = {\n        .hmac_key_id = HMAC_UP_KEY_ID,\n    };\n    ```\n\n**Selecting OTA Scheme in Example:**\n\nThe `pre_encrypted_ota` example project uses Kconfig options to allow selection between RSA and ECIES-P256 schemes for OTA updates:\n\n* `PRE_ENCRYPTED_OTA_SCHEME`: This choice allows you to select either:\n* `PRE_ENCRYPTED_OTA_USE_RSA`: For RSA-based pre-encrypted OTA.\n* `PRE_ENCRYPTED_OTA_USE_ECIES`: For ECC-based pre-encrypted OTA.\n\nMake sure these configurations are set correctly in your project's configuration to match your chosen encryption scheme and hardware provisioning.\n\n### ECC-256 Encryption Use Cases\n\n* **Use Case 1: No Pre-existing Device Keys**\n  If you do not have existing ECC keys for the device, you must first generate them. The `--generate_ecc_key` option will create a device HMAC key (`device_hmac_key.bin`) and a device public key (`device_pub_key.pem`) derived from it. The `device_pub_key.pem` is then used for encryption.\n\n  1. Generate the necessary keys:\n\n     ```bash\n     python esp_enc_img_gen.py --generate_ecc_key\n     ```\n\n     This command creates `device_hmac_key.bin` and `device_pub_key.pem` in the current directory.\n\n  2. Encrypt the image using the generated device public key:\n\n     ```bash\n     python esp_enc_img_gen.py encrypt <input_file.bin> device_pub_key.pem <output_encrypted.bin>\n     ```\n\n* **Use Case 2: Pre-existing Device Public Key is Available**\n    Uses a provided device public ECC key (e.g., `device_pub_key.pem`) directly. The script will use this key and generate a new server key pair for ECDH.\n\n    ```bash\n    python esp_enc_img_gen.py encrypt <input_file.bin> <path_to_your_device_public_key.pem> <output_encrypted.bin>\n    ```\n\n    The public key of the ephemeral server key pair used for ECDH is embedded in the image but not saved to a separate file.\n\n## Per Device Unique Key Support\n\nThe `esp_encrypted_img` component supports workflows where each device is provisioned with a unique key pair. This is essential for scenarios requiring per-device image encryption and secure provisioning. By exporting the public key from the device or key management system, you can automate image generation and ensure that only the intended device can decrypt its firmware or data.\n\nIt is the application's responsibility to:\n- Generate the key using a good entropy source (the [ESP-IDF Random Number Generation APIs](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/random.html) provide suggested approach using ESP-IDF APIs).\n- Flash the generated key to the device securely (e.g., to eFuse or in Flash).\n- Retrieve the public key (using the API below), send it to the server, and use it to generate pre-encrypted OTA binaries for each device.\n\n<details>\n<summary>How to Export the Public Key</summary>\n\n### Exporting the Public Key Programmatically\n\nThe component provides an API to retrieve the public key associated with the decryption context:\n\n```c\n/**\n * @brief  Export the public key corresponding to the private key.\n *         The application should free the memory pointed by `pub_key` after use.\n *         For RSA, the public key is in DER format and corresponds to the private key passed with `esp_encrypted_img_decrypt_start()`.\n *         For ECIES, the public key is in DER format and is derived from the HMAC key ID passed with `esp_encrypted_img_decrypt_start()`.\n *\n * @param ctx   esp_decrypt_handle_t handle\n * @param pub_key   Pointer to store the public key\n * @param pub_key_len   Pointer to store the length of the public key\n * @return esp_err_t   Status of the operation\n */\nesp_err_t esp_encrypted_img_export_public_key(esp_decrypt_handle_t ctx, uint8_t **pub_key, size_t *pub_key_len);\n```\n\n- **RSA-3072:** Returns the public key in DER format.\n- **ECIES-P256:** Returns the public key in DER format and is derived from the HMAC key ID.\n\n</details>\n\n### Getting More Help\n\nTo explore all available options and commands for the tool, use:\n\n```bash\npython esp_enc_img_gen.py --help\n```\n\n## API Reference\n\nTo learn more about how to use this component, please check API Documentation from header file [esp_encrypted_img.h](https://github.com/espressif/idf-extra-components/blob/master/esp_encrypted_img/include/esp_encrypted_img.h)\n"
  },
  {
    "path": "esp_encrypted_img/examples/pre_encrypted_ota/CMakeLists.txt",
    "content": "# For more information about build system see\n# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html\n# The following five lines of boilerplate have to be in your project's\n# CMakeLists in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nproject(pre_encrypted_ota)\n\n# Flash the pre_encrypted_ota_secure.bin to the OTA 1 partition.\nif(CONFIG_EXAMPLE_ENABLE_CI_TEST)\n    set(partition ota_1)\n    idf_build_get_property(build_dir BUILD_DIR)\n    set(image_file ${build_dir}/pre_encrypted_ota_secure.bin)\n    partition_table_get_partition_info(offset \"--partition-name ${partition}\" \"offset\")\n    esptool_py_flash_target_image(flash \"${partition}\" \"${offset}\" \"${image_file}\")\nendif()\n\nif (CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    set(partition esp_secure_cert)\n    idf_build_get_property(project_dir PROJECT_DIR)\n    set(image_file ${CMAKE_CURRENT_SOURCE_DIR}/esp_secure_cert_data/${partition}.bin)\n    partition_table_get_partition_info(offset \"--partition-name ${partition}\" \"offset\")\n    esptool_py_flash_target_image(flash \"${partition}\" \"${offset}\" \"${image_file}\")\nendif()\n"
  },
  {
    "path": "esp_encrypted_img/examples/pre_encrypted_ota/README.md",
    "content": "| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-P4 | ESP32-S2 | ESP32-S3 |\n| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- |\n\n# Encrypted Binary OTA\n\nThis example demonstrates OTA updates with pre-encrypted binary using `esp_encrypted_img` component's APIs and tool.\n\nPre-encrypted firmware binary must be hosted on OTA update server.\nThis firmware will be fetched and then decrypted on device before being flashed.\nThis allows firmware to remain `confidential` on the OTA update channel irrespective of underlying transport (e.g., non-TLS).\n\n* **NOTE:** Pre-encrypted OTA is a completely different scheme from Flash Encryption. Pre-encrypted OTA helps in ensuring the confidentiality of the firmware on the network channel, whereas Flash Encryption is intended for encrypting the contents of the ESP32's off-chip flash memory.\n\n> [!CAUTION]\n> Using the Pre-encrypted Binary OTA provides confidentiality of the firmware, but it does not ensure authenticity of the firmware. For ensuring that the firmware is coming from trusted source, please consider enabling secure boot feature along with the Pre-encrypted binary OTA. Please refer to security guide in the ESP-IDF docs for more details.\n\n## ESP Encrypted Image Abstraction Layer\n\nThis example uses `esp_encrypted_img` component hosted at [idf-extra-components/esp_encrypted_img](https://github.com/espressif/idf-extra-components/blob/master/esp_encrypted_img) and available though the [IDF component manager](https://components.espressif.com/component/espressif/esp_encrypted_img).\n\nPlease refer to its documentation [here](https://github.com/espressif/idf-extra-components/blob/master/esp_encrypted_img/README.md) for more details.\n\n\n## How to use the example\n\nThis example can use either RSA or ECIES-P256 for pre-encrypted OTA. You must first select your desired scheme:\n1. Run `idf.py menuconfig`.\n2. Navigate to `Component config` -> `Pre Encrypted OTA Configuration`.\n3. Set `Pre-encrypted OTA Scheme` to your choice:\n    * `RSA-3072 encryption`\n    * `ECIES encryption`\n4. If you selected `ECIES encryption` and will be using the HMAC-derived key, ensure `HMAC EFUSE KEY ID` is set to the eFuse block where `ecc_key/device_hmac_key.bin` will be burned.\n5. Save the configuration and exit.\n\nOnce the scheme is selected, follow the relevant sub-section below for key generation and specific setup.\n\n### Creating RSA key for encryption\n\nYou can generate a public and private RSA key pair using the `esp_enc_img_gen.py` tool or `openssl`.\n\nUsing `esp_enc_img_gen.py`:\n```bash\npython esp_enc_img_gen.py --generate_rsa_key\n```\nThis will create `rsa_pub_key.pem` and `rsa_priv_key.pem` in the current directory.\n\nUsing `openssl`:\n`openssl genrsa -out rsa_key/private.pem 3072`\n\nThis generates a 3072-bit RSA key pair, and writes them to a file.\n\nPrivate key is required for decryption process and is used as input to the `esp_encrypted_img` component. Private key can either be embedded into the firmware or stored in NVS.\n\nEncrypted image generation tool will derive public key (from private key) and use it for encryption purpose.\n\n* **NOTE:** We highly recommend the use of flash encryption or NVS encryption to protect the RSA Private Key on the device.\n* **NOTE:** RSA key provided in the example is for demonstration purpose only. We recommend to create a new key for production applications.\n\n### Steps for ECIES Scheme\n\nTo test the ECIES-based encryption scheme:\n\n1.  **Configure for ECIES** (Ensure `ECIES encryption` is selected in `menuconfig` as described above):\n    *   Run `idf.py menuconfig` (if not already done, or to verify).\n    *   Navigate to `Component config` -> `Pre Encrypted OTA Configuration`.\n    *   Select `ECIES encryption` for the `Pre-encrypted OTA Scheme`.\n    *   Set the `HMAC EFUSE KEY ID` to the eFuse block number (0-5) where you will burn the `ecc_key/device_hmac_key.bin`. The default is -1 (disabled), so this must be changed.\n    *   Save the configuration and exit.\n\n2.  **Key Management**:\n    *   This example provides a pre-generated HMAC key and its corresponding public key in the `ecc_key/` directory (relative to this example).\n        *   `ecc_key/device_hmac_key.bin`: The HMAC key that needs to be burned into the device\\'s eFuse.\n        *   `ecc_key/public.pem`: The device public key, derived from `device_hmac_key.bin`. This key will be used by the build system to encrypt the firmware.\n    *   **Burn the HMAC Key to eFuse**:\n        Use the `idf.py efuse-burn-key` command to burn the `ecc_key/device_hmac_key.bin` to the eFuse block you configured in `menuconfig`.\n        For example, if you set `HMAC EFUSE KEY ID` to 0:\n        ```bash\n        idf.py efuse-burn-key BLOCK_KEY0 ecc_key/device_hmac_key.bin HMAC_UP\n        ```\n        Replace `BLOCK_KEY0` with the correct eFuse block if you chose a different ID (e.g., `BLOCK_KEY1` for ID 1).\n    *   **(Alternative) Generate New Keys**: If you prefer not to use the provided keys, you can generate a new set:\n        ```bash\n        python <path_to_esp_encrypted_img>/tools/esp_enc_img_gen.py --generate_ecc_key\n        ```\n        This will create `device_hmac_key.bin` and `device_pub_key.pem` in the current directory. You would then need to:\n        1.  Replace `ecc_key/device_hmac_key.bin` and `ecc_key/public.pem` with these new files (or update the example to point to them).\n        2.  Burn the new `device_hmac_key.bin` to the eFuse.\n\n3.  **Build, Flash, and OTA**:\n    *   Follow the steps in \"Build and Flash example\" and \"Configure and start python based HTTPS Server\" below. The build system will use the ECIES scheme and the public key (e.g., `ecc_key/public.pem`) to generate `build/pre_encrypted_ota_secure.bin`.\n\n* **NOTE:** The keys in the `ecc_key/` directory are for demonstration purposes only. We recommend creating a new key pair for production applications.\n\n## Build and Flash example\n\n```\nidf.py build flash\n```\n\n* An encrypted image is automatically generated by build system. Upload the generated encrypted image (`build/pre_encrypted_ota_secure.bin`) to a server for performing OTA update.\n\n### Configure and start python based HTTPS Server\n\nAfter a successful build, we need to create a self-signed certificate and run a simple HTTPS server as follows:\n\n![create_self_signed_certificate](https://raw.githubusercontent.com/espressif/idf-extra-components/master/esp_encrypted_img/examples/pre_encrypted_ota/docs/ota_self_signature.gif)\n\n* Create server_certs directory, Navigate to server_certs directory `cd server_certs`.\n* To create a new self-signed certificate and key, run the command `openssl req -x509 -newkey rsa:2048 -keyout ca_key.pem -out ca_cert.pem -days 365 -nodes`.\n  * When prompted for the `Common Name (CN)`, enter the name of the server that the \"ESP-Dev-Board\" will connect to. When running this example from a development machine, this is probably the IP address. The HTTPS client will check that the `CN` matches the address given in the HTTPS URL.\n\nYou can start the server using following instructions:\n\nAfter the successful build, start the local python based HTTPS server using the certificate and key present in the 'server_certs' directory (certificate: ca_cert.pem and key: ca_key.pem).\n\nTo start the server use the following command -\n```\npython pytest_pre_encrypted_ota.py build 8070 server_certs\n```\n\n1. build - build directory (where the new firmware image is present) will be exposed\n2. 8070 - server port (user can use any port)\n3. server_certs - cert directory where the certificate and key is present (here same ca_cert.pem is used in main/pre_encrypted_ota.c and server_certs dir). If user wants to use own certificate and key just pass the directory name, in which the certificate and key is present.\n\n* Note - If you don't want to create certificates then just run the `pytest_pre_encrypted_ota.py` without passing `server_certs` directory, the server will use the hardcoded certificates present in `pytest_pre_encrypted_ota.py`\n\n## Configuration\n\nRefer the README.md in the parent directory for the setup details.\n"
  },
  {
    "path": "esp_encrypted_img/examples/pre_encrypted_ota/ecc_key/public.pem",
    "content": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE6TXYz6Z507EZpQyXxI/+Lk5OunqO\n+Sv8zEFOGfhUGqt7P7KiAldMASLaLy5d9mOkl+FhwSRzf+vM54b7CoKhUg==\n-----END PUBLIC KEY-----\n"
  },
  {
    "path": "esp_encrypted_img/examples/pre_encrypted_ota/main/CMakeLists.txt",
    "content": "idf_build_get_property(project_dir PROJECT_DIR)\n\nset(SRCS \"\")\nset(INCLUDE_DIRS \"\")\nset(EMBED_TXTFILES \"\")\n\nif(CONFIG_EXAMPLE_ENABLE_CI_TEST)\n    list(APPEND SRCS\n        \"tests/test_local_server_ota.c\")\n    list(APPEND INCLUDE_DIRS \"tests\")\n    list(APPEND EMBED_TXTFILES \"tests/certs/servercert.pem\"\n                               \"tests/certs/prvtkey.pem\")\nendif()\n\nidf_component_register(SRCS \"pre_encrypted_ota.c\" ${SRCS}\n                    PRIV_REQUIRES esp_http_client app_update esp_https_ota nvs_flash esp_netif esp_wifi esp_netif esp_partition mbedtls\n                    INCLUDE_DIRS \".\" ${INCLUDE_DIRS}\n                    EMBED_TXTFILES ${project_dir}/rsa_key/private.pem\n                                   ${project_dir}/server_certs/ca_cert.pem\n                                   ${EMBED_TXTFILES})\n\nif(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n    set(KEY_FILE \"${project_dir}/rsa_key/private.pem\")\nelseif(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\n    set(KEY_FILE \"${project_dir}/ecc_key/public.pem\")\nelse()\n    message(FATAL_ERROR \"Unsupported encryption scheme\")\nendif()\n\ncreate_esp_enc_img(${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.bin\n    ${KEY_FILE} ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}_secure.bin app)\n\nif(CONFIG_EXAMPLE_ENABLE_CI_TEST)\n    target_link_libraries(${COMPONENT_LIB} PRIVATE idf::esp_https_server)\nendif()\n\nif(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    set(TARGET_CHIP $ENV{IDF_TARGET})\n    # This is skipped unless esp_secure_cert_mgr\n    # can generate secure partition without providing port\n    # create_esp_enc_img_secure_cert_data(${TARGET_CHIP} ${KEY_FILE} \"RSA 3072\")\n    idf_component_optional_requires(PRIVATE espressif__esp_secure_cert_mgr)\nendif()\n"
  },
  {
    "path": "esp_encrypted_img/examples/pre_encrypted_ota/main/Kconfig.projbuild",
    "content": "menu \"Example Configuration\"\n\n    config EXAMPLE_FIRMWARE_UPGRADE_URL\n        string \"firmware upgrade url endpoint\"\n        default \"https://192.168.0.3:8070/hello_world.bin\"\n        help\n            URL of server which hosts the encrypted firmware image.\n\n    config EXAMPLE_FIRMWARE_UPGRADE_URL_FROM_STDIN\n        bool\n        default y if EXAMPLE_FIRMWARE_UPGRADE_URL = \"FROM_STDIN\"\n\n    config EXAMPLE_SKIP_COMMON_NAME_CHECK\n        bool \"Skip server certificate CN fieldcheck\"\n        default n\n        help\n            This allows you to skip the validation of OTA server certificate CN field.\n\n    config EXAMPLE_SKIP_VERSION_CHECK\n        bool \"Skip firmware version check\"\n        default n\n        help\n            This allows you to skip the firmware version check.\n\n    config EXAMPLE_OTA_RECV_TIMEOUT\n        int \"OTA Receive Timeout\"\n        default 5000\n        help\n            Maximum time for reception\n\n    config EXAMPLE_ENABLE_PARTIAL_HTTP_DOWNLOAD\n        bool \"Enable partial HTTP download\"\n        default n\n        select ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD\n        select ESP_TLS_CLIENT_SESSION_TICKETS\n        help\n            This enables use of Range header in esp_https_ota component.\n            The firmware image will be downloaded over multiple HTTP requests,\n            with session resumption enabled between them.\n\n    config EXAMPLE_HTTP_REQUEST_SIZE\n        int \"HTTP request size\"\n        default MBEDTLS_SSL_IN_CONTENT_LEN\n        depends on EXAMPLE_ENABLE_PARTIAL_HTTP_DOWNLOAD\n        help\n            This options specifies HTTP request size. Number of bytes specified\n            in this option will be downloaded in single HTTP request.\n\n    config EXAMPLE_ENABLE_CI_TEST\n        bool \"Enable the CI test code\"\n        default n\n        help\n            This enables the CI test code i.e. https local server code.\n\n    config EXAMPLE_USE_CERT_BUNDLE\n        bool \"Enable certificate bundle\"\n        default y\n        depends on MBEDTLS_CERTIFICATE_BUNDLE\n        help\n            Enable trusted root certificate bundle. This approach allows to have\n            OTA updates functional with any public server without requirement\n            to explicitly add its server certificate.\nendmenu\n"
  },
  {
    "path": "esp_encrypted_img/examples/pre_encrypted_ota/main/idf_component.yml",
    "content": "dependencies:\n  espressif/esp_encrypted_img:\n    version: '*'\n    override_path: ../../../\n  protocol_examples_common:\n    path: ${IDF_PATH}/examples/common_components/protocol_examples_common\n\n"
  },
  {
    "path": "esp_encrypted_img/examples/pre_encrypted_ota/main/pre_encrypted_ota.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n/* Pre Encrypted HTTPS OTA example\n\n   This example code is in the Public Domain (or CC0 licensed, at your option.)\n\n   Unless required by applicable law or agreed to in writing, this\n   software is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n   CONDITIONS OF ANY KIND, either express or implied.\n*/\n\n#include <string.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"freertos/event_groups.h\"\n#include \"esp_system.h\"\n#include \"esp_event.h\"\n#include \"esp_log.h\"\n#include \"esp_ota_ops.h\"\n#include \"esp_http_client.h\"\n#include \"esp_https_ota.h\"\n#include \"esp_idf_version.h\"\n#include \"nvs.h\"\n#include \"nvs_flash.h\"\n#include \"protocol_examples_common.h\"\n#include \"esp_encrypted_img.h\"\n#ifdef CONFIG_EXAMPLE_USE_CERT_BUNDLE\n#include \"esp_crt_bundle.h\"\n#endif\n#if CONFIG_EXAMPLE_ENABLE_CI_TEST\n#include \"test_local_server_ota.h\"\n#endif\n#if CONFIG_EXAMPLE_CONNECT_WIFI\n#include \"esp_wifi.h\"\n#endif\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA) && defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n#include \"esp_secure_cert_read.h\"\n#endif\n\nstatic const char *TAG = \"pre_encrypted_ota_example\";\nextern const char server_cert_pem_start[] asm(\"_binary_ca_cert_pem_start\");\nextern const char server_cert_pem_end[] asm(\"_binary_ca_cert_pem_end\");\n\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\nextern const char rsa_private_pem_start[] asm(\"_binary_private_pem_start\");\nextern const char rsa_private_pem_end[]   asm(\"_binary_private_pem_end\");\n#elif defined(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\n#define HMAC_UP_KEY_ID 2\n#else\n#error \"Please select a valid encryption algorithm in menuconfig\"\n#endif\n\nstatic esp_err_t validate_image_header(esp_app_desc_t *new_app_info)\n{\n    if (new_app_info == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    const esp_partition_t *running = esp_ota_get_running_partition();\n    esp_app_desc_t running_app_info;\n    if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK) {\n        ESP_LOGI(TAG, \"Running firmware version: %s\", running_app_info.version);\n    }\n\n#ifndef CONFIG_EXAMPLE_SKIP_VERSION_CHECK\n    if (memcmp(new_app_info->version, running_app_info.version, sizeof(new_app_info->version)) == 0) {\n        ESP_LOGW(TAG, \"Current running version is the same as a new. We will not continue the update.\");\n        return ESP_FAIL;\n    }\n#endif\n    return ESP_OK;\n}\n\nstatic esp_err_t _decrypt_cb(decrypt_cb_arg_t *args, void *user_ctx)\n{\n    if (args == NULL || user_ctx == NULL) {\n        ESP_LOGE(TAG, \"_decrypt_cb: Invalid argument\");\n        return ESP_ERR_INVALID_ARG;\n    }\n    esp_err_t err;\n    pre_enc_decrypt_arg_t pargs = {};\n    pargs.data_in = args->data_in;\n    pargs.data_in_len = args->data_in_len;\n    err = esp_encrypted_img_decrypt_data((esp_decrypt_handle_t *)user_ctx, &pargs);\n    if (err != ESP_OK && err != ESP_ERR_NOT_FINISHED) {\n        ESP_LOGE(TAG, \"Decrypt callback failed %d\", err);\n        free(pargs.data_out);\n        return err;\n    }\n\n    static bool is_image_verified = false;\n    if (pargs.data_out_len > 0) {\n        args->data_out = pargs.data_out;\n        args->data_out_len = pargs.data_out_len;\n        if (!is_image_verified) {\n            is_image_verified = true;\n            const int app_desc_offset = sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t);\n            // It is unlikely to not have App Descriptor available in first iteration of decrypt callback.\n            assert(args->data_out_len >= app_desc_offset + sizeof(esp_app_desc_t));\n            esp_app_desc_t *app_info = (esp_app_desc_t *) &args->data_out[app_desc_offset];\n            err = validate_image_header(app_info);\n            if (err != ESP_OK) {\n                free(pargs.data_out);\n            }\n            return err;\n        }\n    } else {\n        args->data_out_len = 0;\n    }\n\n    return ESP_OK;\n}\n\nvoid pre_encrypted_ota_task(void *pvParameter)\n{\n    ESP_LOGI(TAG, \"Starting Pre Encrypted OTA example\");\n\n    esp_http_client_config_t config = {\n        .url = CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL,\n        .timeout_ms = CONFIG_EXAMPLE_OTA_RECV_TIMEOUT,\n#ifdef CONFIG_EXAMPLE_USE_CERT_BUNDLE\n        .crt_bundle_attach = esp_crt_bundle_attach,\n#else\n        .cert_pem = (char *)server_cert_pem_start,\n#endif /* CONFIG_EXAMPLE_USE_CERT_BUNDLE */\n        .keep_alive_enable = true,\n#if ESP_IDF_VERSION_MAJOR > 5 || (ESP_IDF_VERSION_MAJOR == 5 && ESP_IDF_VERSION_MINOR > 2)\n#ifdef CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS\n        .save_client_session = true,\n#endif\n#endif\n    };\n    esp_decrypt_cfg_t cfg = {0};\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n#if defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    esp_ds_data_ctx_t *ds_data = esp_secure_cert_get_ds_ctx();\n    if (ds_data == NULL) {\n        ESP_LOGE(TAG, \"Failed to get DS context\");\n        vTaskDelete(NULL);\n    }\n    cfg.ds_data = ds_data;\n#else\n    cfg.rsa_priv_key = rsa_private_pem_start;\n    cfg.rsa_priv_key_len = rsa_private_pem_end - rsa_private_pem_start;\n#endif /* CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n#elif defined(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\n    cfg.hmac_key_id = HMAC_UP_KEY_ID;\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_RSA */\n    esp_decrypt_handle_t decrypt_handle = esp_encrypted_img_decrypt_start(&cfg);\n    if (!decrypt_handle) {\n        ESP_LOGE(TAG, \"OTA upgrade failed\");\n        vTaskDelete(NULL);\n    }\n\n#if CONFIG_EXAMPLE_ENABLE_CI_TEST\n    example_test_firmware_data_from_stdin(&config.url);\n#endif\n\n#ifdef CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK\n    config.skip_cert_common_name_check = true;\n#endif\n\n    esp_https_ota_config_t ota_config = {\n        .http_config = &config,\n#ifdef CONFIG_EXAMPLE_ENABLE_PARTIAL_HTTP_DOWNLOAD\n        .partial_http_download = true,\n        .max_http_request_size = CONFIG_EXAMPLE_HTTP_REQUEST_SIZE,\n#endif\n        .decrypt_cb = _decrypt_cb,\n        .decrypt_user_ctx = (void *)decrypt_handle,\n        .enc_img_header_size = esp_encrypted_img_get_header_size(),\n    };\n\n    esp_https_ota_handle_t https_ota_handle = NULL;\n    esp_err_t err = esp_https_ota_begin(&ota_config, &https_ota_handle);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"ESP HTTPS OTA Begin failed\");\n        vTaskDelete(NULL);\n    }\n\n    while (1) {\n        err = esp_https_ota_perform(https_ota_handle);\n        if (err != ESP_ERR_HTTPS_OTA_IN_PROGRESS) {\n            break;\n        }\n        // esp_https_ota_perform returns after every read operation which gives user the ability to\n        // monitor the status of OTA upgrade by calling esp_https_ota_get_image_len_read, which gives length of image\n        // data read so far.\n        ESP_LOGD(TAG, \"Image bytes read: %d\", esp_https_ota_get_image_len_read(https_ota_handle));\n    }\n\n    if (!esp_https_ota_is_complete_data_received(https_ota_handle)) {\n        // the OTA image was not completely received and user can customise the response to this situation.\n        ESP_LOGE(TAG, \"Complete data was not received.\");\n    } else {\n        err = esp_encrypted_img_decrypt_end(decrypt_handle);\n        if (err != ESP_OK) {\n            goto ota_end;\n        }\n        esp_err_t ota_finish_err = esp_https_ota_finish(https_ota_handle);\n        if ((err == ESP_OK) && (ota_finish_err == ESP_OK)) {\n            ESP_LOGI(TAG, \"ESP_HTTPS_OTA upgrade successful. Rebooting ...\");\n            vTaskDelay(1000 / portTICK_PERIOD_MS);\n            esp_restart();\n        } else {\n            if (ota_finish_err == ESP_ERR_OTA_VALIDATE_FAILED) {\n                ESP_LOGE(TAG, \"Image validation failed, image is corrupted\");\n            }\n            ESP_LOGE(TAG, \"ESP_HTTPS_OTA upgrade failed 0x%x\", ota_finish_err);\n            vTaskDelete(NULL);\n        }\n    }\n\nota_end:\n    esp_https_ota_abort(https_ota_handle);\n    esp_encrypted_img_decrypt_abort(decrypt_handle);\n    ESP_LOGE(TAG, \"ESP_HTTPS_OTA upgrade failed\");\n    vTaskDelete(NULL);\n}\n\nvoid app_main(void)\n{\n    // Initialize NVS.\n    esp_err_t err = nvs_flash_init();\n    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {\n        // 1.OTA app partition table has a smaller NVS partition size than the non-OTA\n        // partition table. This size mismatch may cause NVS initialization to fail.\n        // 2.NVS partition contains data in new format and cannot be recognized by this version of code.\n        // If this happens, we erase NVS partition and initialize NVS again.\n        ESP_ERROR_CHECK(nvs_flash_erase());\n        err = nvs_flash_init();\n    }\n    ESP_ERROR_CHECK( err );\n\n    ESP_ERROR_CHECK(esp_netif_init());\n    ESP_ERROR_CHECK(esp_event_loop_create_default());\n\n    /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.\n     * Read \"Establishing Wi-Fi or Ethernet Connection\" section in\n     * examples/protocols/README.md for more information about this function.\n    */\n    ESP_ERROR_CHECK(example_connect());\n\n#if CONFIG_EXAMPLE_CONNECT_WIFI\n    /* Ensure to disable any WiFi power save mode, this allows best throughput\n     * and hence timings for overall OTA operation.\n     */\n    esp_wifi_set_ps(WIFI_PS_NONE);\n#endif // CONFIG_EXAMPLE_CONNECT_WIFI\n\n#if CONFIG_EXAMPLE_ENABLE_CI_TEST\n    if (example_test_start_webserver() != ESP_OK) {\n        ESP_LOGE(TAG, \"Unable to start server\");\n    }\n#endif\n    xTaskCreate(&pre_encrypted_ota_task, \"pre_encrypted_ota_task\", 1024 * 8, NULL, 5, NULL);\n}\n"
  },
  {
    "path": "esp_encrypted_img/examples/pre_encrypted_ota/main/tests/certs/prvtkey.pem",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwYp7epz++0QkH\nJioMD7U7BitLgpcYPi8Cid1l7snt6Kp546iQsDBJ3l8xnRtPU7ANEsjT8KxIHmyw\nh/NGp94FlOKRw3ahh3yUGtowS9vdHv+S+TAfuj07NjSnKIyv5KnGZJ+fDFl4Q1tT\naQJybY1Z4itirL6/2CGEm8g/iYhLNDBsRMfpDpfXe4URyWiM3Rhf7ztqZdveb9al\n3pAJZIDTLWCFQI1MvQjKamkAQkES/gZj0iUZFwbGJPBj54nkuLFLKedw7DbwgrVg\n0+n3fQ9b/gQepw5PxQjyobY2DsDgGZV+MFjUmaUTa+XX68SrG4wJ+DwrkdmpHReB\nvFi1Hg1hAgMBAAECggEAaTCnZkl/7qBjLexIryC/CBBJyaJ70W1kQ7NMYfniWwui\nf0aRxJgOdD81rjTvkINsPp+xPRQO6oOadjzdjImYEuQTqrJTEUnntbu924eh+2D9\nMf2CAanj0mglRnscS9mmljZ0KzoGMX6Z/EhnuS40WiJTlWlH6MlQU/FDnwC6U34y\nJKy6/jGryfsx+kGU/NRvKSru6JYJWt5v7sOrymHWD62IT59h3blOiP8GMtYKeQlX\n49om9Mo1VTIFASY3lrxmexbY+6FG8YO+tfIe0tTAiGrkb9Pz6tYbaj9FjEWOv4Vc\n+3VMBUVdGJjgqvE8fx+/+mHo4Rg69BUPfPSrpEg7sQKBgQDlL85G04VZgrNZgOx6\npTlCCl/NkfNb1OYa0BELqWINoWaWQHnm6lX8YjrUjwRpBF5s7mFhguFjUjp/NW6D\n0EEg5BmO0ePJ3dLKSeOA7gMo7y7kAcD/YGToqAaGljkBI+IAWK5Su5yldrECTQKG\nYnMKyQ1MWUfCYEwHtPvFvE5aPwKBgQDFBWXekpxHIvt/B41Cl/TftAzE7/f58JjV\nMFo/JCh9TDcH6N5TMTRS1/iQrv5M6kJSSrHnq8pqDXOwfHLwxetpk9tr937VRzoL\nCuG1Ar7c1AO6ujNnAEmUVC2DppL/ck5mRPWK/kgLwZSaNcZf8sydRgphsW1ogJin\n7g0nGbFwXwKBgQCPoZY07Pr1TeP4g8OwWTu5F6dSvdU2CAbtZthH5q98u1n/cAj1\nnoak1Srpa3foGMTUn9CHu+5kwHPIpUPNeAZZBpq91uxa5pnkDMp3UrLIRJ2uZyr8\n4PxcknEEh8DR5hsM/IbDcrCJQglM19ZtQeW3LKkY4BsIxjDf45ymH407IQKBgE/g\nUl6cPfOxQRlNLH4VMVgInSyyxWx1mODFy7DRrgCuh5kTVh+QUVBM8x9lcwAn8V9/\nnQT55wR8E603pznqY/jX0xvAqZE6YVPcw4kpZcwNwL1RhEl8GliikBlRzUL3SsW3\nq30AfqEViHPE3XpE66PPo6Hb1ymJCVr77iUuC3wtAoGBAIBrOGunv1qZMfqmwAY2\nlxlzRgxgSiaev0lTNxDzZkmU/u3dgdTwJ5DDANqPwJc6b8SGYTp9rQ0mbgVHnhIB\njcJQBQkTfq6Z0H6OoTVi7dPs3ibQJFrtkoyvYAbyk36quBmNRjVh6rc8468bhXYr\nv/t+MeGJP/0Zw8v/X2CFll96\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "esp_encrypted_img/examples/pre_encrypted_ota/main/tests/certs/servercert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDKzCCAhOgAwIBAgIUBxM3WJf2bP12kAfqhmhhjZWv0ukwDQYJKoZIhvcNAQEL\nBQAwJTEjMCEGA1UEAwwaRVNQMzIgSFRUUFMgc2VydmVyIGV4YW1wbGUwHhcNMTgx\nMDE3MTEzMjU3WhcNMjgxMDE0MTEzMjU3WjAlMSMwIQYDVQQDDBpFU1AzMiBIVFRQ\nUyBzZXJ2ZXIgZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nALBint6nP77RCQcmKgwPtTsGK0uClxg+LwKJ3WXuye3oqnnjqJCwMEneXzGdG09T\nsA0SyNPwrEgebLCH80an3gWU4pHDdqGHfJQa2jBL290e/5L5MB+6PTs2NKcojK/k\nqcZkn58MWXhDW1NpAnJtjVniK2Ksvr/YIYSbyD+JiEs0MGxEx+kOl9d7hRHJaIzd\nGF/vO2pl295v1qXekAlkgNMtYIVAjUy9CMpqaQBCQRL+BmPSJRkXBsYk8GPnieS4\nsUsp53DsNvCCtWDT6fd9D1v+BB6nDk/FCPKhtjYOwOAZlX4wWNSZpRNr5dfrxKsb\njAn4PCuR2akdF4G8WLUeDWECAwEAAaNTMFEwHQYDVR0OBBYEFMnmdJKOEepXrHI/\nivM6mVqJgAX8MB8GA1UdIwQYMBaAFMnmdJKOEepXrHI/ivM6mVqJgAX8MA8GA1Ud\nEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADiXIGEkSsN0SLSfCF1VNWO3\nemBurfOcDq4EGEaxRKAU0814VEmU87btIDx80+z5Dbf+GGHCPrY7odIkxGNn0DJY\nW1WcF+DOcbiWoUN6DTkAML0SMnp8aGj9ffx3x+qoggT+vGdWVVA4pgwqZT7Ybntx\nbkzcNFW0sqmCv4IN1t4w6L0A87ZwsNwVpre/j6uyBw7s8YoJHDLRFT6g7qgn0tcN\nZufhNISvgWCVJQy/SZjNBHSpnIdCUSJAeTY2mkM4sGxY0Widk8LnjydxZUSxC3Nl\nhb6pnMh3jRq4h0+5CZielA4/a+TdrNPv/qok67ot/XJdY3qHCCd8O2b14OVq9jo=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "esp_encrypted_img/examples/pre_encrypted_ota/main/tests/test_local_server_ota.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n/* Pre Encrypted HTTPS OTA example's test file\n\n   This example code is in the Public Domain (or CC0 licensed, at your option.)\n\n   Unless required by applicable law or agreed to in writing, this\n   software is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n   CONDITIONS OF ANY KIND, either express or implied.\n*/\n#include \"esp_https_server.h\"\n#include \"esp_log.h\"\n#include \"nvs_flash.h\"\n#include \"test_local_server_ota.h\"\n#include \"protocol_examples_common.h\"\n\n#define OTA_URL_SIZE 256\n#define PARTITION_READ_BUFFER_SIZE 256\n#define PARTITION_READ_SIZE PARTITION_READ_BUFFER_SIZE\n\nstatic const char *TAG = \"test_local_server_ota\";\nstatic size_t binary_size;\n\n#ifdef CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL_FROM_STDIN\nvoid example_test_firmware_data_from_stdin(const char **data)\n{\n    char input_buf[OTA_URL_SIZE];\n    if (strcmp(*data, \"FROM_STDIN\") == 0) {\n        example_configure_stdin_stdout();\n        fflush(stdin);\n        char *url = NULL;\n        char *tokens[OTA_URL_SIZE], *saveptr;\n        int token_count = 0;\n\n        fgets(input_buf, OTA_URL_SIZE, stdin);\n        int len = strlen(input_buf);\n        if (len > 0 && input_buf[len - 1] == '\\n') {\n            input_buf[len - 1] = '\\0';\n        }\n        char *token = strtok_r(input_buf, \" \", &saveptr);\n        if (token == NULL) {\n            return;\n        }\n        // First token is the URL\n        url = token;\n        tokens[token_count++] = url;\n        // Process remaining tokens\n        while ((token = strtok_r(NULL, \" \", &saveptr)) != NULL) {\n            tokens[token_count++] = token;\n        }\n        // Return if no further data is captured\n        if (strchr(input_buf, ' ') != NULL) {\n            return;\n        }\n        *data = strdup(tokens[0]);\n        // Assign the URL and additional data after the loop\n        if (token_count > 1) {\n            ESP_LOGI(TAG, \"binary_size: %s\\n\", tokens[1]);\n            binary_size = atoi(tokens[1]); // Assuming the next token is the binary size\n        }\n        // Tokens are collected in the tokens array\n    } else {\n        ESP_LOGE(TAG, \"Configuration mismatch: wrong firmware upgrade image url\");\n        abort();\n    }\n}\n#endif\n/* An HTTP GET handler */\nstatic esp_err_t root_get_handler(httpd_req_t *req)\n{\n    httpd_resp_set_type(req, \"text/plain\");\n    const esp_partition_t *p = esp_partition_find_first(ESP_PARTITION_TYPE_APP,\n                               ESP_PARTITION_SUBTYPE_APP_OTA_1, NULL);\n\n\n    assert(p != NULL);\n\n    if (binary_size == 0) {\n        return ESP_FAIL;\n    }\n\n    int image_len = binary_size;\n    char buffer[PARTITION_READ_BUFFER_SIZE];\n    int size = PARTITION_READ_SIZE;\n    int offset = 0;\n\n    do {\n        /* Read file in chunks into the scratch buffer */\n        if (offset + size > image_len) {\n            size = image_len - offset;\n        }\n        if (size == 0) {\n            break;\n        }\n        esp_err_t ret = esp_partition_read(p, offset, buffer, size);\n        if (ret == ESP_OK) {\n            /* Send the buffer contents as HTTP response chunk */\n            if (httpd_resp_send_chunk(req, buffer, size) != ESP_OK) {\n                ESP_LOGE(TAG, \"File sending failed!\");\n                /* Abort sending file */\n                httpd_resp_sendstr_chunk(req, NULL);\n                /* Respond with 500 Internal Server Error */\n                httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, \"Failed to send file\");\n                return ESP_FAIL;\n            }\n        }\n        offset += size;\n\n        /* Keep looping till the whole file is sent */\n    } while (offset <= image_len);\n\n    ESP_LOGI(TAG, \"File sending complete\");\n\n    // Set headers\n    httpd_resp_set_type(req, \"application/octet-stream\");\n    httpd_resp_set_hdr(req, \"Accept-Ranges\", \"bytes\");\n    httpd_resp_set_hdr(req, \"Connection\", \"close\");\n    httpd_resp_send_chunk(req, NULL, 0);\n\n    return ESP_OK;\n}\n\nstatic esp_err_t root_head_handler(httpd_req_t *req)\n{\n    const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1, NULL);\n\n    if (partition == NULL) {\n        ESP_LOGE(TAG, \"Partition not found\");\n        httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, \"Partition not found\");\n        return ESP_FAIL;\n    }\n\n    if (binary_size == 0) {\n        return ESP_FAIL;\n    }\n    // Get the size of the binary\n    httpd_resp_set_type(req, \"application/octet-stream\");\n    httpd_resp_set_hdr(req, \"Accept-Ranges\", \"bytes\");\n    httpd_resp_set_hdr(req, \"Connection\", \"close\");\n\n    // Complete HEAD response with no body\n    return httpd_resp_send(req, NULL, binary_size); // No body for HEAD method\n}\n\nstatic const httpd_uri_t get_root = {\n    .uri       = \"/\",\n    .method    = HTTP_GET,\n    .handler   = root_get_handler\n};\n\nstatic const httpd_uri_t head_root = {\n    .uri       = \"/\",\n    .method    = HTTP_HEAD,\n    .handler   = root_head_handler\n\n};\n\nesp_err_t example_test_start_webserver(void)\n{\n    httpd_handle_t server = NULL;\n    // Start the httpd server\n    ESP_LOGI(TAG, \"Starting server\");\n\n    httpd_ssl_config_t conf = HTTPD_SSL_CONFIG_DEFAULT();\n\n    extern const unsigned char servercert_start[] asm(\"_binary_servercert_pem_start\");\n    extern const unsigned char servercert_end[]   asm(\"_binary_servercert_pem_end\");\n    conf.servercert = servercert_start;\n    conf.servercert_len = servercert_end - servercert_start;\n\n    extern const unsigned char prvtkey_pem_start[] asm(\"_binary_prvtkey_pem_start\");\n    extern const unsigned char prvtkey_pem_end[]   asm(\"_binary_prvtkey_pem_end\");\n    conf.prvtkey_pem = prvtkey_pem_start;\n    conf.prvtkey_len = prvtkey_pem_end - prvtkey_pem_start;\n\n    esp_err_t ret = httpd_ssl_start(&server, &conf);\n    if (ESP_OK != ret) {\n        ESP_LOGI(TAG, \"Error starting server!\");\n        return ret;\n    }\n\n    // Set URI handlers\n    ESP_LOGI(TAG, \"Registering URI handlers\");\n    httpd_register_uri_handler(server, &get_root);\n    httpd_register_uri_handler(server, &head_root);\n    return ESP_OK;\n}\n"
  },
  {
    "path": "esp_encrypted_img/examples/pre_encrypted_ota/main/tests/test_local_server_ota.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n#include \"esp_https_server.h\"\n\n/**\n * @brief starts the https server\n *\n * @param bin_size the size of binary image which will be exposed\n *                 by the server. NOTE - bin_size cannot be 0.\n */\nesp_err_t example_test_start_webserver(void);\n\n/**\n * @brief Takes the firmware URL from the STDIN (if want to send\n *         other data write the data in just one line by adding \" \" deleminator).\n *\n * @param data pointer to the firmware URL (or URL including other data)\n */\nvoid example_test_firmware_data_from_stdin(const char **data);\n"
  },
  {
    "path": "esp_encrypted_img/examples/pre_encrypted_ota/partitions.csv",
    "content": "# Name,   Type, SubType, Offset,   Size,     Flags\nesp_secure_cert,0x3F,,,0x2000,\nnvs,      data, nvs,     ,        0x4000,\notadata,  data, ota,     ,        0x2000,\nphy_init, data, phy,     ,        0x1000,\nfactory,  app,  factory, ,        0x13A000,\nota_0,    app,  ota_0,   ,        0x13A000,\nota_1,    app,  ota_1,   ,        0x13A000,\n"
  },
  {
    "path": "esp_encrypted_img/examples/pre_encrypted_ota/pytest_pre_encrypted_ota.py",
    "content": "# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport http.server\nimport multiprocessing\nimport os\nimport sys\n\nimport socket\nimport ssl\nfrom typing import Optional\nfrom typing import Callable\n\nimport pexpect\nimport pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.app import FlashFile\nfrom pytest_embedded_idf.serial import IdfSerial\n\nenc_bin_name = 'pre_encrypted_ota_secure.bin'\nhost_ip = '127.0.0.1'\nserver_port = 443\n\nserver_cert = '-----BEGIN CERTIFICATE-----\\n'\\\n             'MIIDKzCCAhOgAwIBAgIUBxM3WJf2bP12kAfqhmhhjZWv0ukwDQYJKoZIhvcNAQEL\\n'\\\n             'BQAwJTEjMCEGA1UEAwwaRVNQMzIgSFRUUFMgc2VydmVyIGV4YW1wbGUwHhcNMTgx\\n'\\\n             'MDE3MTEzMjU3WhcNMjgxMDE0MTEzMjU3WjAlMSMwIQYDVQQDDBpFU1AzMiBIVFRQ\\n'\\\n             'UyBzZXJ2ZXIgZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\\n'\\\n             'ALBint6nP77RCQcmKgwPtTsGK0uClxg+LwKJ3WXuye3oqnnjqJCwMEneXzGdG09T\\n'\\\n             'sA0SyNPwrEgebLCH80an3gWU4pHDdqGHfJQa2jBL290e/5L5MB+6PTs2NKcojK/k\\n'\\\n             'qcZkn58MWXhDW1NpAnJtjVniK2Ksvr/YIYSbyD+JiEs0MGxEx+kOl9d7hRHJaIzd\\n'\\\n             'GF/vO2pl295v1qXekAlkgNMtYIVAjUy9CMpqaQBCQRL+BmPSJRkXBsYk8GPnieS4\\n'\\\n             'sUsp53DsNvCCtWDT6fd9D1v+BB6nDk/FCPKhtjYOwOAZlX4wWNSZpRNr5dfrxKsb\\n'\\\n             'jAn4PCuR2akdF4G8WLUeDWECAwEAAaNTMFEwHQYDVR0OBBYEFMnmdJKOEepXrHI/\\n'\\\n             'ivM6mVqJgAX8MB8GA1UdIwQYMBaAFMnmdJKOEepXrHI/ivM6mVqJgAX8MA8GA1Ud\\n'\\\n             'EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADiXIGEkSsN0SLSfCF1VNWO3\\n'\\\n             'emBurfOcDq4EGEaxRKAU0814VEmU87btIDx80+z5Dbf+GGHCPrY7odIkxGNn0DJY\\n'\\\n             'W1WcF+DOcbiWoUN6DTkAML0SMnp8aGj9ffx3x+qoggT+vGdWVVA4pgwqZT7Ybntx\\n'\\\n             'bkzcNFW0sqmCv4IN1t4w6L0A87ZwsNwVpre/j6uyBw7s8YoJHDLRFT6g7qgn0tcN\\n'\\\n             'ZufhNISvgWCVJQy/SZjNBHSpnIdCUSJAeTY2mkM4sGxY0Widk8LnjydxZUSxC3Nl\\n'\\\n             'hb6pnMh3jRq4h0+5CZielA4/a+TdrNPv/qok67ot/XJdY3qHCCd8O2b14OVq9jo=\\n'\\\n             '-----END CERTIFICATE-----\\n'\n\nserver_key = '-----BEGIN PRIVATE KEY-----\\n'\\\n             'MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwYp7epz++0QkH\\n'\\\n             'JioMD7U7BitLgpcYPi8Cid1l7snt6Kp546iQsDBJ3l8xnRtPU7ANEsjT8KxIHmyw\\n'\\\n             'h/NGp94FlOKRw3ahh3yUGtowS9vdHv+S+TAfuj07NjSnKIyv5KnGZJ+fDFl4Q1tT\\n'\\\n             'aQJybY1Z4itirL6/2CGEm8g/iYhLNDBsRMfpDpfXe4URyWiM3Rhf7ztqZdveb9al\\n'\\\n             '3pAJZIDTLWCFQI1MvQjKamkAQkES/gZj0iUZFwbGJPBj54nkuLFLKedw7DbwgrVg\\n'\\\n             '0+n3fQ9b/gQepw5PxQjyobY2DsDgGZV+MFjUmaUTa+XX68SrG4wJ+DwrkdmpHReB\\n'\\\n             'vFi1Hg1hAgMBAAECggEAaTCnZkl/7qBjLexIryC/CBBJyaJ70W1kQ7NMYfniWwui\\n'\\\n             'f0aRxJgOdD81rjTvkINsPp+xPRQO6oOadjzdjImYEuQTqrJTEUnntbu924eh+2D9\\n'\\\n             'Mf2CAanj0mglRnscS9mmljZ0KzoGMX6Z/EhnuS40WiJTlWlH6MlQU/FDnwC6U34y\\n'\\\n             'JKy6/jGryfsx+kGU/NRvKSru6JYJWt5v7sOrymHWD62IT59h3blOiP8GMtYKeQlX\\n'\\\n             '49om9Mo1VTIFASY3lrxmexbY+6FG8YO+tfIe0tTAiGrkb9Pz6tYbaj9FjEWOv4Vc\\n'\\\n             '+3VMBUVdGJjgqvE8fx+/+mHo4Rg69BUPfPSrpEg7sQKBgQDlL85G04VZgrNZgOx6\\n'\\\n             'pTlCCl/NkfNb1OYa0BELqWINoWaWQHnm6lX8YjrUjwRpBF5s7mFhguFjUjp/NW6D\\n'\\\n             '0EEg5BmO0ePJ3dLKSeOA7gMo7y7kAcD/YGToqAaGljkBI+IAWK5Su5yldrECTQKG\\n'\\\n             'YnMKyQ1MWUfCYEwHtPvFvE5aPwKBgQDFBWXekpxHIvt/B41Cl/TftAzE7/f58JjV\\n'\\\n             'MFo/JCh9TDcH6N5TMTRS1/iQrv5M6kJSSrHnq8pqDXOwfHLwxetpk9tr937VRzoL\\n'\\\n             'CuG1Ar7c1AO6ujNnAEmUVC2DppL/ck5mRPWK/kgLwZSaNcZf8sydRgphsW1ogJin\\n'\\\n             '7g0nGbFwXwKBgQCPoZY07Pr1TeP4g8OwWTu5F6dSvdU2CAbtZthH5q98u1n/cAj1\\n'\\\n             'noak1Srpa3foGMTUn9CHu+5kwHPIpUPNeAZZBpq91uxa5pnkDMp3UrLIRJ2uZyr8\\n'\\\n             '4PxcknEEh8DR5hsM/IbDcrCJQglM19ZtQeW3LKkY4BsIxjDf45ymH407IQKBgE/g\\n'\\\n             'Ul6cPfOxQRlNLH4VMVgInSyyxWx1mODFy7DRrgCuh5kTVh+QUVBM8x9lcwAn8V9/\\n'\\\n             'nQT55wR8E603pznqY/jX0xvAqZE6YVPcw4kpZcwNwL1RhEl8GliikBlRzUL3SsW3\\n'\\\n             'q30AfqEViHPE3XpE66PPo6Hb1ymJCVr77iUuC3wtAoGBAIBrOGunv1qZMfqmwAY2\\n'\\\n             'lxlzRgxgSiaev0lTNxDzZkmU/u3dgdTwJ5DDANqPwJc6b8SGYTp9rQ0mbgVHnhIB\\n'\\\n             'jcJQBQkTfq6Z0H6OoTVi7dPs3ibQJFrtkoyvYAbyk36quBmNRjVh6rc8468bhXYr\\n'\\\n             'v/t+MeGJP/0Zw8v/X2CFll96\\n'\\\n             '-----END PRIVATE KEY-----\\n'\n\ndef start_https_server(ota_image_dir: str, server_ip: str, port: int, server_file: Optional[str] = None, key_file: Optional[str] = None) -> None:\n    os.chdir(ota_image_dir)\n\n    if server_file is None:\n        server_file = os.path.join(ota_image_dir, 'server_cert.pem')\n        cert_file_handle = open(server_file, 'w+')\n        cert_file_handle.write(server_cert)\n        cert_file_handle.close()\n\n    if key_file is None:\n        key_file = os.path.join(ota_image_dir, 'server_key.pem')\n        key_file_handle = open('server_key.pem', 'w+')\n        key_file_handle.write(server_key)\n        key_file_handle.close()\n\n    httpd = http.server.HTTPServer((server_ip, port), http.server.SimpleHTTPRequestHandler)\n\n    ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)\n    ssl_context.load_cert_chain(certfile=server_file, keyfile=key_file)\n\n    httpd.socket = ssl_context.wrap_socket(httpd.socket, server_side=True)\n    httpd.serve_forever()\n\n@pytest.mark.generic\ndef test_examples_protocol_pre_encrypted_ota_example(dut: Dut) -> None:\n    bin_path = os.path.join(dut.app.binary_path, enc_bin_name)\n    bin_size = os.path.getsize(bin_path)\n    # Construct the URI\n    uri = f'https://{host_ip}:{server_port}/'\n\n    try:\n        dut.expect('Loaded app from partition at offset', timeout=30)\n        dut.expect('Starting Pre Encrypted OTA example', timeout=30)\n        dut.write(f'{uri} {bin_size}\\n')\n        dut.expect('Magic Verified', timeout=30)\n        dut.expect('Reading RSA private key', timeout=30)\n        dut.expect('upgrade successful. Rebooting', timeout=60)\n        # after reboot\n        dut.expect('Loaded app from partition at offset', timeout=30)\n    finally:\n        pass\n\n@pytest.mark.generic\n@pytest.mark.parametrize('config', ['partial_download',], indirect=True)\ndef test_examples_protocol_pre_encrypted_ota_example_partial_download(dut: Dut, config) -> None:\n    # Size of partial HTTP request\n    request_size = int(dut.app.sdkconfig.get('EXAMPLE_HTTP_REQUEST_SIZE'))\n    # File to be downloaded. This file is generated after compilation\n    bin_path = os.path.join(dut.app.binary_path, enc_bin_name)\n    bin_size = os.path.getsize(bin_path)\n\n    uri = f'https://{host_ip}:{server_port}/'\n\n    http_requests = int((bin_size / request_size) - 1)\n    assert http_requests > 1\n\n    try:\n        dut.expect('Loaded app from partition at offset', timeout=30)\n        dut.expect('Starting Pre Encrypted OTA example', timeout=30)\n        dut.write(f'{uri} {bin_size}\\n')\n        dut.expect('Magic Verified', timeout=60)\n        dut.expect('Reading RSA private key', timeout=30)\n        dut.expect('upgrade successful. Rebooting', timeout=60)\n        # after reboot\n        dut.expect('Loaded app from partition at offset', timeout=30)\n    finally:\n        pass\n\nif __name__ == '__main__':\n    if sys.argv[2:]: # if two or more arguments are provided\n        # Usage: python pytest_pre_encrypted_ota.py <image_dir> <server_port> <cert_dir>\n        this_dir = os.path.dirname(os.path.realpath(__file__))\n        bin_dir = os.path.join(this_dir, sys.argv[1])\n        port = int(sys.argv[2])\n        cert_dir = bin_dir if not sys.argv[3:] else os.path.join(this_dir, sys.argv[3])  # optional argument\n        print(f'Starting HTTPS server at \"https://0.0.0.0:{port}\"')\n        server_file=os.path.join(cert_dir, 'ca_cert.pem')\n        key_file=os.path.join(cert_dir, 'ca_key.pem')\n        #check if file exits\n        if not os.path.exists(server_file):\n            server_file = None\n        if not os.path.exists(key_file):\n            key_file = None\n\n        start_https_server(bin_dir, '', port, server_file, key_file)"
  },
  {
    "path": "esp_encrypted_img/examples/pre_encrypted_ota/rsa_key/private.pem",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIG4wIBAAKCAYEAwiweYOoQ06RE5jAHJP5Y34j0PQR6T/unqQPVg0Z0NOstMcLW\nqzqRXL3f+fAc3ooxrN+vZkriKK6dcU0qM4g69BJwRKc+VKS4uRNfQhuAeCyFgTP0\nMWJDlSZplphjDXnPoJM5WN5S/qRTQVMiBJdxycryIIqjPpVDxd3ET/xuHG2VTVlV\nMoqcqdXhKNOWGEAgWe8Kc8VpeQSdXGrhgmTdlJoLP2wy1nEOfIo/UZJV+vDqZvnX\n8hZe7l0sl6SCUJ7P/VzzSOJreDxGCBVjSJkaL3xE+8C5bX85oLcFsbFS1M2zfgLG\nRJ0Ha/PMs6CarQzhn77GjqNUY0qYmdlInJcIiQ3bkPlTsBdgDZ9m/RrMzl49ndLI\n2ZIWlTQr/gJh+kJUU02XEzRZ+bd0/v760JjIKtUKItMfiNa9OO2chvVuYs6FID+8\noICHmj90E2gz4O6WHsBf9+R9Rtn3KJ1d1d5IHYMispa+q3K6dqVFhLjgT7vVQbFE\nz2FPghtH3dZPv10BAgMBAAECggGBAL+bR7L85vPiMvcvR62Sq+KRw+n+ZDBPNghL\nt0MeoAekVum2yZ0YY18wIzgBYIudtR1RckUv+fKJNOYcbluBwCMfmte0bYabMYm4\nexTCDMkJrghsWzjsLaKd0C4CXCRtIpzjCwEOCrorL9jTj0sWovutH7dK94IHS2SS\nzWjcwU+eN2mnkLIaJDRX0SM3f/KYPRRiFV9e3BDGo/4RnkzM+fbs99JzE8uWruPo\njEkTbXL+j2BkhVroBm+TVDCj7tBdlUhhfFaBAUjwum2otO2ND4fEUdiV0PyIapP3\nUFFEU+8bqGIlWNffDzLbRBiPjma1QX4ktjfsb18TdZu+OTTps2dgiivo6x8kau+I\no3alg1RnQQyK+Wn4NRtE8Eknp33aT7HyRbH10/Vko5lnEfwTUyfdOVIGj5Jh5yvY\nheIDAQgRcvuCllr1ypDZlmd0wkqWC9nZRbLFN2NpLotSSrf69pYv3z4/beffzYsI\nQnGQmdYhX32+7BLqt+qEb4V+VlkkAQKBwQD4i9OSZYqD1iBXPGUZGioPY3ftPVIb\n6kQ94AIgNZ+HLbYzYL4QNimakPtRSrE1VxsDAn+GG1A3ncvJIqw8+tHSKecpIM5G\n4FaGzFqwpLnw3XOgHwgXRHcXRwFngf3G464KFHfZ4E6VkHeOxdfNdh+pOQlpLkYS\nWS4OuvTVJyUNvv2N3+7NELSQkAacdVf2yDIa4o17a7KP69FYxwW3Reco6MDeQU6E\ntlyXas/upGrle06DfYa02hiiF4tY5bOjCyECgcEAx/7Ye9JO0rA6ozzfFCF8RtPR\nWyKjypBXrZOmrAOzo1H0H9rB4pR+7NYa+ixN6tsv0dJylQsj7nszipzqms9WIvxA\n9hH+k4+UoOKHnNeywNVVNEswfeTaaIXMxGWGx7QNTg58hVZZQgkdgIWJxznr4REq\nbEmWgEoyDtmN5x+N4p9fjjQkboWyatJ9r7eCoiG1wzAoI9hqqcEOf49B4jCXtHIk\nbsKOs6jTbZq7aCxMkYDxyMQFyutuq01F9GRWTPXhAoHAQEwb7ZFrJfPs5eRv2vCT\n1OtMiQkGBsax5LfglOiKXnQK4Hu0b4kzdhLvkPYbpcrk6ABrcQv70od1wpC/sf7I\n7O9+J3ufIWLDv5d6FpxmpdMEKHYep7ZEgLcTu+0684rO6TimUKzgZ3y6EStJSpO2\nWRayQo1//xsm+RSQZdv8j/PKsDswEciyjXtU2oDYwrTDkYTuSPFxfh3pSGgkKGdj\nB4g+7MBESbzLczhklj3ekYM2qnl8saiCGtywZcz2jcVBAoHAWKNUYxyEntBITMzP\nueZVZDbA1Pl3SnHKyj1kY1yIo1vRLMURpVBXKLSD5Fj6d5qJiR8SdYgodqvX3hlJ\nyS8XaA4Q5H55LAE4yE1d+V+H8/sY9kJUzZc+TZDvfiPZJm1gcDXvblEk4iWUE8Ab\nnlbHekrXWIMM1vMLWJWHVOYhRk2IVkg51VogB0QfPF/C4AS8wDN5ttlV/MJ5oINn\nmc4bjngAOa60/F9YxX0MjlED5oEVp/to7dSGihmHZZeKwDVBAoHAYVNuPLf2L08u\nljOD5YnVfYFRIwfTUfOew7eQnPgfBNbgE0EUDR3ukIQKaZQzt3COA4oieSUd+dK9\nXRUJBF6EzUkBCTC22ExtdedEjdn5s6fCX63Ad5k6Olr44cINqgJtuVp3a4RnxENr\nPdhiIMkqW3rp+/0HdZNHAzDhbKM6C8AVWX4chDEVUOIaRE53+Amfebd/PGQ/7WkT\nLuAz4IA2Abj0/VXr1txQwhVk3zloLYxyacyyqQHYn+GgWPHdmQw8\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "esp_encrypted_img/examples/pre_encrypted_ota/sdkconfig.ci",
    "content": "CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL=\"FROM_STDIN\"\nCONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y\nCONFIG_EXAMPLE_SKIP_VERSION_CHECK=y\nCONFIG_EXAMPLE_OTA_RECV_TIMEOUT=3000\nCONFIG_EXAMPLE_CONNECT_WIFI=n\nCONFIG_EXAMPLE_ENABLE_CI_TEST=y\nCONFIG_EXAMPLE_CONNECT_ETHERNET=n\nCONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y\nCONFIG_PARTITION_TABLE_CUSTOM=y\nCONFIG_ESP_HTTPS_SERVER_ENABLE=y\nCONFIG_COMPILER_OPTIMIZATION_SIZE=y\n"
  },
  {
    "path": "esp_encrypted_img/examples/pre_encrypted_ota/sdkconfig.ci.partial_download",
    "content": "CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL=\"FROM_STDIN\"\nCONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y\nCONFIG_EXAMPLE_SKIP_VERSION_CHECK=y\nCONFIG_EXAMPLE_OTA_RECV_TIMEOUT=3000\nCONFIG_EXAMPLE_ENABLE_PARTIAL_HTTP_DOWNLOAD=y\nCONFIG_EXAMPLE_CONNECT_WIFI=n\nCONFIG_EXAMPLE_ENABLE_CI_TEST=y\nCONFIG_EXAMPLE_CONNECT_ETHERNET=n\nCONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y\nCONFIG_PARTITION_TABLE_CUSTOM=y\nCONFIG_ESP_HTTPS_SERVER_ENABLE=y\nCONFIG_COMPILER_OPTIMIZATION_SIZE=y\n"
  },
  {
    "path": "esp_encrypted_img/examples/pre_encrypted_ota/sdkconfig.defaults",
    "content": "# Default sdkconfig parameters to use the OTA\n# partition table layout, with a 4MB flash size\nCONFIG_ESPTOOLPY_FLASHSIZE_4MB=y\nCONFIG_PARTITION_TABLE_TWO_OTA=y\n# Enable ESP HTTPS OTA decryption callback\nCONFIG_ESP_HTTPS_OTA_DECRYPT_CB=y\n\n# Certificate bundle configuration\nCONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN=y\nCONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE=y\nCONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE_PATH=\"server_certs/ca_cert.pem\"\n"
  },
  {
    "path": "esp_encrypted_img/examples/pre_encrypted_ota/server_certs/ca_cert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDKzCCAhOgAwIBAgIUBxM3WJf2bP12kAfqhmhhjZWv0ukwDQYJKoZIhvcNAQEL\nBQAwJTEjMCEGA1UEAwwaRVNQMzIgSFRUUFMgc2VydmVyIGV4YW1wbGUwHhcNMTgx\nMDE3MTEzMjU3WhcNMjgxMDE0MTEzMjU3WjAlMSMwIQYDVQQDDBpFU1AzMiBIVFRQ\nUyBzZXJ2ZXIgZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nALBint6nP77RCQcmKgwPtTsGK0uClxg+LwKJ3WXuye3oqnnjqJCwMEneXzGdG09T\nsA0SyNPwrEgebLCH80an3gWU4pHDdqGHfJQa2jBL290e/5L5MB+6PTs2NKcojK/k\nqcZkn58MWXhDW1NpAnJtjVniK2Ksvr/YIYSbyD+JiEs0MGxEx+kOl9d7hRHJaIzd\nGF/vO2pl295v1qXekAlkgNMtYIVAjUy9CMpqaQBCQRL+BmPSJRkXBsYk8GPnieS4\nsUsp53DsNvCCtWDT6fd9D1v+BB6nDk/FCPKhtjYOwOAZlX4wWNSZpRNr5dfrxKsb\njAn4PCuR2akdF4G8WLUeDWECAwEAAaNTMFEwHQYDVR0OBBYEFMnmdJKOEepXrHI/\nivM6mVqJgAX8MB8GA1UdIwQYMBaAFMnmdJKOEepXrHI/ivM6mVqJgAX8MA8GA1Ud\nEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADiXIGEkSsN0SLSfCF1VNWO3\nemBurfOcDq4EGEaxRKAU0814VEmU87btIDx80+z5Dbf+GGHCPrY7odIkxGNn0DJY\nW1WcF+DOcbiWoUN6DTkAML0SMnp8aGj9ffx3x+qoggT+vGdWVVA4pgwqZT7Ybntx\nbkzcNFW0sqmCv4IN1t4w6L0A87ZwsNwVpre/j6uyBw7s8YoJHDLRFT6g7qgn0tcN\nZufhNISvgWCVJQy/SZjNBHSpnIdCUSJAeTY2mkM4sGxY0Widk8LnjydxZUSxC3Nl\nhb6pnMh3jRq4h0+5CZielA4/a+TdrNPv/qok67ot/XJdY3qHCCd8O2b14OVq9jo=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "esp_encrypted_img/idf_component.yml",
    "content": "version: \"2.7.1\"\ndescription: ESP Encrypted Image Abstraction Layer\nurl: https://github.com/espressif/idf-extra-components/tree/master/esp_encrypted_img\ndependencies:\n  idf:\n    version: \">=5.0\"\n  espressif/esp_secure_cert_mgr:\n    version: \">=2.5.1\"\n    rules:\n      - if: \"idf_version >= 5.3\"\n"
  },
  {
    "path": "esp_encrypted_img/include/esp_encrypted_img.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdbool.h>\n#include <esp_err.h>\n#include <esp_idf_version.h>\n\n#if 0   //High level layout for state machine\n\n// *INDENT-OFF*\n@startuml\n[*] --> READ_MAGIC\nREAD_MAGIC --> READ_MAGIC : READ LEN < 4\nREAD_MAGIC --> DECODE_MAGIC : READ LEN = 4\n\nDECODE_MAGIC --> READ_GCM : MAGIC VERIFIED\nDECODE_MAGIC --> ESP_FAIL : MAGIC VERIFICATION FAILED\nPROCESS_BINARY --> ESP_FAIL : DECRYPTION FAILED\n\nREAD_GCM --> READ_GCM : READ_LEN < 384\nREAD_GCM --> DECRYPT_GCM : READ_LEN = 384\nDECRYPT_GCM --> ESP_FAIL : DECRYPTION FAILED\nDECRYPT_GCM --> READ_IV : DECRYPTION SUCCESSFUL\nREAD_IV --> READ_IV : READ LEN < 16\nREAD_IV --> READ_BIN_SIZE\nREAD_BIN_SIZE --> READ_BIN_SIZE : READ LEN < 5\nREAD_BIN_SIZE --> READ_AUTH\nREAD_AUTH --> READ_AUTH : READ LEN < 16\nREAD_AUTH --> PROCESS_BINARY\nPROCESS_BINARY --> PROCESS_BINARY : READ LEN < BIN_SIZE\n\nPROCESS_BINARY --> ESP_OK : READ LEN = BIN_SIZE\nESP_OK --> [*]\nESP_FAIL --> [*]\n@enduml\n// *INDENT-OFF*\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0))\n#define DEPRECATED_ATTRIBUTE __attribute__((deprecated))\n#else\n#define DEPRECATED_ATTRIBUTE\n#endif\n\n#define MAGIC_SIZE          4\n#define ENC_GCM_KEY_SIZE    384\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\n#define SERVER_ECC_KEY_LEN  64\n#define KDF_SALT_SIZE       32\n#define RESERVED_SIZE       (384 - (SERVER_ECC_KEY_LEN + KDF_SALT_SIZE))\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES */\n#define IV_SIZE             16\n#define AUTH_SIZE           16\n#define BIN_SIZE_DATA       4\n#define RESERVED_HEADER     88\n\n#define ESP_ERR_ENCRYPTED_IMAGE_HMAC_KEY_NOT_FOUND 1\n\ntypedef void *esp_decrypt_handle_t;\n\ntypedef struct {\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n#if defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    void *ds_data;                         /*!< Data context for DS */\n#else\n    union {\n        const char *rsa_priv_key;                       /*!< 3072 bit RSA private key in PEM format */\n        const char *rsa_pub_key DEPRECATED_ATTRIBUTE;   /*!< This name is kept for backward compatibility purpose,\n                                                             but it is not accurate (meaning wise) and hence it would\n                                                             be removed in the next major release */\n    };\n    union {\n        size_t rsa_priv_key_len;                        /*!< Length of the buffer pointed to by rsa_priv_key */\n        size_t rsa_pub_key_len DEPRECATED_ATTRIBUTE;    /*!< This name is kept for backward compatibility purpose,\n                                                             but it is not accurate (meaning wise) and hence it would\n                                                             be removed in the next major release */\n    };\n#endif /* CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n#elif defined(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\n    int hmac_key_id;                             /*!< HMAC key ID to be used for HMAC generation */\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES */\n} esp_decrypt_cfg_t;\n\n#undef DEPRECATED_ATTRIBUTE\n\ntypedef struct {\n    const char *data_in;    /*!< Pointer to data to be decrypted */\n    size_t data_in_len;     /*!< Input data length */\n    char *data_out;         /*!< Pointer to decrypted data */\n    size_t data_out_len;    /*!< Output data length */\n} pre_enc_decrypt_arg_t;\n\n\n/**\n* @brief  This function returns esp_decrypt_handle_t handle.\n*\n* @param[in]   cfg   pointer to esp_decrypt_cfg_t structure\n*\n* @return\n*    - NULL    On failure\n*    - esp_decrypt_handle_t handle\n*/\nesp_decrypt_handle_t esp_encrypted_img_decrypt_start(const esp_decrypt_cfg_t *cfg);\n\n\n/**\n* @brief  This function performs decryption on input data.\n*\n* This function must be called only if esp_encrypted_img_decrypt_start() returns successfully.\n* This function must be called in a loop since input data might not contain whole binary at once.\n* This function must be called till it return ESP_OK.\n*\n* @note args->data_out must be freed after use provided args->data_out_len is greater than 0\n*\n* @param[in]        ctx                 esp_decrypt_handle_t handle\n* @param[in/out]    args                pointer to pre_enc_decrypt_arg_t\n*\n* @return\n*    - ESP_FAIL                         On failure\n*    - ESP_ERR_INVALID_ARG              Invalid arguments\n*    - ESP_ERR_NOT_FINISHED             Decryption is in process\n*    - ESP_OK                           Success\n*/\nesp_err_t esp_encrypted_img_decrypt_data(esp_decrypt_handle_t ctx, pre_enc_decrypt_arg_t *args);\n\n\n/**\n* @brief  Clean-up decryption process.\n*\n* @param[in]   ctx   esp_decrypt_handle_t handle\n*\n* @note This API cleans the decrypt handle and return ESP_FAIL if the complete data has not been decrypted. Verify if complete data\n*       has been decrypted using API `esp_encrypted_img_is_complete_data_received` to prevent an early call to this API.\n*\n* @return\n*    - ESP_FAIL                 On failure\n*    - ESP_ERR_INVALID_ARG      Invalid argument\n*    - ESP_OK                   Success\n*/\nesp_err_t esp_encrypted_img_decrypt_end(esp_decrypt_handle_t ctx);\n\n/**\n* @brief  Checks if the complete data has been decrypted.\n*\n* @note This API checks if complete data has been supplied to `esp_encrypted_img_decrypt_data`. This can be used to prevent an early\n*       call to `esp_encrypted_img_decrypt_end` which cleans up the decrypt handle. If this API returns true, then call `esp_encrypted_img_decrypt_end`.\n*       If this API returns false, and there is some other error (like network error) due to which decryption process should be terminated,\n*       call `esp_encrypted_img_decrypt_abort` to clean up the handle.\n*\n* @param[in]  ctx   esp_decrypt_handle_t handle\n*\n* @return\n*     - true\n*     - false\n*/\nbool esp_encrypted_img_is_complete_data_received(esp_decrypt_handle_t ctx);\n\n/**\n* @brief  Abort the decryption process\n*\n* @param[in]   ctx   esp_decrypt_handle_t handle\n*\n* @return\n*    - ESP_ERR_INVALID_ARG  Invalid argument\n*    - ESP_OK               Success\n*/\nesp_err_t esp_encrypted_img_decrypt_abort(esp_decrypt_handle_t ctx);\n\n/**\n* @brief  Get the size of pre encrypted binary image header (`struct pre_enc_bin_header`). The initial header in\n*         the image contains magic, credentials (symmetric key) and few other parameters. This API could be useful\n*         for scenarios where the entire decrypted image length must be computed by the application including the \n*         image header.  \n*\n* @return\n*    - Header size of pre encrypted image\n*/\nuint16_t esp_encrypted_img_get_header_size(void);\n\n/**\n * @brief  Export the public key corresponding to the private key.\n *         The application should free the memory pointed by `pub_key` after use.\n *         For RSA, the public key is in DER format and corresponds to the private key passed with `esp_encrypted_img_decrypt_start()`.\n *         For ECIES, the public key is in DER format and is derived from the HMAC key ID passed with `esp_encrypted_img_decrypt_start()`.\n *\n * @param ctx   esp_decrypt_handle_t handle\n * @param pub_key   Pointer to store the public key\n * @param pub_key_len   Pointer to store the length of the public key\n * @return esp_err_t   Status of the operation\n */\nesp_err_t esp_encrypted_img_export_public_key(esp_decrypt_handle_t ctx, uint8_t **pub_key, size_t *pub_key_len);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_encrypted_img/private_include/esp_encrypted_img_priv.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stddef.h>\n#include <stdbool.h>\n#include \"esp_err.h\"\n#include \"esp_encrypted_img.h\"\n#include \"mbedtls/version.h\"\n#include \"sdkconfig.h\"\n\n#if defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\n#include \"psa/crypto.h\"\n#else\n#include \"mbedtls/gcm.h\"\n#endif\n\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\n#include \"esp_hmac.h\"\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define GCM_KEY_SIZE        32\n#define CACHE_BUF_SIZE      16\n\ntypedef enum {\n    ESP_PRE_ENC_IMG_READ_MAGIC,\n    ESP_PRE_ENC_IMG_READ_GCM,\n    ESP_PRE_ENC_IMG_READ_IV,\n    ESP_PRE_ENC_IMG_READ_BINSIZE,\n    ESP_PRE_ENC_IMG_READ_AUTH,\n    ESP_PRE_ENC_IMG_READ_EXTRA_HEADER,\n    ESP_PRE_ENC_DATA_DECODE_STATE,\n} esp_encrypted_img_state;\n\n/**\n * @brief Internal handle structure for encrypted image decryption\n */\ntypedef struct esp_encrypted_img_handle {\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n#if !defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    char *rsa_pem;\n    size_t rsa_len;\n#endif\n#elif defined(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\n    hmac_key_id_t hmac_key;\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES */\n    uint32_t binary_file_len;\n    uint32_t binary_file_read;\n    char gcm_key[GCM_KEY_SIZE];\n    char iv[IV_SIZE];\n    char auth_tag[AUTH_SIZE];\n    esp_encrypted_img_state state;\n#if defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\n    psa_aead_operation_t psa_aead_op;\n    psa_key_id_t psa_gcm_key_id;\n    bool psa_initialized;\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n#if defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    void *ds_data;\n#endif /* CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_RSA */\n#else\n    mbedtls_gcm_context gcm_ctx;\n#endif\n    size_t cache_buf_len;\n    char *cache_buf;\n} esp_encrypted_img_t;\n\n\ntypedef struct {\n    char magic[MAGIC_SIZE];\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n    char enc_gcm[ENC_GCM_KEY_SIZE];\n#elif defined(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\n    unsigned char server_ecc_pub_key[SERVER_ECC_KEY_LEN];\n    unsigned char kdf_salt[KDF_SALT_SIZE];\n    unsigned char reserved[RESERVED_SIZE];\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES */\n    char iv[IV_SIZE];\n    char bin_size[BIN_SIZE_DATA];\n    char auth[AUTH_SIZE];\n    char extra_header[RESERVED_HEADER];\n} pre_enc_bin_header;\n#define HEADER_DATA_SIZE    sizeof(pre_enc_bin_header)\n\n// Magic Byte is created using command: echo -n \"esp_encrypted_img\" | sha256sum\nstatic const uint32_t esp_enc_img_magic = 0x0788b6cf;\n\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\n#define HMAC_OUTPUT_SIZE    32\n#define PBKDF2_ITERATIONS   2048\n#define HKDF_INFO_SIZE      16\n#define DER_ASN1_OVERHEAD 30\n#define SECP256R1_COORD_SIZE 32\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES */\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_encrypted_img/private_include/esp_encrypted_img_utilities.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include \"esp_efuse.h\"\n#include \"esp_hmac.h\"\n\n/**\n * @brief Check if the HMAC key is burnt in efuse.\n *\n * @param hmac_key_id[in] The HMAC key ID to check.\n *\n * @return\n *      - true If the HMAC key is burnt.\n *      - false If the HMAC key is not burnt.\n */\nbool esp_encrypted_is_hmac_key_burnt_in_efuse(hmac_key_id_t hmac_key_id);\n\n/**\n * @brief Perform PBKDF2 HMAC-SHA256 key derivation.\n *\n * @param hmac_key_id[in] HMAC key ID.\n * @param salt[in] Pointer to the salt.\n * @param salt_len[in] Length of the salt.\n * @param iteration_count[in] Number of iterations for the key derivation.\n * @param key_length[in] Desired length of the derived key.\n * @param output[out] Buffer to store the derived key.\n *\n * @return\n *     - 0 on success.\n *     - -1 on failure.\n */\nint esp_encrypted_img_pbkdf2_hmac_sha256(hmac_key_id_t hmac_key_id, const unsigned char *salt, size_t salt_len,\n        size_t iteration_count, size_t key_length, unsigned char *output);\n"
  },
  {
    "path": "esp_encrypted_img/project_include.cmake",
    "content": "set(ESP_IMG_GEN_TOOL_PATH ${CMAKE_CURRENT_LIST_DIR}/tools/esp_enc_img_gen.py)\nset(ESP_IMG_GEN_SECURE_CERT_DATA_TOOL_PATH \n    ${CMAKE_SOURCE_DIR}/managed_components/espressif__esp_secure_cert_mgr/tools/configure_esp_secure_cert.py)\n\nidf_build_get_property(build_dir BUILD_DIR)\nif(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)\n    set(app_dependency \"${build_dir}/.signed_bin_timestamp\")\nelse()\n    set(app_dependency \"${build_dir}/.bin_timestamp\")\nendif()\n\nfunction(create_esp_enc_img input_file key_file output_file app)\n    cmake_parse_arguments(arg \"${options}\" \"\" \"${multi}\" \"${ARGN}\")\n    idf_build_get_property(python PYTHON)\n\n    add_custom_command(OUTPUT ${output_file}\n        COMMAND ${python} ${ESP_IMG_GEN_TOOL_PATH} encrypt \n            ${input_file} ${key_file}\n            ${output_file}\n        DEPENDS \"${app_dependency}\"\n        COMMENT \"Generating pre-encrypted binary\"\n        VERBATIM\n    )\n    get_filename_component(name ${output_file} NAME_WE)\n    add_custom_target(enc_bin_target_${name} ALL DEPENDS ${output_file})\n    add_dependencies(enc_bin_target_${name} gen_project_binary)\nendfunction()\n\n# function(create_esp_enc_img_secure_cert_data target_chip input_key input_key_algo)\n#     cmake_parse_arguments(arg \"${options}\" \"\" \"${multi}\" \"${ARGN}\")\n#     idf_build_get_property(python PYTHON)\n#     separate_arguments(input_key_algo_args UNIX_COMMAND \"${input_key_algo}\")\n#     add_custom_command(OUTPUT ${input_key}\n#         COMMAND ${python} ${ESP_IMG_GEN_SECURE_CERT_DATA_TOOL_PATH}\n#             --skip_flash\n#             --target_chip ${target_chip}\n#             --private-key ${input_key}\n#             --priv_key_algo ${input_key_algo_args}\n#             -p /dev/cu.usbserial-1230 # This needs to be removed when the esp_secure_cert_mgr tool is updated to not require a port\n#         COMMENT \"Generating secure data for ${target_chip}\"\n#         VERBATIM\n#     )\n#     get_filename_component(name ${input_key} NAME_WE)\n#     add_custom_target(enc_secure_cert_data_target_${name} ALL\n#         DEPENDS ${input_key}\n#     )\n#     add_dependencies(enc_secure_cert_data_target_${name} gen_project_binary)\n# endfunction()\n"
  },
  {
    "path": "esp_encrypted_img/src/esp_encrypted_img.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include <errno.h>\n#include <esp_log.h>\n#include <esp_err.h>\n#include \"sys/param.h\"\n\n#include \"esp_encrypted_img.h\"\n#include \"esp_encrypted_img_priv.h\"\n\n#include \"mbedtls/version.h\"\n#include \"mbedtls/pk.h\"\n#include \"sdkconfig.h\"\n\n#if !defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\n#include \"mbedtls/entropy.h\"\n#include \"mbedtls/ctr_drbg.h\"\n#endif\n\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\n#if !defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\n#include \"mbedtls/ecp.h\"\n#include \"mbedtls/ecdh.h\"\n#include \"mbedtls/hkdf.h\"\n#include \"mbedtls/pkcs5.h\"\n#endif\n#include \"esp_random.h\"\n#include \"esp_encrypted_img_utilities.h\"\n\n#if SOC_HMAC_SUPPORTED\n#include \"esp_efuse.h\"\n#include \"esp_efuse_chip.h\"\n#endif /* SOC_HMAC_SUPPORTED */\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES */\n\n#if defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n#if defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\n#if __has_include(\"psa_crypto_driver_esp_rsa_ds.h\")\n#include \"psa_crypto_driver_esp_rsa_ds.h\"\n#endif /* __has_include(\"psa_crypto_driver_esp_rsa_ds.h\") */\n#else\n#if __has_include(\"rsa_dec_alt.h\")\n#include \"rsa_dec_alt.h\"\n#else\n#error \"DS Peripheral is not supported on this version of ESP-IDF\"\n#endif /* __has_include(\"rsa_dec_alt.h\") */\n#endif /* CONFIG_MBEDTLS_VER_4_X_SUPPORT */\n#endif /* CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n\n#include \"esp_random.h\"\n\nstatic const char *TAG = \"esp_encrypted_img\";\n\n/*\n * GCM Abstraction Layer Implementations\n */\nstatic esp_err_t gcm_init_and_set_key(esp_encrypted_img_t *handle, const unsigned char *key, size_t key_bits)\n{\n#if defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\n    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;\n    psa_status_t status;\n\n    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT);\n    psa_set_key_algorithm(&attributes, PSA_ALG_GCM);\n    psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);\n    psa_set_key_bits(&attributes, key_bits);\n\n    status = psa_import_key(&attributes, key, key_bits / 8, &handle->psa_gcm_key_id);\n    if (status != PSA_SUCCESS) {\n        ESP_LOGE(TAG, \"psa_import_key for GCM failed: %d\", (int)status);\n        psa_reset_key_attributes(&attributes);\n        return ESP_FAIL;\n    }\n\n    handle->psa_aead_op = psa_aead_operation_init();\n    status = psa_aead_decrypt_setup(&handle->psa_aead_op, handle->psa_gcm_key_id, PSA_ALG_GCM);\n    if (status != PSA_SUCCESS) {\n        ESP_LOGE(TAG, \"psa_aead_decrypt_setup failed: %d\", (int)status);\n        psa_aead_abort(&handle->psa_aead_op);\n        psa_destroy_key(handle->psa_gcm_key_id);\n        return ESP_FAIL;\n    }\n    return ESP_OK;\n#else\n    mbedtls_gcm_init(&handle->gcm_ctx);\n    int ret = mbedtls_gcm_setkey(&handle->gcm_ctx, MBEDTLS_CIPHER_ID_AES, key, key_bits);\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"Error: mbedtls_gcm_set_key: -0x%04x\", (unsigned int) - ret);\n        return ESP_FAIL;\n    }\n    return ESP_OK;\n#endif\n}\n\nstatic esp_err_t gcm_start(esp_encrypted_img_t *handle, const unsigned char *iv, size_t iv_len)\n{\n#if defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\n    psa_status_t status = psa_aead_set_nonce(&handle->psa_aead_op, iv, iv_len);\n    if (status != PSA_SUCCESS) {\n        ESP_LOGE(TAG, \"psa_aead_set_nonce failed: %d\", (int)status);\n        psa_aead_abort(&handle->psa_aead_op);\n        psa_destroy_key(handle->psa_gcm_key_id);\n        return ESP_FAIL;\n    }\n    handle->psa_initialized = true;\n    return ESP_OK;\n#else\n    int ret;\n#if (MBEDTLS_VERSION_NUMBER < 0x03000000)\n    ret = mbedtls_gcm_starts(&handle->gcm_ctx, MBEDTLS_GCM_DECRYPT, iv, iv_len, NULL, 0);\n#else\n    ret = mbedtls_gcm_starts(&handle->gcm_ctx, MBEDTLS_GCM_DECRYPT, iv, iv_len);\n#endif\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"Error: mbedtls_gcm_starts: -0x%04x\", (unsigned int) - ret);\n        return ESP_FAIL;\n    }\n    return ESP_OK;\n#endif\n}\n\nstatic esp_err_t gcm_update(esp_encrypted_img_t *handle, const unsigned char *input, size_t input_len,\n                            unsigned char *output, size_t output_size, size_t *output_len)\n{\n#if defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\n    psa_status_t status = psa_aead_update(&handle->psa_aead_op, input, input_len,\n                                          output, output_size, output_len);\n    if (status != PSA_SUCCESS) {\n        ESP_LOGE(TAG, \"psa_aead_update failed: %d\", (int)status);\n        return ESP_FAIL;\n    }\n    return ESP_OK;\n#else\n    int ret;\n#if (MBEDTLS_VERSION_NUMBER < 0x03000000)\n    ret = mbedtls_gcm_update(&handle->gcm_ctx, input_len, input, output);\n    if (output_len) {\n        *output_len = input_len;\n    }\n#else\n    size_t olen;\n    ret = mbedtls_gcm_update(&handle->gcm_ctx, input, input_len, output, output_size, &olen);\n    if (output_len) {\n        *output_len = olen;\n    }\n#endif\n    if (ret != 0) {\n        return ESP_FAIL;\n    }\n    return ESP_OK;\n#endif\n}\n\nstatic esp_err_t gcm_finish_and_verify(esp_encrypted_img_t *handle, const unsigned char *tag, size_t tag_len)\n{\n#if defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\n    size_t output_len = 0;\n    psa_status_t status = psa_aead_verify(&handle->psa_aead_op, NULL, 0, &output_len, tag, tag_len);\n    if (status != PSA_SUCCESS) {\n        if (status == PSA_ERROR_INVALID_SIGNATURE) {\n            ESP_LOGE(TAG, \"Invalid Auth Tag\");\n        } else {\n            ESP_LOGE(TAG, \"psa_aead_verify failed: %d\", (int)status);\n        }\n        return ESP_FAIL;\n    }\n    return ESP_OK;\n#else\n    unsigned char got_auth[AUTH_SIZE] = {0};\n    int ret;\n#if (MBEDTLS_VERSION_NUMBER < 0x03000000)\n    ret = mbedtls_gcm_finish(&handle->gcm_ctx, got_auth, tag_len);\n#else\n    size_t olen;\n    ret = mbedtls_gcm_finish(&handle->gcm_ctx, NULL, 0, &olen, got_auth, tag_len);\n#endif\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"mbedtls_gcm_finish failed: %d\", ret);\n        return ESP_FAIL;\n    }\n    if (memcmp(got_auth, tag, tag_len) != 0) {\n        ESP_LOGE(TAG, \"Invalid Auth\");\n        return ESP_FAIL;\n    }\n    return ESP_OK;\n#endif\n}\n\nstatic void gcm_cleanup(esp_encrypted_img_t *handle)\n{\n#if defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\n    if (handle->psa_initialized) {\n        psa_aead_abort(&handle->psa_aead_op);\n        psa_destroy_key(handle->psa_gcm_key_id);\n        handle->psa_initialized = false;\n    }\n#else\n    mbedtls_gcm_free(&handle->gcm_ctx);\n#endif\n}\n\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n#define RSA_MPI_ASN1_HEADER_SIZE 11\n\n#if defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n#if !defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\nint esp_encrypted_random(void *ctx, unsigned char *buf, size_t len)\n{\n    (void) ctx;\n    esp_fill_random(buf, len);\n    return 0;\n}\n#endif /* CONFIG_MBEDTLS_VER_4_X_SUPPORT */\n\nstatic int decipher_gcm_key(const char *enc_gcm, esp_encrypted_img_t *handle)\n{\n#if defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\n    if (handle == NULL || handle->ds_data == NULL) {\n        ESP_LOGE(TAG, \"Invalid argument: handle or ds_data is NULL\");\n        return ESP_ERR_INVALID_ARG;\n    }\n    psa_key_id_t rsa_key_id = PSA_KEY_ID_NULL;\n    psa_status_t status;\n    psa_algorithm_t alg = PSA_ALG_RSA_PKCS1V15_CRYPT;\n\n    esp_rsa_ds_opaque_key_t rsa_ds_opaque_key = {0};\n    rsa_ds_opaque_key.ds_data_ctx = (esp_ds_data_ctx_t *)handle->ds_data;\n\n    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;\n    psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);\n    psa_set_key_bits(&attributes, rsa_ds_opaque_key.ds_data_ctx->rsa_length_bits);\n    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT);\n    psa_set_key_algorithm(&attributes, alg);\n    psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_ESP_RSA_DS_VOLATILE);\n    status = psa_import_key(&attributes,\n                            (const uint8_t *)&rsa_ds_opaque_key,\n                            sizeof(rsa_ds_opaque_key),\n                            &rsa_key_id);\n    psa_reset_key_attributes(&attributes);\n    if (status != PSA_SUCCESS) {\n        ESP_LOGE(TAG, \"psa_import_key failed: %d\", (int)status);\n        return ESP_FAIL;\n    }\n    size_t olen = 0;\n    status = psa_asymmetric_decrypt(rsa_key_id, alg, (const unsigned char *)enc_gcm,\n                                    ENC_GCM_KEY_SIZE, NULL, 0,\n                                    (unsigned char *)handle->gcm_key,\n                                    GCM_KEY_SIZE,\n                                    &olen);\n    psa_destroy_key(rsa_key_id);\n    if (status != PSA_SUCCESS) {\n        ESP_LOGE(TAG, \"psa_asymmetric_decrypt failed: %d\", (int)status);\n        return ESP_FAIL;\n    }\n#else\n    int ret;\n    mbedtls_pk_context pk;\n    mbedtls_pk_init(&pk);\n\n    ret = mbedtls_pk_setup_rsa_alt(&pk, NULL, esp_ds_rsa_decrypt, NULL, esp_ds_get_keylen);\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"failed\\n  ! mbedtls_pk_setup_rsa_alt returned -0x%04x\\n\", (unsigned int) - ret);\n        mbedtls_pk_free(&pk);\n        return ret;\n    }\n\n    size_t olen = 0;\n    ret = mbedtls_pk_decrypt(&pk, (const unsigned char *)enc_gcm, ENC_GCM_KEY_SIZE,\n                             (unsigned char *)handle->gcm_key, &olen, GCM_KEY_SIZE,\n                             esp_encrypted_random, NULL);\n    mbedtls_pk_free(&pk);\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"failed\\n  ! mbedtls_pk_decrypt returned -0x%04x\\n\", (unsigned int) - ret);\n        return ret;\n    }\n#endif /* CONFIG_MBEDTLS_VER_4_X_SUPPORT */\n\n    void *tmp_buf = realloc(handle->cache_buf, CACHE_BUF_SIZE);\n    if (!tmp_buf) {\n        ESP_LOGE(TAG, \"Failed to reallocate memory for cache buffer\");\n        return ESP_ERR_NO_MEM;\n    }\n    handle->cache_buf = tmp_buf;\n    handle->state = ESP_PRE_ENC_IMG_READ_IV;\n    handle->binary_file_read = 0;\n    handle->cache_buf_len = 0;\n    return ESP_OK;\n}\n\n#else\n\nstatic int decipher_gcm_key(const char *enc_gcm, esp_encrypted_img_t *handle)\n{\n    int ret = 1;\n    size_t olen = 0;\n\n#if defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\n    psa_key_id_t rsa_key_id = PSA_KEY_ID_NULL;\n    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;\n    psa_status_t status;\n    mbedtls_pk_context *pk = calloc(1, sizeof(mbedtls_pk_context));\n    if (pk == NULL) {\n        ESP_LOGE(TAG, \"Failed to allocate memory for mbedtls_pk_context\");\n        return ESP_ERR_NO_MEM;\n    }\n    unsigned char *key_buf = NULL;\n    size_t key_buf_size = MBEDTLS_MPI_MAX_SIZE * 2;\n\n    ESP_LOGI(TAG, \"Reading RSA private key (PSA)\");\n\n    mbedtls_pk_init(pk);\n\n    /* Parse RSA key from PEM using mbedtls */\n    ret = mbedtls_pk_parse_key(pk, (const unsigned char *)handle->rsa_pem, handle->rsa_len, NULL, 0);\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"failed\\n  ! mbedtls_pk_parse_key returned -0x%04x\\n\", (unsigned int) - ret);\n        goto exit;\n    }\n\n    /* Export to DER format for PSA import */\n    key_buf = calloc(1, key_buf_size);\n    if (key_buf == NULL) {\n        ESP_LOGE(TAG, \"Failed to allocate memory for key buffer\");\n        ret = ESP_ERR_NO_MEM;\n        goto exit;\n    }\n\n    ret = mbedtls_pk_write_key_der(pk, key_buf, key_buf_size);\n    if (ret < 0) {\n        ESP_LOGE(TAG, \"failed\\n  ! mbedtls_pk_write_key_der returned -0x%04x\\n\", (unsigned int) - ret);\n        goto exit;\n    }\n\n    /* DER is written at the end of the buffer */\n    size_t key_len = ret;\n    unsigned char *key_start = key_buf + key_buf_size - key_len;\n\n    /* Import RSA key to PSA */\n    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT);\n    psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PKCS1V15_CRYPT);\n    psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);\n\n    status = psa_import_key(&attributes, key_start, key_len, &rsa_key_id);\n    mbedtls_pk_free(pk);\n    free(pk);\n    pk = NULL;\n\n    if (status != PSA_SUCCESS) {\n        ESP_LOGE(TAG, \"psa_import_key failed: %d\", (int)status);\n        ret = ESP_FAIL;\n        goto exit;\n    }\n\n    /* Perform RSA PKCS#1 v1.5 decryption */\n    status = psa_asymmetric_decrypt(rsa_key_id,\n                                    PSA_ALG_RSA_PKCS1V15_CRYPT,\n                                    (const unsigned char *)enc_gcm,\n                                    ENC_GCM_KEY_SIZE,\n                                    NULL, 0,  /* No salt */\n                                    (unsigned char *)handle->gcm_key,\n                                    GCM_KEY_SIZE,\n                                    &olen);\n\n    if (status != PSA_SUCCESS) {\n        ESP_LOGE(TAG, \"psa_asymmetric_decrypt failed: %d\", (int)status);\n        ret = ESP_FAIL;\n        goto exit;\n    }\n\n    ret = 0;\n\n    void *tmp_buf = realloc(handle->cache_buf, CACHE_BUF_SIZE);\n    if (!tmp_buf) {\n        ESP_LOGE(TAG, \"Failed to reallocate memory for cache buffer\");\n        ret = ESP_ERR_NO_MEM;\n        goto exit;\n    }\n    handle->cache_buf = tmp_buf;\n    handle->state = ESP_PRE_ENC_IMG_READ_IV;\n    handle->binary_file_read = 0;\n    handle->cache_buf_len = 0;\n\nexit:\n    if (pk) {\n        mbedtls_pk_free(pk);\n        free(pk);\n    }\n    if (rsa_key_id != PSA_KEY_ID_NULL) {\n        psa_destroy_key(rsa_key_id);\n    }\n    if (key_buf) {\n        mbedtls_platform_zeroize(key_buf, key_buf_size);\n        free(key_buf);\n    }\n    if (handle->rsa_pem) {\n        mbedtls_platform_zeroize(handle->rsa_pem, handle->rsa_len);\n        free(handle->rsa_pem);\n        handle->rsa_pem = NULL;\n    }\n    return ret;\n\n#else /* !CONFIG_MBEDTLS_VER_4_X_SUPPORT */\n    mbedtls_pk_context pk;\n    mbedtls_entropy_context entropy;\n    mbedtls_ctr_drbg_context ctr_drbg;\n    const char *pers = \"mbedtls_pk_encrypt\";\n\n    mbedtls_ctr_drbg_init( &ctr_drbg );\n    mbedtls_entropy_init( &entropy );\n    mbedtls_pk_init( &pk );\n\n    if ((ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func,\n                                      &entropy, (const unsigned char *) pers,\n                                      strlen(pers))) != 0) {\n        ESP_LOGE(TAG, \"failed\\n  ! mbedtls_ctr_drbg_seed returned -0x%04x\\n\", (unsigned int) - ret);\n        goto exit;\n    }\n\n    ESP_LOGI(TAG, \"Reading RSA private key\");\n\n#if (MBEDTLS_VERSION_NUMBER < 0x03000000)\n    if ( (ret = mbedtls_pk_parse_key(&pk, (const unsigned char *) handle->rsa_pem, handle->rsa_len, NULL, 0)) != 0) {\n#else\n    if ( (ret = mbedtls_pk_parse_key(&pk, (const unsigned char *) handle->rsa_pem, handle->rsa_len, NULL, 0, mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) {\n#endif\n        ESP_LOGE(TAG, \"failed\\n  ! mbedtls_pk_parse_keyfile returned -0x%04x\\n\", (unsigned int) - ret );\n        goto exit;\n    }\n\n    if (( ret = mbedtls_pk_decrypt( &pk, (const unsigned char *)enc_gcm, ENC_GCM_KEY_SIZE, (unsigned char *)handle->gcm_key, &olen, GCM_KEY_SIZE,\n                                    mbedtls_ctr_drbg_random, &ctr_drbg ) ) != 0 ) {\n        ESP_LOGE(TAG, \"failed\\n  ! mbedtls_pk_decrypt returned -0x%04x\\n\", (unsigned int) - ret );\n        goto exit;\n    }\n    void *tmp_buf = realloc(handle->cache_buf, CACHE_BUF_SIZE);\n    if (!tmp_buf) {\n        ESP_LOGE(TAG, \"Failed to reallocate memory for cache buffer\");\n        ret = ESP_ERR_NO_MEM;\n        goto exit;\n    }\n    handle->cache_buf = tmp_buf;\n    handle->state = ESP_PRE_ENC_IMG_READ_IV;\n    handle->binary_file_read = 0;\n    handle->cache_buf_len = 0;\nexit:\n    if (handle->rsa_pem) {\n        mbedtls_platform_zeroize(handle->rsa_pem, handle->rsa_len);\n        free(handle->rsa_pem);\n        handle->rsa_pem = NULL;\n    }\n    mbedtls_pk_free( &pk );\n    mbedtls_entropy_free( &entropy );\n    mbedtls_ctr_drbg_free( &ctr_drbg );\n    return (ret);\n#endif /* CONFIG_MBEDTLS_VER_4_X_SUPPORT */\n}\n\nstatic esp_err_t esp_encrypted_img_export_rsa_pub_key(const char *rsa_pem, size_t rsa_len, uint8_t **pub_key, size_t *pub_key_len)\n{\n    int ret = 0;\n    if (rsa_pem == NULL) {\n        ESP_LOGE(TAG, \"RSA private key is not set\");\n        return ESP_ERR_INVALID_ARG;\n    }\n    mbedtls_pk_context pk;\n    mbedtls_pk_init(&pk);\n\n#if defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\n    /* For mbedtls 4.x, use PSA-based key parsing */\n    ret = mbedtls_pk_parse_key(&pk, (const unsigned char *)rsa_pem, rsa_len, NULL, 0);\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"failed\\n  ! mbedtls_pk_parse_key returned -0x%04x\\n\", (unsigned int) - ret);\n        goto exit;\n    }\n\n    /* Export public key in DER SubjectPublicKeyInfo format first */\n    size_t max_pub_key_size = MBEDTLS_MPI_MAX_SIZE * 2;\n    unsigned char *der_buf = calloc(1, max_pub_key_size);\n    if (der_buf == NULL) {\n        ESP_LOGE(TAG, \"Failed to allocate memory for DER buffer\");\n        goto exit;\n    }\n\n    ret = mbedtls_pk_write_pubkey_der(&pk, der_buf, max_pub_key_size);\n    if (ret < 0) {\n        ESP_LOGE(TAG, \"Failed to write public key DER: -0x%04x\", (unsigned int) - ret);\n        free(der_buf);\n        goto exit;\n    }\n\n    /* DER is written at the end of the buffer */\n    size_t der_len = ret;\n    unsigned char *der_start = der_buf + max_pub_key_size - der_len;\n\n    /* Parse SubjectPublicKeyInfo to extract raw public key (BIT STRING content)\n     * Structure: SEQUENCE { SEQUENCE { OID, params }, BIT STRING { raw_key } }\n     * We need to skip the outer SEQUENCE and algorithm SEQUENCE to get the BIT STRING */\n    unsigned char *p = der_start;\n    size_t len;\n\n    /* Skip outer SEQUENCE tag and length */\n    if (*p++ != 0x30) { /* SEQUENCE */\n        ESP_LOGE(TAG, \"Invalid DER: expected SEQUENCE\");\n        free(der_buf);\n        goto exit;\n    }\n    /* Skip length (may be 1 or more bytes) */\n    if (*p & 0x80) {\n        size_t len_bytes = *p++ & 0x7f;\n        p += len_bytes;\n    } else {\n        p++;\n    }\n\n    /* Skip algorithm SEQUENCE */\n    if (*p++ != 0x30) { /* SEQUENCE */\n        ESP_LOGE(TAG, \"Invalid DER: expected algorithm SEQUENCE\");\n        free(der_buf);\n        goto exit;\n    }\n    /* Get algorithm sequence length and skip it */\n    if (*p & 0x80) {\n        size_t len_bytes = *p++ & 0x7f;\n        len = 0;\n        for (size_t i = 0; i < len_bytes; i++) {\n            len = (len << 8) | *p++;\n        }\n    } else {\n        len = *p++;\n    }\n    p += len; /* Skip algorithm sequence content */\n\n    /* Now at BIT STRING */\n    if (*p++ != 0x03) { /* BIT STRING */\n        ESP_LOGE(TAG, \"Invalid DER: expected BIT STRING\");\n        free(der_buf);\n        goto exit;\n    }\n    /* Get BIT STRING length */\n    if (*p & 0x80) {\n        size_t len_bytes = *p++ & 0x7f;\n        len = 0;\n        for (size_t i = 0; i < len_bytes; i++) {\n            len = (len << 8) | *p++;\n        }\n    } else {\n        len = *p++;\n    }\n    /* Skip unused bits byte (should be 0x00) */\n    p++;\n    len--;\n\n    /* p now points to raw public key, len is its length */\n    *pub_key = calloc(1, len);\n    if (*pub_key == NULL) {\n        ESP_LOGE(TAG, \"Failed to allocate memory for public key\");\n        free(der_buf);\n        goto exit;\n    }\n    memcpy(*pub_key, p, len);\n    *pub_key_len = len;\n\n    free(der_buf);\n    mbedtls_pk_free(&pk);\n    return ESP_OK;\n\nexit:\n    if (*pub_key) {\n        free(*pub_key);\n        *pub_key = NULL;\n        *pub_key_len = 0;\n    }\n    mbedtls_pk_free(&pk);\n    return ESP_FAIL;\n\n#else /* !CONFIG_MBEDTLS_VER_4_X_SUPPORT */\n    mbedtls_entropy_context entropy;\n    mbedtls_ctr_drbg_context ctr_drbg;\n\n    mbedtls_ctr_drbg_init( &ctr_drbg );\n    mbedtls_entropy_init( &entropy );\n\n#if (MBEDTLS_VERSION_NUMBER < 0x03000000)\n    if ( (ret = mbedtls_pk_parse_key(&pk, (const unsigned char *) rsa_pem, rsa_len, NULL, 0)) != 0) {\n#else\n    if ( (ret = mbedtls_pk_parse_key(&pk, (const unsigned char *) rsa_pem, rsa_len, NULL, 0, mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) {\n#endif\n        ESP_LOGE(TAG, \"failed\\n  ! mbedtls_pk_parse_key returned -0x%04x\\n\", (unsigned int) - ret );\n        goto exit;\n    }\n\n    if (mbedtls_pk_get_type(&pk) != MBEDTLS_PK_RSA) {\n        ESP_LOGE(TAG, \"Public key is not RSA\");\n        goto exit;\n    }\n\n    const mbedtls_rsa_context *rsa_ctx = mbedtls_pk_rsa(pk);\n    if (rsa_ctx == NULL) {\n        ESP_LOGE(TAG, \"Failed to get RSA context from public key\");\n        goto exit;\n    }\n\n    size_t max_pub_key_size = MBEDTLS_MPI_MAX_SIZE + RSA_MPI_ASN1_HEADER_SIZE;\n    *pub_key = calloc(1, max_pub_key_size + 1);\n    if (*pub_key == NULL) {\n        ESP_LOGE(TAG, \"Failed to allocate memory for public key\");\n        goto exit;\n    }\n\n    unsigned char *c = *pub_key + max_pub_key_size;\n\n    ret = mbedtls_pk_write_pubkey(&c, *pub_key, &pk);\n    if (ret < 0) {\n        ESP_LOGE(TAG, \"Failed to write public key: -0x%04x\", (unsigned int) - ret);\n        goto exit;\n    }\n    if (c - *pub_key < 0) {\n        ESP_LOGE(TAG, \"Public key buffer is too small\");\n        goto exit;\n    }\n    // Adjust the length of the public key\n    *pub_key_len = ret;\n    // Move the memory to the start of the buffer\n    // This is necessary because mbedtls_pk_write_pubkey writes the key in reverse order\n    // and we need to adjust the pointer to point to the start of the key.\n    memmove(*pub_key, c, *pub_key_len);\n    // Resize the public key buffer to the actual length\n    unsigned char *temp_pub_key = realloc(*pub_key, *pub_key_len);\n    if (temp_pub_key == NULL) {\n        ESP_LOGE(TAG, \"Failed to resize public key buffer\");\n        goto exit;\n    }\n    *pub_key = temp_pub_key;\n\n    // Free the resources\n    mbedtls_pk_free(&pk);\n    mbedtls_entropy_free(&entropy);\n    mbedtls_ctr_drbg_free(&ctr_drbg);\n    return ESP_OK;\nexit:\n    if (*pub_key) {\n        free(*pub_key);\n        *pub_key = NULL;\n        *pub_key_len = 0;\n    }\n    mbedtls_entropy_free(&entropy);\n    mbedtls_ctr_drbg_free(&ctr_drbg);\n    mbedtls_pk_free(&pk);\n    return ESP_FAIL;\n#endif /* CONFIG_MBEDTLS_VER_4_X_SUPPORT */\n}\n#endif /* CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_RSA */\n\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\n\nstatic uint8_t pbkdf2_salt[32] = {\n    0x0e, 0x21, 0x60, 0x64, 0x2d, 0xae, 0x76, 0xd3, 0x34, 0x48, 0xe4, 0x3d, 0x77, 0x20, 0x12, 0x3d,\n    0x9f, 0x3b, 0x1e, 0xce, 0xb8, 0x8e, 0x57, 0x3a, 0x4e, 0x8f, 0x7f, 0xb9, 0x4f, 0xf0, 0xc8, 0x69\n};\n\n#if !defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\nstatic int mbedtls_esp_random(void *ctx, unsigned char *buf, size_t len)\n{\n    esp_fill_random(buf, len);\n    return 0;\n}\n#else\nstatic int psa_hkdf_derive(const uint8_t *ikm, size_t ikm_len,\n                           const uint8_t *salt, size_t salt_len,\n                           const uint8_t *info, size_t info_len,\n                           uint8_t *okm, size_t okm_len)\n{\n    psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT;\n    psa_status_t status;\n\n    status = psa_key_derivation_setup(&operation, PSA_ALG_HKDF(PSA_ALG_SHA_256));\n    if (status != PSA_SUCCESS) {\n        ESP_LOGE(TAG, \"psa_key_derivation_setup failed: %d\", (int)status);\n        return ESP_FAIL;\n    }\n\n    /* Input salt */\n    status = psa_key_derivation_input_bytes(&operation,\n                                            PSA_KEY_DERIVATION_INPUT_SALT,\n                                            salt, salt_len);\n    if (status != PSA_SUCCESS) {\n        ESP_LOGE(TAG, \"psa_key_derivation_input_bytes (salt) failed: %d\", (int)status);\n        goto abort;\n    }\n\n    /* Input IKM (shared secret) */\n    status = psa_key_derivation_input_bytes(&operation,\n                                            PSA_KEY_DERIVATION_INPUT_SECRET,\n                                            ikm, ikm_len);\n    if (status != PSA_SUCCESS) {\n        ESP_LOGE(TAG, \"psa_key_derivation_input_bytes (secret) failed: %d\", (int)status);\n        goto abort;\n    }\n\n    /* Input info */\n    status = psa_key_derivation_input_bytes(&operation,\n                                            PSA_KEY_DERIVATION_INPUT_INFO,\n                                            info, info_len);\n    if (status != PSA_SUCCESS) {\n        ESP_LOGE(TAG, \"psa_key_derivation_input_bytes (info) failed: %d\", (int)status);\n        goto abort;\n    }\n\n    /* Output derived key */\n    status = psa_key_derivation_output_bytes(&operation, okm, okm_len);\n    if (status != PSA_SUCCESS) {\n        ESP_LOGE(TAG, \"psa_key_derivation_output_bytes failed: %d\", (int)status);\n        goto abort;\n    }\n\n    psa_key_derivation_abort(&operation);\n    return ESP_OK;\n\nabort:\n    psa_key_derivation_abort(&operation);\n    return ESP_FAIL;\n}\n#endif /* CONFIG_MBEDTLS_VER_4_X_SUPPORT */\n\nstatic esp_err_t compute_ecc_key_with_hmac(hmac_key_id_t hmac_key, mbedtls_mpi *ecc_priv_key)\n{\n    esp_err_t err = ESP_OK;\n    if (ecc_priv_key == NULL) {\n        ESP_LOGE(TAG, \"ECC key buffer is NULL\");\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    int ret = 0;\n    uint8_t hmac_output[HMAC_OUTPUT_SIZE] = {0};\n    mbedtls_ecp_group grp;\n\n    mbedtls_ecp_group_init(&grp);\n    mbedtls_mpi_init(ecc_priv_key);\n\n    ret = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1);\n    if (ret != 0) {\n        goto cleanup;\n    }\n\n    err = esp_encrypted_img_pbkdf2_hmac_sha256(hmac_key, pbkdf2_salt, sizeof(pbkdf2_salt),\n            PBKDF2_ITERATIONS, HMAC_OUTPUT_SIZE, hmac_output);\n    if (err != 0) {\n        ESP_LOGE(TAG, \"Failed to calculate ECC key: [0x%02X] (%s)\", err, esp_err_to_name(err));\n        goto cleanup;\n    }\n\n    // Step 2: Convert output to scalar mod curve order\n    ret = mbedtls_mpi_read_binary(ecc_priv_key, hmac_output, HMAC_OUTPUT_SIZE);\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"failed\\n  ! mbedtls_mpi_read_binary returned -0x%04x\\n\", (unsigned int) - ret);\n        goto cleanup;\n    }\n\n    ret = mbedtls_ecp_check_privkey(&grp, ecc_priv_key);\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"failed\\n  ! mbedtls_ecp_check_privkey returned -0x%04x\\n\", (unsigned int) - ret);\n        goto cleanup;\n    }\n\n    ESP_LOGI(TAG, \"ECC key derived successfully\");\n\ncleanup:\n    mbedtls_ecp_group_free(&grp);\n    return ret;\n}\n\nstatic int derive_ota_ecc_device_key(hmac_key_id_t hmac_key, mbedtls_mpi *ecc_priv_key)\n{\n    // Although we have checked this during the esp_encrypted_img_decrypt_start() call,\n    // we will check again here to ensure that the HMAC key is valid.\n    if (!esp_encrypted_is_hmac_key_burnt_in_efuse(hmac_key)) {\n        ESP_LOGE(TAG, \"Could not find HMAC key in configured eFuse block!\");\n        return ESP_ERR_ENCRYPTED_IMAGE_HMAC_KEY_NOT_FOUND;\n    }\n\n    esp_err_t err = compute_ecc_key_with_hmac(hmac_key, ecc_priv_key);\n    return err;\n}\n\nstatic mbedtls_ecp_point *get_server_public_point(const char *data, size_t len)\n{\n    int ret;\n    uint8_t *server_public_key = NULL;\n    mbedtls_ecp_point *server_public_point = NULL;\n    mbedtls_ecp_group grp;\n    mbedtls_ecp_group_init(&grp);\n\n    if ((ret = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1)) != 0) {\n        ESP_LOGE(TAG, \"failed\\n  ! mbedtls_ecp_group_load returned -0x%04x\\n\", (unsigned int) - ret);\n        return NULL;\n    }\n\n    server_public_point = calloc(1, sizeof(mbedtls_ecp_point));\n    if (server_public_point == NULL) {\n        ESP_LOGE(TAG, \"failed to allocate memory for server public point\");\n        goto cleanup;\n    }\n    mbedtls_ecp_point_init(server_public_point);\n\n    server_public_key = calloc(1, len + 1);\n    if (server_public_key == NULL) {\n        ESP_LOGE(TAG, \"failed to allocate memory for server public key\");\n        mbedtls_ecp_point_free(server_public_point);\n        server_public_point = NULL;\n        goto cleanup;\n    }\n    server_public_key[0] = 0x04; // Uncompressed point\n    memcpy(server_public_key + 1, data, len);\n\n    ret = mbedtls_ecp_point_read_binary(&grp, server_public_point, (const unsigned char *)server_public_key, len + 1);\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"failed\\n  ! mbedtls_ecp_point_read_binary returned -0x%04x\\n\", (unsigned int) - ret);\n        mbedtls_ecp_point_free(server_public_point);\n        free(server_public_key);\n        server_public_key = NULL;\n        return NULL;\n    }\n\n    ret = mbedtls_ecp_check_pubkey(&grp, server_public_point);\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"failed\\n  ! mbedtls_ecp_check_pubkey returned -0x%04x\\n\", (unsigned int) - ret);\n        mbedtls_ecp_point_free(server_public_point);\n        free(server_public_key);\n        server_public_key = NULL;\n        return NULL;\n    }\n\ncleanup:\n    mbedtls_ecp_group_free(&grp);\n    if (server_public_key) {\n        memset(server_public_key, 0, len + 1);\n        free(server_public_key);\n        server_public_key = NULL;\n    }\n    return server_public_point;\n}\n\nstatic unsigned char *get_kdf_salt_from_header(const char *data, size_t len)\n{\n    unsigned char *kdf_salt = NULL;\n    if (len >= KDF_SALT_SIZE) {\n        kdf_salt = calloc(1, KDF_SALT_SIZE);\n        if (kdf_salt == NULL) {\n            ESP_LOGE(TAG, \"failed to allocate memory for kdf_salt\");\n            return NULL;\n        }\n        memcpy(kdf_salt, data, KDF_SALT_SIZE);\n    }\n    return kdf_salt;\n}\n\n\nstatic int derive_gcm_key(const char *data, esp_encrypted_img_t *handle)\n{\n    int ret = 0;\n    uint8_t *derived_key = calloc(1, GCM_KEY_SIZE);\n    if (derived_key == NULL) {\n        ESP_LOGE(TAG, \"Failed to allocate memory for derived key\");\n        return ESP_ERR_NO_MEM;\n    }\n    mbedtls_ecp_point *server_public_point = NULL;\n    unsigned char *kdf_salt = NULL;\n    uint8_t shared_secret_bytes[32] = {0};\n\n    mbedtls_ecp_group grp;\n    mbedtls_ecp_group_init(&grp);\n    if ((ret = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1)) != 0) {\n        ESP_LOGE(TAG, \"failed\\n  ! mbedtls_ecp_group_load returned -0x%04x\\n\", (unsigned int) - ret);\n        goto exit;\n    }\n\n    server_public_point = get_server_public_point(data, SERVER_ECC_KEY_LEN);\n    if (server_public_point == NULL) {\n        ESP_LOGE(TAG, \"Failed to get server public point\");\n        ret = ESP_FAIL;\n        goto exit;\n    }\n    kdf_salt = get_kdf_salt_from_header(data + SERVER_ECC_KEY_LEN, KDF_SALT_SIZE);\n    mbedtls_mpi device_private_mpi;\n\n    esp_err_t err = derive_ota_ecc_device_key(handle->hmac_key, &device_private_mpi);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to derive ECC device key\");\n        goto exit;\n    }\n\n#if defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\n    {\n        psa_key_id_t device_key_id = PSA_KEY_ID_NULL;\n        psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;\n        psa_status_t status;\n        uint8_t priv_key_buf[32];\n        uint8_t server_pub_key_buf[65];  /* 0x04 || X || Y */\n        size_t shared_secret_len = 0;\n\n        /* Convert device private key MPI to raw bytes */\n        ret = mbedtls_mpi_write_binary(&device_private_mpi, priv_key_buf, sizeof(priv_key_buf));\n        mbedtls_mpi_free(&device_private_mpi);\n        if (ret != 0) {\n            ESP_LOGE(TAG, \"failed\\n  ! mbedtls_mpi_write_binary returned -0x%04x\\n\", (unsigned int) - ret);\n            goto exit;\n        }\n\n        /* Import private key to PSA */\n        psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);\n        psa_set_key_algorithm(&attributes, PSA_ALG_ECDH);\n        psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));\n        psa_set_key_bits(&attributes, 256);\n\n        status = psa_import_key(&attributes, priv_key_buf, sizeof(priv_key_buf), &device_key_id);\n        mbedtls_platform_zeroize(priv_key_buf, sizeof(priv_key_buf));\n\n        if (status != PSA_SUCCESS) {\n            ESP_LOGE(TAG, \"psa_import_key failed: %d\", (int)status);\n            ret = ESP_FAIL;\n            goto exit;\n        }\n\n        /* Prepare server public key in uncompressed format */\n        server_pub_key_buf[0] = 0x04;  /* Uncompressed point */\n        mbedtls_mpi_write_binary(&server_public_point->MBEDTLS_PRIVATE(X),\n                                 server_pub_key_buf + 1, 32);\n        mbedtls_mpi_write_binary(&server_public_point->MBEDTLS_PRIVATE(Y),\n                                 server_pub_key_buf + 33, 32);\n\n        /* Perform ECDH using PSA */\n        status = psa_raw_key_agreement(PSA_ALG_ECDH,\n                                       device_key_id,\n                                       server_pub_key_buf, sizeof(server_pub_key_buf),\n                                       shared_secret_bytes, sizeof(shared_secret_bytes),\n                                       &shared_secret_len);\n\n        psa_destroy_key(device_key_id);\n\n        if (status != PSA_SUCCESS) {\n            ESP_LOGE(TAG, \"psa_raw_key_agreement failed: %d\", (int)status);\n            ret = ESP_FAIL;\n            goto exit;\n        }\n\n        /* Perform HKDF using PSA */\n        ret = psa_hkdf_derive(shared_secret_bytes, sizeof(shared_secret_bytes),\n                              kdf_salt, KDF_SALT_SIZE,\n                              (const uint8_t *)\"_esp_enc_img_ecc\", HKDF_INFO_SIZE,\n                              derived_key, GCM_KEY_SIZE);\n        if (ret != ESP_OK) {\n            ESP_LOGE(TAG, \"psa_hkdf_derive failed\");\n            goto exit;\n        }\n    }\n#else /* !CONFIG_MBEDTLS_VER_4_X_SUPPORT */\n    {\n        mbedtls_mpi shared_secret;\n        mbedtls_mpi_init(&shared_secret);\n\n        ret = mbedtls_ecdh_compute_shared(&grp, &shared_secret, server_public_point, &device_private_mpi,\n                                          mbedtls_esp_random, NULL);\n        mbedtls_mpi_free(&device_private_mpi);\n        if (ret != 0) {\n            ESP_LOGE(TAG, \"failed\\n  ! mbedtls_ecdh_compute_shared returned -0x%04x\\n\", (unsigned int) - ret);\n            goto exit;\n        }\n\n        ret = mbedtls_mpi_write_binary(&shared_secret, shared_secret_bytes, sizeof(shared_secret_bytes));\n        mbedtls_mpi_free(&shared_secret);\n        if (ret != 0) {\n            ESP_LOGE(TAG, \"failed\\n  ! mbedtls_mpi_write_binary returned -0x%04x\\n\", (unsigned int) - ret);\n            goto exit;\n        }\n\n        unsigned char *hkdf_info = calloc(1, HKDF_INFO_SIZE);\n        if (hkdf_info == NULL) {\n            ESP_LOGE(TAG, \"failed to allocate memory for hkdf_info\");\n            ret = ESP_ERR_NO_MEM;\n            goto exit;\n        }\n        memcpy(hkdf_info, \"_esp_enc_img_ecc\", HKDF_INFO_SIZE);\n\n        ret = mbedtls_hkdf(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), kdf_salt, KDF_SALT_SIZE,\n                           (const unsigned char *)shared_secret_bytes, sizeof(shared_secret_bytes),\n                           hkdf_info, HKDF_INFO_SIZE, derived_key, GCM_KEY_SIZE);\n        mbedtls_platform_zeroize(hkdf_info, HKDF_INFO_SIZE);\n        free(hkdf_info);\n        if (ret != 0) {\n            ESP_LOGE(TAG, \"failed\\n  ! mbedtls_hkdf returned -0x%04x\\n\", (unsigned int) - ret);\n            goto exit;\n        }\n    }\n#endif /* CONFIG_MBEDTLS_VER_4_X_SUPPORT */\n\n    memcpy(handle->gcm_key, derived_key, GCM_KEY_SIZE);\n    ESP_LOGI(TAG, \"GCM key derived successfully\");\n\n    void *tmp_buf = realloc(handle->cache_buf, CACHE_BUF_SIZE);\n    if (!tmp_buf) {\n        ESP_LOGE(TAG, \"Failed to reallocate memory for cache buffer\");\n        ret = ESP_ERR_NO_MEM;\n        goto exit;\n    }\n    handle->cache_buf = tmp_buf;\n\n    handle->state = ESP_PRE_ENC_IMG_READ_IV;\n    handle->binary_file_read = 0;\n    handle->cache_buf_len = 0;\nexit:\n    mbedtls_ecp_group_free(&grp);\n    if (server_public_point) {\n        mbedtls_ecp_point_free(server_public_point);\n        free(server_public_point);\n    }\n    mbedtls_platform_zeroize(shared_secret_bytes, sizeof(shared_secret_bytes));\n    mbedtls_platform_zeroize(derived_key, GCM_KEY_SIZE);\n    free(derived_key);\n    if (kdf_salt) {\n        mbedtls_platform_zeroize(kdf_salt, KDF_SALT_SIZE);\n        free(kdf_salt);\n    }\n\n    return ret;\n}\n\n#if defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\nstatic esp_err_t esp_encrypted_img_export_ecies_pub_key(hmac_key_id_t hmac_key, uint8_t **pub_key, size_t *pub_key_len)\n{\n    esp_err_t err = ESP_FAIL;\n    psa_status_t status;\n    psa_key_id_t key_id = 0;\n    mbedtls_mpi ecc_priv_key;\n    uint8_t priv_key_bytes[32];\n    uint8_t raw_pub_key[65];  // 1 byte prefix + 32 bytes x + 32 bytes y\n    size_t raw_pub_key_len;\n\n    mbedtls_mpi_init(&ecc_priv_key);\n\n    int ret = derive_ota_ecc_device_key(hmac_key, &ecc_priv_key);\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"Failed to derive ECC device key: -0x%04x\", (unsigned int) - ret);\n        goto exit;\n    }\n\n    // Convert MPI to bytes\n    ret = mbedtls_mpi_write_binary(&ecc_priv_key, priv_key_bytes, sizeof(priv_key_bytes));\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"Failed to convert private key to bytes: -0x%04x\", (unsigned int) - ret);\n        goto exit;\n    }\n\n    // Import private key to PSA\n    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;\n    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_EXPORT);\n    psa_set_key_algorithm(&attributes, PSA_ALG_ECDH);\n    psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));\n    psa_set_key_bits(&attributes, 256);\n\n    status = psa_import_key(&attributes, priv_key_bytes, sizeof(priv_key_bytes), &key_id);\n    if (status != PSA_SUCCESS) {\n        ESP_LOGE(TAG, \"Failed to import ECC key to PSA: %d\", (int)status);\n        goto exit;\n    }\n\n    // Export public key (raw format: 0x04 || X || Y for uncompressed point)\n    status = psa_export_public_key(key_id, raw_pub_key, sizeof(raw_pub_key), &raw_pub_key_len);\n    if (status != PSA_SUCCESS) {\n        ESP_LOGE(TAG, \"Failed to export public key: %d\", (int)status);\n        goto exit;\n    }\n\n    // Convert raw public key to DER SubjectPublicKeyInfo format\n    // Fixed ASN.1 header for secp256r1 EC public key\n    static const uint8_t der_header[] = {\n        0x30, 0x59,  // SEQUENCE, length 89\n        0x30, 0x13,  // SEQUENCE, length 19\n        0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,  // OID ecPublicKey (1.2.840.10045.2.1)\n        0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,  // OID secp256r1 (1.2.840.10045.3.1.7)\n        0x03, 0x42, 0x00  // BIT STRING, length 66, no unused bits\n    };\n\n    size_t der_len = sizeof(der_header) + raw_pub_key_len;\n    *pub_key = calloc(1, der_len);\n    if (*pub_key == NULL) {\n        ESP_LOGE(TAG, \"Failed to allocate memory for public key\");\n        err = ESP_ERR_NO_MEM;\n        goto exit;\n    }\n\n    memcpy(*pub_key, der_header, sizeof(der_header));\n    memcpy(*pub_key + sizeof(der_header), raw_pub_key, raw_pub_key_len);\n    *pub_key_len = der_len;\n\n    ESP_LOGI(TAG, \"ECC public key derived successfully\");\n    err = ESP_OK;\n\nexit:\n    if (key_id != 0) {\n        psa_destroy_key(key_id);\n    }\n    mbedtls_mpi_free(&ecc_priv_key);\n    mbedtls_platform_zeroize(priv_key_bytes, sizeof(priv_key_bytes));\n    if (err != ESP_OK && *pub_key) {\n        free(*pub_key);\n        *pub_key = NULL;\n        *pub_key_len = 0;\n    }\n    return err;\n}\n#else /* !CONFIG_MBEDTLS_VER_4_X_SUPPORT */\nstatic esp_err_t esp_encrypted_img_export_ecies_pub_key(hmac_key_id_t hmac_key, uint8_t **pub_key, size_t *pub_key_len)\n{\n    esp_err_t err = ESP_FAIL;\n\n    mbedtls_mpi ecc_priv_key;\n    mbedtls_pk_context pk_ctx;\n    mbedtls_ecp_keypair *ecp_keypair;\n\n    mbedtls_mpi_init(&ecc_priv_key);\n    mbedtls_pk_init(&pk_ctx);\n\n    int ret = derive_ota_ecc_device_key(hmac_key, &ecc_priv_key);\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"Failed to derive ECC device key: -0x%04x\", (unsigned int) - ret);\n        goto exit;\n    }\n\n    // Setup PK context for ECKEY\n    ret = mbedtls_pk_setup(&pk_ctx, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"Failed to setup PK context: -0x%04x\", (unsigned int) - ret);\n        goto exit;\n    }\n\n    ecp_keypair = mbedtls_pk_ec(pk_ctx);\n    if (ecp_keypair == NULL) {\n        ESP_LOGE(TAG, \"Failed to get ECP keypair from PK context\");\n        goto exit;\n    }\n\n    // Load the curve\n    ret = mbedtls_ecp_group_load(&ecp_keypair->MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP256R1);\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"Failed to load ECP group: -0x%04x\", (unsigned int) - ret);\n        goto exit;\n    }\n\n    // Set the private key\n    ret = mbedtls_mpi_copy(&ecp_keypair->MBEDTLS_PRIVATE(d), &ecc_priv_key);\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"Failed to copy private key: -0x%04x\", (unsigned int) - ret);\n        goto exit;\n    }\n\n    // Compute the public key from private key\n    ret = mbedtls_ecp_keypair_calc_public(ecp_keypair, mbedtls_esp_random, NULL);\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"Failed to compute public key: -0x%04x\", (unsigned int) - ret);\n        goto exit;\n    }\n\n    // Public key will be stored in DER format, which includes ASN.1 headers.\n    // For SECP256R1, the maximum DER public key size is:\n    // 30 bytes (ASN.1 overhead) + 2 * 32 bytes (uncompressed coordinates) = 94 bytes\n    size_t max_pubkey_len = DER_ASN1_OVERHEAD + (2 * SECP256R1_COORD_SIZE);\n    *pub_key = calloc(1, max_pubkey_len);\n    if (*pub_key == NULL) {\n        ESP_LOGE(TAG, \"Failed to allocate memory for public key\");\n        err = ESP_ERR_NO_MEM;\n        goto exit;\n    }\n\n    ret = mbedtls_pk_write_pubkey_der(&pk_ctx, *pub_key, max_pubkey_len);\n    if (ret < 0) {\n        ESP_LOGE(TAG, \"Failed to write public key DER: -0x%04x\", (unsigned int) - ret);\n        goto exit;\n    }\n\n    *pub_key_len = ret;\n    if (*pub_key_len > max_pubkey_len) {\n        ESP_LOGE(TAG, \"Public key length exceeds allocated buffer size\");\n        err = ESP_ERR_INVALID_SIZE;\n        goto exit;\n    }\n\n    // Move the memory to the start of the buffer\n    // mbedtls_pk_write_pubkey_der writes the key in reverse order, so we need to adjust the pointer\n    // to point to the start of the key.\n    memmove(*pub_key, *pub_key + (max_pubkey_len - ret), ret);\n\n    // Resize buffer to actual size\n    unsigned char *temp_pub_key = realloc(*pub_key, *pub_key_len);\n    if (temp_pub_key == NULL) {\n        ESP_LOGE(TAG, \"Failed to resize public key buffer\");\n        err = ESP_ERR_NO_MEM;\n        goto exit;\n    }\n    *pub_key = temp_pub_key;\n\n    ESP_LOGI(TAG, \"ECC public key derived successfully\");\n    err = ESP_OK;\n\nexit:\n    mbedtls_pk_free(&pk_ctx);\n    mbedtls_mpi_free(&ecc_priv_key);\n    if (err != ESP_OK && *pub_key) {\n        free(*pub_key);\n        *pub_key = NULL;\n        *pub_key_len = 0;\n    }\n    return err;\n}\n#endif /* CONFIG_MBEDTLS_VER_4_X_SUPPORT */\n\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES */\n\nesp_err_t esp_encrypted_img_export_public_key(esp_decrypt_handle_t ctx, uint8_t **pub_key, size_t *pub_key_len)\n{\n    if (ctx == NULL) {\n        ESP_LOGE(TAG, \"esp_encrypted_img_export_public_key : Invalid argument\");\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    if (pub_key == NULL || pub_key_len == NULL) {\n        ESP_LOGE(TAG, \"esp_encrypted_img_export_public_key : Invalid argument\");\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    esp_encrypted_img_t *handle = (esp_encrypted_img_t *)ctx;\n\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n#if !defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    // In case of RSA, we return the public key corresponding to the private key\n    // passed with esp_encrypted_img_decrypt_start()\n    return esp_encrypted_img_export_rsa_pub_key(handle->rsa_pem, handle->rsa_len, pub_key, pub_key_len);\n#else\n    // In case of RSA with DS, the private key is stored securely in the DS context,\n    // and we cannot export the public key directly.\n    // The public key is derived from the DS context, so we return an error.\n    (void)handle;\n    ESP_LOGE(TAG, \"Public key export is not supported for RSA with DS\");\n    return ESP_ERR_NOT_SUPPORTED;\n#endif /* CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n#elif defined(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\n    // In case of ECIES, we return the public key corresponding to the private key\n    // derived from the HMAC key ID passed with esp_encrypted_img_decrypt_start()\n    return esp_encrypted_img_export_ecies_pub_key(handle->hmac_key, pub_key, pub_key_len);\n#else\n    ESP_LOGE(TAG, \"No public key available for the current encryption scheme\");\n    return ESP_ERR_NOT_FOUND;\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_RSA */\n}\n\nesp_decrypt_handle_t esp_encrypted_img_decrypt_start(const esp_decrypt_cfg_t *cfg)\n{\n    if (cfg == NULL) {\n        ESP_LOGE(TAG, \"esp_encrypted_img_decrypt_start : Invalid argument\");\n        return NULL;\n    }\n\n    ESP_LOGI(TAG, \"Initializing Decryption Handle\");\n\n    esp_encrypted_img_t *handle = calloc(1, sizeof(esp_encrypted_img_t));\n    if (!handle) {\n        ESP_LOGE(TAG, \"Couldn't allocate memory to handle\");\n        goto failure;\n    }\n\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n#if defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    if (cfg->ds_data == NULL) {\n        ESP_LOGE(TAG, \"esp_encrypted_img_decrypt_start : Invalid argument\");\n        goto failure;\n    }\n#if CONFIG_MBEDTLS_VER_4_X_SUPPORT\n    handle->ds_data = cfg->ds_data;\n#else\n    esp_err_t err = esp_ds_init_data_ctx(cfg->ds_data);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to initialize DS context, err: %2x\", err);\n        goto failure;\n    }\n#endif /* CONFIG_MBEDTLS_VER_4_X_SUPPORT */\n#else\n    if (cfg->rsa_priv_key == NULL || cfg->rsa_priv_key_len == 0) {\n        ESP_LOGE(TAG, \"esp_encrypted_img_decrypt_start : Invalid argument\");\n        goto failure;\n    }\n\n    handle->rsa_pem = calloc(1, cfg->rsa_priv_key_len);\n    if (!handle->rsa_pem) {\n        ESP_LOGE(TAG, \"Couldn't allocate memory to handle->rsa_pem\");\n        goto failure;\n    }\n\n    memcpy(handle->rsa_pem, cfg->rsa_priv_key, cfg->rsa_priv_key_len);\n    handle->rsa_len = cfg->rsa_priv_key_len;\n#endif /* CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_RSA */\n\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\n    if (cfg->hmac_key_id < 0 || cfg->hmac_key_id >= HMAC_KEY_MAX) {\n        ESP_LOGE(TAG, \"esp_encrypted_img_decrypt_start : Invalid argument\");\n        goto failure;\n    }\n\n    // Check if the HMAC key is burnt in eFuse\n    if (!esp_encrypted_is_hmac_key_burnt_in_efuse(cfg->hmac_key_id)) {\n        ESP_LOGE(TAG, \"Could not find HMAC key in configured eFuse block!\");\n        goto failure;\n    }\n\n    handle->hmac_key = cfg->hmac_key_id;\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES */\n    handle->cache_buf = calloc(1, ENC_GCM_KEY_SIZE);\n    if (!handle->cache_buf) {\n        ESP_LOGE(TAG, \"Couldn't allocate memory to handle->cache_buf\");\n        goto failure;\n    }\n\n#if defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\n    psa_status_t status = psa_crypto_init();\n    if (status != PSA_SUCCESS) {\n        ESP_LOGE(TAG, \"psa_crypto_init failed: %d\", (int)status);\n        goto failure;\n    }\n#endif /* CONFIG_MBEDTLS_VER_4_X_SUPPORT */\n\n    handle->state = ESP_PRE_ENC_IMG_READ_MAGIC;\n\n    esp_decrypt_handle_t ctx = (esp_decrypt_handle_t)handle;\n    return ctx;\n\nfailure:\n    if (handle) {\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA) && !defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n        free(handle->rsa_pem);\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_RSA */\n        if (handle->cache_buf) {\n            free(handle->cache_buf);\n            handle->cache_buf = NULL;\n        }\n        free(handle);\n    }\n    return NULL;\n}\n\nstatic esp_err_t process_bin(esp_encrypted_img_t *handle, pre_enc_decrypt_arg_t *args, int curr_index)\n{\n    size_t data_len = args->data_in_len;\n    size_t data_out_size = args->data_out_len;\n    size_t output_len = 0;\n\n    handle->binary_file_read += data_len - curr_index;\n    int dec_len = 0;\n    if (handle->binary_file_read != handle->binary_file_len) {\n        size_t copy_len = 0;\n\n        if ((handle->cache_buf_len + (data_len - curr_index)) - (handle->cache_buf_len + (data_len - curr_index)) % CACHE_BUF_SIZE > 0) {\n            data_out_size = (handle->cache_buf_len + (data_len - curr_index)) - (handle->cache_buf_len + (data_len - curr_index)) % CACHE_BUF_SIZE;\n            args->data_out = realloc(args->data_out, data_out_size);\n            if (!args->data_out) {\n                return ESP_ERR_NO_MEM;\n            }\n        }\n        if (handle->cache_buf_len != 0) {\n            copy_len = MIN(CACHE_BUF_SIZE - handle->cache_buf_len, data_len - curr_index);\n            memcpy(handle->cache_buf + handle->cache_buf_len, args->data_in + curr_index, copy_len);\n            handle->cache_buf_len += copy_len;\n            if (handle->cache_buf_len != CACHE_BUF_SIZE) {\n                args->data_out_len = 0;\n                return ESP_ERR_NOT_FINISHED;\n            }\n            if (gcm_update(handle, (const unsigned char *)handle->cache_buf, CACHE_BUF_SIZE,\n                           (unsigned char *)args->data_out, data_out_size, &output_len) != ESP_OK) {\n                return ESP_FAIL;\n            }\n            dec_len = CACHE_BUF_SIZE;\n        }\n        handle->cache_buf_len = (data_len - curr_index - copy_len) % CACHE_BUF_SIZE;\n        if (handle->cache_buf_len != 0) {\n            data_len -= handle->cache_buf_len;\n            memcpy(handle->cache_buf, args->data_in + (data_len), handle->cache_buf_len);\n        }\n\n        if (data_len - copy_len - curr_index > 0) {\n            if (gcm_update(handle, (const unsigned char *)args->data_in + curr_index + copy_len,\n                           data_len - copy_len - curr_index,\n                           (unsigned char *)args->data_out + dec_len,\n                           data_out_size - dec_len, &output_len) != ESP_OK) {\n                return ESP_FAIL;\n            }\n        }\n        args->data_out_len = dec_len + data_len - curr_index - copy_len;\n        return ESP_ERR_NOT_FINISHED;\n    }\n    data_out_size = handle->cache_buf_len + data_len - curr_index;\n\n    /* Handle zero-size allocation edge case to avoid undefined behavior */\n    if (data_out_size == 0) {\n        if (args->data_out) {\n            free(args->data_out);\n            args->data_out = NULL;\n        }\n        args->data_out_len = 0;\n        return ESP_OK;\n    }\n\n    /* Use temporary pointer to prevent memory leak if realloc fails */\n    void *temp = realloc(args->data_out, data_out_size);\n    if (!temp) {\n        /* Original pointer remains valid, caller should free it */\n        return ESP_ERR_NO_MEM;\n    }\n    args->data_out = temp;\n    size_t copy_len = 0;\n\n    copy_len = MIN(CACHE_BUF_SIZE - handle->cache_buf_len, data_len - curr_index);\n    memcpy(handle->cache_buf + handle->cache_buf_len, args->data_in + curr_index, copy_len);\n    handle->cache_buf_len += copy_len;\n    if (gcm_update(handle, (const unsigned char *)handle->cache_buf, handle->cache_buf_len,\n                   (unsigned char *)args->data_out, data_out_size, &output_len) != ESP_OK) {\n        return ESP_FAIL;\n    }\n    if (data_len - curr_index - copy_len > 0) {\n        if (gcm_update(handle, (const unsigned char *)(args->data_in + curr_index + copy_len),\n                       data_len - curr_index - copy_len,\n                       (unsigned char *)(args->data_out + CACHE_BUF_SIZE),\n                       data_out_size - CACHE_BUF_SIZE, &output_len) != ESP_OK) {\n            return ESP_FAIL;\n        }\n    }\n\n    args->data_out_len = handle->cache_buf_len + data_len - copy_len - curr_index;\n    handle->cache_buf_len = 0;\n\n    return ESP_OK;\n}\n\nstatic void read_and_cache_data(esp_encrypted_img_t *handle, pre_enc_decrypt_arg_t *args, int *curr_index, int data_size)\n{\n    const int data_left = data_size - handle->binary_file_read;\n    const int data_recv = args->data_in_len - *curr_index;\n    if (handle->state == ESP_PRE_ENC_IMG_READ_IV) {\n        memcpy(handle->iv + handle->cache_buf_len, args->data_in + *curr_index, MIN(data_recv, data_left));\n    } else if (handle->state == ESP_PRE_ENC_IMG_READ_AUTH) {\n        memcpy(handle->auth_tag + handle->cache_buf_len, args->data_in + *curr_index, MIN(data_recv, data_left));\n    } else {\n        memcpy(handle->cache_buf + handle->cache_buf_len, args->data_in + *curr_index, MIN(data_recv, data_left));\n    }\n    handle->cache_buf_len += MIN(data_recv, data_left);\n    int temp = *curr_index;\n    *curr_index += MIN(data_recv, data_left);\n    handle->binary_file_read += MIN(args->data_in_len - temp, data_left);\n}\n\nstatic esp_err_t process_gcm_key(esp_encrypted_img_t *handle, const char *data_in, size_t data_in_len)\n{\n    if (data_in_len < ENC_GCM_KEY_SIZE) {\n        ESP_LOGE(TAG, \"GCM key size is less than expected\");\n        return ESP_FAIL;\n    }\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n    if (decipher_gcm_key(data_in, handle) != 0) {\n        ESP_LOGE(TAG, \"Unable to decipher GCM key\");\n        return ESP_FAIL;\n    }\n#elif defined(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\n    if (derive_gcm_key(data_in, handle) != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to derive GCM key\");\n        return ESP_FAIL;\n    }\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_RSA */\n    return ESP_OK;\n}\n\nesp_err_t esp_encrypted_img_decrypt_data(esp_decrypt_handle_t ctx, pre_enc_decrypt_arg_t *args)\n{\n    if (ctx == NULL || args == NULL || args->data_in == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    esp_encrypted_img_t *handle = (esp_encrypted_img_t *)ctx;\n    if (handle == NULL) {\n        ESP_LOGE(TAG, \"esp_encrypted_img_decrypt_data: Invalid argument\");\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    esp_err_t err;\n    int curr_index = 0;\n\n    switch (handle->state) {\n    case ESP_PRE_ENC_IMG_READ_MAGIC:\n        if (handle->cache_buf_len == 0 && (args->data_in_len - curr_index) >= MAGIC_SIZE) {\n            uint32_t recv_magic = *(uint32_t *)args->data_in;\n            if (recv_magic != esp_enc_img_magic) {\n                ESP_LOGE(TAG, \"Magic Verification failed\");\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA) && !defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n                free(handle->rsa_pem);\n                handle->rsa_pem = NULL;\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_RSA */\n                return ESP_FAIL;\n            }\n            curr_index += MAGIC_SIZE;\n        } else {\n            read_and_cache_data(handle, args, &curr_index, MAGIC_SIZE);\n            if (handle->binary_file_read == MAGIC_SIZE) {\n                uint32_t recv_magic = *(uint32_t *)handle->cache_buf;\n\n                if (recv_magic != esp_enc_img_magic) {\n                    ESP_LOGE(TAG, \"Magic Verification failed\");\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA) && !defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n                    free(handle->rsa_pem);\n                    handle->rsa_pem = NULL;\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_RSA */\n                    return ESP_FAIL;\n                }\n                handle->binary_file_read = 0;\n                handle->cache_buf_len = 0;\n            } else {\n                return ESP_ERR_NOT_FINISHED;\n            }\n        }\n        ESP_LOGI(TAG, \"Magic Verified\");\n        handle->state = ESP_PRE_ENC_IMG_READ_GCM;\n    /* falls through */\n    case ESP_PRE_ENC_IMG_READ_GCM:\n        if (handle->cache_buf_len == 0 && args->data_in_len - curr_index >= ENC_GCM_KEY_SIZE) {\n            if (process_gcm_key(handle, args->data_in + curr_index, ENC_GCM_KEY_SIZE) != ESP_OK) {\n                ESP_LOGE(TAG, \"Failed to process GCM key\");\n                handle->cache_buf_len = 0;\n                return ESP_FAIL;\n            }\n            curr_index += ENC_GCM_KEY_SIZE;\n        } else {\n            read_and_cache_data(handle, args, &curr_index, ENC_GCM_KEY_SIZE);\n            if (handle->cache_buf_len == ENC_GCM_KEY_SIZE) {\n                if (process_gcm_key(handle, handle->cache_buf, ENC_GCM_KEY_SIZE) != ESP_OK) {\n                    ESP_LOGE(TAG, \"Failed to process GCM key\");\n                    handle->cache_buf_len = 0;\n                    return ESP_FAIL;\n                }\n            } else {\n                return ESP_ERR_NOT_FINISHED;\n            }\n        }\n    /* falls through */\n    case ESP_PRE_ENC_IMG_READ_IV:\n        if (handle->cache_buf_len == 0 && args->data_in_len - curr_index >= IV_SIZE) {\n            memcpy(handle->iv, args->data_in + curr_index, IV_SIZE);\n            handle->binary_file_read = IV_SIZE;\n            curr_index += IV_SIZE;\n        } else {\n            read_and_cache_data(handle, args, &curr_index, IV_SIZE);\n        }\n        if (handle->binary_file_read == IV_SIZE) {\n            handle->state = ESP_PRE_ENC_IMG_READ_BINSIZE;\n            handle->binary_file_read = 0;\n            handle->cache_buf_len = 0;\n\n            /* Initialize GCM with key and IV using abstraction layer */\n            if (gcm_init_and_set_key(handle, (const unsigned char *)handle->gcm_key, GCM_KEY_SIZE * 8) != ESP_OK) {\n                return ESP_FAIL;\n            }\n            if (gcm_start(handle, (const unsigned char *)handle->iv, IV_SIZE) != ESP_OK) {\n                return ESP_FAIL;\n            }\n        } else {\n            return ESP_ERR_NOT_FINISHED;\n        }\n    /* falls through */\n    case ESP_PRE_ENC_IMG_READ_BINSIZE:\n        if (handle->cache_buf_len == 0 && (args->data_in_len - curr_index) >= BIN_SIZE_DATA) {\n            handle->binary_file_len = *(uint32_t *)(args->data_in + curr_index);\n            curr_index += BIN_SIZE_DATA;\n        } else {\n            read_and_cache_data(handle, args, &curr_index, BIN_SIZE_DATA);\n            if (handle->binary_file_read == BIN_SIZE_DATA) {\n                handle->binary_file_len = *(uint32_t *)handle->cache_buf;\n            } else {\n                return ESP_ERR_NOT_FINISHED;\n            }\n        }\n        handle->state = ESP_PRE_ENC_IMG_READ_AUTH;\n        handle->binary_file_read = 0;\n        handle->cache_buf_len = 0;\n    /* falls through */\n    case ESP_PRE_ENC_IMG_READ_AUTH:\n        if (handle->cache_buf_len == 0 && args->data_in_len - curr_index >= AUTH_SIZE) {\n            memcpy(handle->auth_tag, args->data_in + curr_index, AUTH_SIZE);\n            handle->binary_file_read = AUTH_SIZE;\n            curr_index += AUTH_SIZE;\n        } else {\n            read_and_cache_data(handle, args, &curr_index, AUTH_SIZE);\n        }\n        if (handle->binary_file_read == AUTH_SIZE) {\n            handle->state = ESP_PRE_ENC_IMG_READ_EXTRA_HEADER;\n            handle->binary_file_read = 0;\n            handle->cache_buf_len = 0;\n        } else {\n            return ESP_ERR_NOT_FINISHED;\n        }\n    /* falls through */\n    case ESP_PRE_ENC_IMG_READ_EXTRA_HEADER: {\n        int temp = curr_index;\n        curr_index += MIN(args->data_in_len - curr_index, RESERVED_HEADER - handle->binary_file_read);\n        handle->binary_file_read += MIN(args->data_in_len - temp, RESERVED_HEADER - handle->binary_file_read);\n        if (handle->binary_file_read == RESERVED_HEADER) {\n            handle->state = ESP_PRE_ENC_DATA_DECODE_STATE;\n            handle->binary_file_read = 0;\n            handle->cache_buf_len = 0;\n        } else {\n            return ESP_ERR_NOT_FINISHED;\n        }\n    }\n    /* falls through */\n    case ESP_PRE_ENC_DATA_DECODE_STATE:\n        err = process_bin(handle, args, curr_index);\n        return err;\n    }\n    return ESP_OK;\n}\n\nesp_err_t esp_encrypted_img_decrypt_end(esp_decrypt_handle_t ctx)\n{\n    if (ctx == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    esp_encrypted_img_t *handle = (esp_encrypted_img_t *)ctx;\n    esp_err_t err = ESP_OK;\n    if (handle == NULL) {\n        ESP_LOGE(TAG, \"esp_encrypted_img_decrypt_data: Invalid argument\");\n        return ESP_ERR_INVALID_ARG;\n    }\n    if (handle->state == ESP_PRE_ENC_DATA_DECODE_STATE) {\n        if (handle->cache_buf_len != 0 || handle->binary_file_read != handle->binary_file_len) {\n            ESP_LOGE(TAG, \"Invalid operation\");\n            err = ESP_FAIL;\n            goto exit;\n        }\n\n        /* Verify authentication tag using abstraction layer */\n        if (gcm_finish_and_verify(handle, (const unsigned char *)handle->auth_tag, AUTH_SIZE) != ESP_OK) {\n            err = ESP_FAIL;\n            goto exit;\n        }\n    } else {\n        // If the state is not ESP_PRE_ENC_DATA_DECODE_STATE, it means that the\n        // decryption process was not completed successfully.\n        ESP_LOGE(TAG, \"Decryption process not completed successfully\");\n        err = ESP_FAIL;\n        goto exit;\n    }\n    err = ESP_OK;\nexit:\n    gcm_cleanup(handle);\n    free(handle->cache_buf);\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n#if defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n#if !defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\n    esp_ds_deinit_data_ctx();\n#endif /* CONFIG_MBEDTLS_VER_4_X_SUPPORT */\n#else\n    free(handle->rsa_pem);\n    handle->rsa_pem = NULL;\n#endif /* CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_RSA */\n    free(handle);\n    return err;\n}\n\nbool esp_encrypted_img_is_complete_data_received(esp_decrypt_handle_t ctx)\n{\n    esp_encrypted_img_t *handle = (esp_encrypted_img_t *)ctx;\n    return (handle != NULL && handle->binary_file_len == handle->binary_file_read);\n}\n\nesp_err_t esp_encrypted_img_decrypt_abort(esp_decrypt_handle_t ctx)\n{\n    esp_encrypted_img_t *handle = (esp_encrypted_img_t *)ctx;\n    if (handle == NULL) {\n        ESP_LOGE(TAG, \"esp_encrypted_img_decrypt_abort: Invalid argument\");\n        return ESP_ERR_INVALID_ARG;\n    }\n    gcm_cleanup(handle);\n    free(handle->cache_buf);\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n#if defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n#if !defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\n    esp_ds_deinit_data_ctx();\n#endif /* CONFIG_MBEDTLS_VER_4_X_SUPPORT */\n#else\n    free(handle->rsa_pem);\n    handle->rsa_pem = NULL;\n#endif /* CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_RSA */\n    free(handle);\n    return ESP_OK;\n}\n\nuint16_t esp_encrypted_img_get_header_size(void)\n{\n    return HEADER_DATA_SIZE;\n}\n"
  },
  {
    "path": "esp_encrypted_img/src/esp_encrypted_img_utilities.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include \"esp_encrypted_img_utilities.h\"\n\n#define SHA256_MD_SIZE 32\n\nstatic const char *TAG = \"esp_efuse_utilities\";\n\nstatic esp_efuse_block_t convert_key_type(hmac_key_id_t key_id)\n{\n    return (esp_efuse_block_t)(EFUSE_BLK_KEY0 + (esp_efuse_block_t) key_id);\n}\n\nbool esp_encrypted_is_hmac_key_burnt_in_efuse(hmac_key_id_t hmac_key_id)\n{\n    bool ret = false;\n\n    esp_efuse_block_t hmac_key_blk = convert_key_type(hmac_key_id);\n\n    esp_efuse_purpose_t hmac_efuse_blk_purpose = esp_efuse_get_key_purpose(hmac_key_blk);\n    if (hmac_efuse_blk_purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_UP) {\n        ret = true;\n    }\n\n    return ret;\n}\n\nint esp_encrypted_img_pbkdf2_hmac_sha256(hmac_key_id_t hmac_key_id, const unsigned char *salt, size_t salt_len,\n        size_t iteration_count, size_t key_length, unsigned char *output)\n{\n    int ret = -1;\n    int j;\n    unsigned int i;\n    unsigned char md1[SHA256_MD_SIZE] = {0};\n    unsigned char work[SHA256_MD_SIZE] = {0};\n    // Considering that we only have SHA256, fixing the MD_SIZE to 32 bytes\n    const size_t MD_SIZE = SHA256_MD_SIZE;\n    size_t use_len;\n    unsigned char *out_p = output;\n    unsigned char counter[4] = {0};\n    counter[3] = 1;\n\n    esp_err_t esp_ret = ESP_FAIL;\n    uint8_t *hmac_input = (uint8_t *) calloc(1, salt_len + sizeof(counter) + 1);\n    if (hmac_input == NULL) {\n        ESP_LOGE(TAG, \"Failed to allocate memory for hmac input\");\n        return -1;\n    }\n\n    while (key_length) {\n        // U1 ends up in work\n        size_t hmac_input_len = 0;\n        memcpy(hmac_input, salt, salt_len);\n        hmac_input_len = hmac_input_len + salt_len;\n        memcpy(hmac_input + salt_len, counter, sizeof(counter));\n        hmac_input_len = hmac_input_len + sizeof(counter);\n        esp_ret = esp_hmac_calculate(hmac_key_id, hmac_input, hmac_input_len, work);\n        if (esp_ret != ESP_OK) {\n            ESP_LOGE(TAG, \"Could not calculate the HMAC value, returned %04X\", esp_ret);\n            ret = -1;\n            goto cleanup;\n        }\n\n        memcpy(md1, work, MD_SIZE);\n\n        for (i = 1; i < iteration_count; i++) {\n            // U2 ends up in md1\n            esp_ret = esp_hmac_calculate(hmac_key_id, md1, MD_SIZE, md1);\n            if (esp_ret != ESP_OK) {\n                ESP_LOGE(TAG, \"Could not calculate the HMAC value, returned %04X\", esp_ret);\n                ret = -1;\n                goto cleanup;\n            }\n            // U1 xor U2\n            for (j = 0; j < MD_SIZE; j++) {\n                work[j] ^= md1[j];\n            }\n        }\n\n        use_len = (key_length < MD_SIZE) ? key_length : MD_SIZE;\n        memcpy(out_p, work, use_len);\n\n        key_length -= (uint32_t) use_len;\n        out_p += use_len;\n\n        for (i = 4; i > 0; i--) {\n            if (++counter[i - 1] != 0) {\n                break;\n            }\n        }\n    }\n    //Success\n    ret = 0;\n\ncleanup:\n    /* Zeroise buffers to clear sensitive data from memory. */\n    free(hmac_input);\n    memset(work, 0, SHA256_MD_SIZE);\n    memset(md1, 0, SHA256_MD_SIZE);\n    return ret;\n}\n"
  },
  {
    "path": "esp_encrypted_img/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(esp_encrypted_img_test)\n\nif (CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    set(partition esp_secure_cert)\n    idf_build_get_property(project_dir PROJECT_DIR)\n    set(image_file ${project_dir}/esp_secure_cert_data/${partition}.bin)\n    partition_table_get_partition_info(offset \"--partition-name ${partition}\" \"offset\")\n    esptool_py_flash_target_image(flash \"${partition}\" \"${offset}\" \"${image_file}\")\nendif()\n"
  },
  {
    "path": "esp_encrypted_img/test_apps/main/CMakeLists.txt",
    "content": "if (CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\n    set(EMBED_FILES \"image_ecc.bin\")\nelse()\n    set(EMBED_FILES \"image.bin\")\nendif()\n\nidf_component_register(SRCS \"esp_encrypted_img_test.c\" \"test.c\" \"test_mocks.c\"\n                    PRIV_INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES unity esp_encrypted_img efuse mbedtls\n                    EMBED_TXTFILES certs/test_rsa_private_key.pem\n                    EMBED_FILES \"${EMBED_FILES}\"\n                    WHOLE_ARCHIVE\n                    )\n\nif (CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    target_link_libraries(${COMPONENT_LIB} INTERFACE \"-Wl,--wrap=esp_efuse_get_key_purpose\")\nendif()\n"
  },
  {
    "path": "esp_encrypted_img/test_apps/main/certs/test_rsa_private_key.pem",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIG4wIBAAKCAYEA9eoohqolow2z6JsuBvqLLP+jfA/ha8t03skR0F4cKMXNFoc2\nQbqdYjRBaFOrkoUD/KC2TzvCjU3OZ3wuGDDjFWURsezUeYCH+r4PcF/qE6vXW1kV\nueE5jImTtxSsnt1HLFAGiUnILUJ7xi3cd86Y8mF0VH2wfmDKo8ESBRbev0eChCJA\nxdynuuyo0m+IN9r7cNStCKz3jglipjnI5+OxtJgw/0fMaCfjtn7KIFktGEeXqJ1r\nuRBALN+i70zZjjDtJj37FL5t4LCgrkImwLpBALVYFXy1wXhMXq7h5cU2Ec6bRVBl\n6GH1xx2lABQ1LVFwrilgklLjY5UTdx8GHE/veR4Sla3dYyE5MKLJ3Kmc7NxlPlWn\nWTmUKAWYIJiRIwBHSBntUgGyBYBqzfBSYFWL3gmTmvV/JQ41laX7qykdabvgdGSR\nLJF6wZMdpJpvafYDBRwV7psvhPkHEXBUSe2dtfWKStiUPT7gcZE1ICMxT26Qlaf9\nT2GvYwyq4WBkEntzAgMBAAECggGAJKYUChW7bDRzlnvh/SpDqZ4jmC6psq3sqfMf\nU4Vi/vSTnwLhpCQSpnsRMGIf1MM8F98/rElEslhhJW0NVY+bmCmq3HBmLgFowoam\nuGGi+fGHM9bv9PbK49XxDLzpCPgDTmhSwQ0c5xncZmmZTMWeZ6j8dEcTEZKNQKBa\ndiW1Zp5apiSQsKw01xfEBTCYBXL+PA+GBh/4+NMPP6Sm+2AksLxpuPHTVcZ0GlOE\n/hMsNE0fHgLv9fGlDsr5dl5modlKg7fnBejEAhnCPQadVdP2DiO6sXJbSGIxRc0c\nWRT2nnmbN9UOAxKgO4Lz0ixgcPqBAD5ZDx4p5pVnakH1lB/Gh4VH4nAzxj8sUd0c\nQcTJ06oHA8OVL/M01IRn4JUMeWdnO+AcuV45uszAx805ZJGRVeQMw/oGzjtYGjuk\njogdN279LcntDempzafBL8knD7GA/t2eCYf4Glwy7ZL9XW7b6w+J9pPD+4gduVCv\nKcvdJxw4SM4q0HJo8YqCDfzQiOKZAoHBAP7JVMrkALdg2AovnRYgzHiLF56JMLip\nI3l2jjz1fbi9dl+SRSD2LEhwuxy4/XWv5cu7O6dZJ4vG5RpjmFsCpLBRkuRp8qcx\nV15T9M+2wFZX1kYCSgU5nljM+Szchs75k+3rKbRbfMQhreAxxTVV3T7i6aTq9nuR\nPI26o8lNTDz6DCfGEkMM2Fg+ydTLGu+o2WIoSWO/o5xc1/l/aBbvbdZ5cRiRUbct\nCiAeIO75hGHZJBgGaAqJI+p9g6tQbFXKbQKBwQD3FgJsj86C7qNSj5sVvbUqNI6Y\nG0MfDLYlI01JAMtdiwgvafF91LNX2j/bHvglo4j6TI9zw2y4L/J0E3mMN0jCJXKE\nDK91vwKwU9yMzacvVH8XgC+ntN9NPG/048Y4j4D3zgfoiNl2/AoazOjpL0iE2gGw\nCayx7JG4KrM41ZybpjafGfp/+ZgTeYZHiBEsNHQ/rSMw7bGkt2jKC4cywEtYCsM/\nmbr0QcUWH74Tx6YWdm6xGODEERjnu7IdbYADsV8CgcEAl5qMzb0lf/gsFMOIISab\nBA8fmsHfL8HUze1xbWxVxptV2EBcyeQxLVmGvOyGRITJo5RhRo6SLWXH5Q/mFCFa\nhV/EnA0+yaVea05hmUcQ40+YvEeYa8uBIS22Bq+ht35iO2t2gU7+ymWP5Js40Seq\nYkT66Zq114jwExU/aASKnK3clb4SF7uI79lMl0XTXU+HKhT2tlfNrri/+kGJWjxV\niwzv8sJlcS1nnPzQc+Icl2xxQapuNfasXFcbBdDw5YtxAoHAH8Zo0WU8/YGK51co\nbodTAPZ5T/5Rh3CvC9+aVMURYho7Fz3cnH36AlZC1/8Hkm+Rcf7eg9ih5p3j5CGN\nBAcoCC+gpnKrLc0+n0ZpmoHn+iI3peIKPtr3zIr1Kt0P5L4vq66HPdQ7gx2ufvvT\nCAnYnZ0bknPsDYWKx9BV8/0kgq/BXnyMxmBmujpqllBdRP4J5RZy7BvlOHWNuE37\nOP+ZsNzRdyBh9n9uxQWYABswtLrOSWAVp6E7PrHYmgg26kKpAoHABDv9fxlBrrCh\nVGCRevH4ojHOoSvF0FqDzg0ixttPBxOYlKB6ggf+vOBjZVkE5ahON7IvTBvfiPAY\n/H9J3uV6OGufzZURuXNdad1NFbcQvfHWvIgGhBozZe5b1seImG21PXDWIb2uZotw\nFg7eaXVYZDeA9jMA9roBbDnwypLAXO4Ve6/J9VXZmOBeXV9rbb0RuWEXgQ9FI1fT\nCG3od/wm0D0sbZsAoNMD/fVOYRhbxQESpzynsgoxlWfzv2+t3Wjn\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "esp_encrypted_img/test_apps/main/esp_encrypted_img_test.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"unity.h\"\n#include \"unity_test_runner.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_newlib.h\"\n#include \"soc/soc_caps.h\"\n#include \"unity_test_utils_memory.h\"\n\n#include \"soc/soc_caps.h\"\n\n#if defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\n#include \"psa/crypto.h\"\n#else\n#include \"mbedtls/aes.h\"\n#endif\n\nvoid setUp(void)\n{\n#if SOC_AES_SUPPORTED\n    // Execute AES operation to allocate AES interrupt\n    // allocation memory which is considered as leak otherwise\n    const uint8_t plaintext[16] = {0};\n    uint8_t ciphertext[16];\n    const uint8_t key[16] = { 0 };\n#if defined(CONFIG_MBEDTLS_VER_4_X_SUPPORT)\n    psa_status_t status = psa_crypto_init();\n    TEST_ASSERT_EQUAL(PSA_SUCCESS, status);\n    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;\n    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);\n    psa_set_key_algorithm(&attributes, PSA_ALG_ECB_NO_PADDING);\n    psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);\n    psa_set_key_bits(&attributes, 128);\n    psa_key_id_t key_id;\n    status = psa_import_key(&attributes, key, sizeof(key), &key_id);\n    TEST_ASSERT_EQUAL(PSA_SUCCESS, status);\n    size_t output_length;\n    status = psa_cipher_encrypt(key_id, PSA_ALG_ECB_NO_PADDING, plaintext, sizeof(plaintext),\n                                ciphertext, sizeof(ciphertext), &output_length);\n    TEST_ASSERT_EQUAL(PSA_SUCCESS, status);\n    psa_destroy_key(key_id);\n\n    /* Warm up AES-GCM with a large buffer to trigger one-time DMA/interrupt\n     * allocations that occur when psa_aead_update processes large inputs */\n    const uint8_t gcm_key[32] = {0};\n    const uint8_t gcm_nonce[12] = {0};\n    psa_key_attributes_t gcm_attr = PSA_KEY_ATTRIBUTES_INIT;\n    psa_set_key_type(&gcm_attr, PSA_KEY_TYPE_AES);\n    psa_set_key_bits(&gcm_attr, 256);\n    psa_set_key_usage_flags(&gcm_attr, PSA_KEY_USAGE_ENCRYPT);\n    psa_set_key_algorithm(&gcm_attr, PSA_ALG_GCM);\n    psa_key_id_t gcm_key_id;\n    status = psa_import_key(&gcm_attr, gcm_key, sizeof(gcm_key), &gcm_key_id);\n    if (status == PSA_SUCCESS) {\n        psa_aead_operation_t aead_op = psa_aead_operation_init();\n        status = psa_aead_encrypt_setup(&aead_op, gcm_key_id, PSA_ALG_GCM);\n        if (status == PSA_SUCCESS) {\n            psa_aead_set_nonce(&aead_op, gcm_nonce, sizeof(gcm_nonce));\n            /* Use a large stack buffer to trigger DMA-mode AES-GCM */\n            uint8_t *gcm_buf = calloc(1, 4096);\n            if (gcm_buf) {\n                size_t gcm_olen;\n                psa_aead_update(&aead_op, gcm_buf, 4096,\n                                gcm_buf, 4096, &gcm_olen);\n                free(gcm_buf);\n            }\n        }\n        psa_aead_abort(&aead_op);\n        psa_destroy_key(gcm_key_id);\n    }\n#else\n    mbedtls_aes_context ctx;\n    mbedtls_aes_init(&ctx);\n    mbedtls_aes_setkey_enc(&ctx, key, 128);\n    mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, plaintext, ciphertext);\n    mbedtls_aes_free(&ctx);\n#endif\n#endif // SOC_AES_SUPPORTED\n\n    unity_utils_record_free_mem();\n}\n\nvoid tearDown(void)\n{\n    esp_reent_cleanup();    //clean up some of the newlib's lazy allocations\n\n    unity_utils_evaluate_leaks_direct(200);\n}\n\nvoid app_main(void)\n{\n    printf(\"Running esp_encrypted_img component tests\\n\");\n    unity_run_menu();\n}\n"
  },
  {
    "path": "esp_encrypted_img/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/esp_encrypted_img:\n    version: \"*\"\n    override_path: \"../..\""
  },
  {
    "path": "esp_encrypted_img/test_apps/main/test.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n#include <stdio.h>\n#include <freertos/FreeRTOS.h>\n\n#include \"unity.h\"\n#if __has_include(\"esp_random.h\")\n#include \"esp_random.h\"\n#else\n#include \"esp_system.h\"\n#endif\n#include \"esp_encrypted_img.h\"\n#include \"sdkconfig.h\"\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES) || \\\n    (defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA) && defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS))\n#include \"test_mocks.h\"\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES */\n#include <string.h>\n\n#ifdef CONFIG_HEAP_TRACING\n#include <esp_heap_trace.h>\n#define NUM_RECORDS 100\nstatic heap_trace_record_t trace_record[NUM_RECORDS]; // This buffer must be in internal RAM\n#endif\n\nextern const uint8_t rsa_private_pem_start[] asm(\"_binary_test_rsa_private_key_pem_start\");\nextern const uint8_t rsa_private_pem_end[]   asm(\"_binary_test_rsa_private_key_pem_end\");\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\nextern const uint8_t bin_start[] asm(\"_binary_image_ecc_bin_start\");\nextern const uint8_t bin_end[]   asm(\"_binary_image_ecc_bin_end\");\n#else\nextern const uint8_t bin_start[] asm(\"_binary_image_bin_start\");\nextern const uint8_t bin_end[]   asm(\"_binary_image_bin_end\");\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES */\n\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA) && defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\nstatic const unsigned char encrypted_gcm_key_bin[] = {\n    0x42, 0xbf, 0x3a, 0xc5, 0x22, 0xd3, 0x1b, 0xca, 0x8e, 0x75, 0xa7, 0x42,\n    0x13, 0x1d, 0xcc, 0xcd, 0x1a, 0x1f, 0xcc, 0x37, 0x80, 0xbe, 0x05, 0x86,\n    0xd9, 0x83, 0x47, 0x95, 0x3f, 0x1e, 0x8d, 0xa1, 0xed, 0xd7, 0xcd, 0xfe,\n    0xae, 0xf4, 0xa5, 0xe3, 0x07, 0x89, 0xb1, 0xd2, 0x68, 0xf5, 0xd8, 0x8c,\n    0x53, 0x82, 0x5a, 0xa0, 0xde, 0x79, 0x84, 0x84, 0xba, 0x9f, 0xe3, 0x6a,\n    0x06, 0x28, 0x7a, 0xae, 0x32, 0x1b, 0x1f, 0x7d, 0x6b, 0xdb, 0x67, 0x27,\n    0x41, 0x7c, 0x38, 0xb0, 0x4d, 0x50, 0xe6, 0x52, 0x88, 0x61, 0x5a, 0xe5,\n    0x97, 0x2b, 0xce, 0x17, 0x6d, 0x5f, 0xc4, 0xbc, 0x6e, 0x87, 0x13, 0x34,\n    0xc5, 0xec, 0x96, 0xbc, 0x00, 0x7c, 0x14, 0xdc, 0x70, 0xa2, 0xa6, 0x29,\n    0x29, 0xe6, 0x88, 0x81, 0x0f, 0x16, 0x9e, 0x6d, 0xd5, 0xea, 0x62, 0xcb,\n    0x8b, 0xc8, 0x42, 0x9e, 0x2d, 0xd8, 0x0f, 0x34, 0x74, 0x60, 0xb0, 0xf8,\n    0x67, 0xa9, 0x43, 0x0a, 0x73, 0x51, 0x24, 0x69, 0xad, 0x6d, 0x5f, 0x58,\n    0x8a, 0x38, 0xed, 0xff, 0x76, 0x25, 0xb4, 0xff, 0xd7, 0xb8, 0x4d, 0x66,\n    0x77, 0xaa, 0x73, 0x25, 0x27, 0x00, 0xce, 0x10, 0x94, 0x69, 0xf3, 0x1b,\n    0xfc, 0x73, 0xe9, 0x00, 0xee, 0x9d, 0xc2, 0x36, 0x4f, 0xcf, 0xd6, 0x41,\n    0xf8, 0x61, 0x67, 0x85, 0xe2, 0xa9, 0xf6, 0xb2, 0x46, 0xad, 0x69, 0x6f,\n    0xf5, 0xe9, 0xb9, 0xc7, 0x64, 0x41, 0x10, 0xa1, 0x44, 0xe9, 0x24, 0x82,\n    0x2e, 0xe7, 0x38, 0x63, 0xa9, 0xd1, 0x06, 0x6b, 0x55, 0xf7, 0xed, 0x53,\n    0xaf, 0xa5, 0xc3, 0x21, 0xa0, 0xbe, 0x4b, 0xb3, 0x7d, 0xcb, 0x1a, 0x9d,\n    0x52, 0x62, 0x24, 0x4d, 0x0c, 0xf8, 0xdd, 0xaf, 0x64, 0x35, 0x0c, 0x90,\n    0xd0, 0x41, 0x08, 0x26, 0xd7, 0xa9, 0x09, 0xd8, 0x21, 0xf3, 0x88, 0xf3,\n    0x46, 0x59, 0xc3, 0xee, 0x41, 0x88, 0x5c, 0x7a, 0x6b, 0x69, 0xbd, 0x02,\n    0xaf, 0xba, 0x7c, 0xcd, 0x2f, 0xf8, 0x57, 0x8c, 0x6b, 0xcf, 0xbc, 0xa0,\n    0x2d, 0x13, 0x22, 0xfc, 0x28, 0x59, 0x60, 0xb2, 0x54, 0x6a, 0xfe, 0x38,\n    0x75, 0x5c, 0x4a, 0x9d, 0xdb, 0xaa, 0x36, 0x1d, 0x1e, 0xb4, 0xc2, 0x0d,\n    0xde, 0xea, 0x08, 0x85, 0xac, 0x64, 0x51, 0xa1, 0x5d, 0xd2, 0xef, 0x63,\n    0x28, 0xf4, 0x6b, 0x45, 0x33, 0x47, 0x55, 0x0e, 0xd3, 0xc5, 0x8b, 0xce,\n    0xf4, 0x15, 0xb0, 0x57, 0xf6, 0x5b, 0xae, 0x15, 0x41, 0x0c, 0x32, 0xa7,\n    0x6f, 0x99, 0x55, 0xf7, 0x42, 0x2b, 0x55, 0x5e, 0x09, 0x3f, 0x1c, 0xa8,\n    0xf4, 0x7f, 0x1b, 0x99, 0x15, 0xc2, 0xb4, 0x34, 0x7c, 0x9a, 0xef, 0x7c,\n    0x5e, 0x70, 0x6c, 0x86, 0x64, 0xae, 0x2b, 0x0c, 0x37, 0xeb, 0x9f, 0x27,\n    0x18, 0x72, 0x50, 0x5f, 0xf8, 0x03, 0xd5, 0xb1, 0x55, 0x03, 0x24, 0xb1\n};\n\nunsigned char encrypted_gcm_key_bin_v21[] = {\n    0x20, 0x1b, 0x4a, 0xac, 0x61, 0x81, 0x35, 0x04, 0xa6, 0x48, 0x5a, 0xc0,\n    0x53, 0x50, 0x80, 0xe3, 0xd4, 0xde, 0x27, 0xbb, 0xe4, 0xe3, 0x58, 0xca,\n    0xa4, 0x8c, 0xdc, 0x74, 0x5a, 0x4b, 0xc8, 0x33, 0x22, 0x62, 0x08, 0xdc,\n    0xd7, 0x21, 0x7f, 0x80, 0x4c, 0x71, 0xd7, 0x02, 0x5e, 0xc7, 0xfe, 0xb6,\n    0x2e, 0x62, 0x3b, 0x6a, 0x61, 0x03, 0x06, 0x42, 0xb7, 0x05, 0x02, 0x63,\n    0xf0, 0xc6, 0xba, 0x14, 0x3f, 0x37, 0x0c, 0x9f, 0x73, 0x4b, 0x34, 0x55,\n    0x2e, 0x07, 0x16, 0xd6, 0x9e, 0x07, 0xfe, 0xd3, 0x5b, 0xc4, 0x88, 0xdf,\n    0x96, 0xcd, 0x5a, 0x1c, 0x42, 0xb1, 0xe4, 0x16, 0xe0, 0x40, 0x51, 0xa8,\n    0x15, 0x03, 0xdd, 0xc8, 0x17, 0x59, 0xd1, 0x06, 0xa2, 0x8f, 0x79, 0xc4,\n    0x82, 0x81, 0xe1, 0xa2, 0xa8, 0xdb, 0x63, 0x4d, 0x93, 0x05, 0xcf, 0x43,\n    0x77, 0x34, 0x23, 0xa5, 0xb4, 0x9d, 0x85, 0x11, 0x95, 0xfc, 0x3c, 0x71,\n    0xd9, 0x15, 0xa8, 0xc3, 0xa0, 0xad, 0x49, 0xe8, 0xdb, 0xed, 0x72, 0x17,\n    0x72, 0x30, 0x36, 0x37, 0xb3, 0x08, 0xfa, 0xf7, 0x31, 0xfe, 0x34, 0x34,\n    0x8d, 0x2b, 0xbc, 0xf2, 0xda, 0x76, 0x69, 0x27, 0x15, 0x89, 0xe7, 0x3f,\n    0x7a, 0x47, 0xf9, 0x0b, 0x3a, 0xda, 0xee, 0x38, 0xed, 0xd0, 0x5c, 0xb2,\n    0xa1, 0x82, 0x89, 0xe7, 0x0d, 0x43, 0xc2, 0xf3, 0xa6, 0xb8, 0x9f, 0x40,\n    0x7f, 0xc3, 0xd7, 0x4c, 0x60, 0xd8, 0xb3, 0xe8, 0xba, 0xec, 0x93, 0x95,\n    0x32, 0x3e, 0xc5, 0x14, 0xd1, 0xf8, 0x47, 0xdf, 0x13, 0x69, 0x6f, 0xb6,\n    0xee, 0x37, 0x0e, 0xcb, 0xfd, 0xa8, 0x65, 0x06, 0x56, 0x8a, 0x47, 0x61,\n    0x72, 0xe1, 0x0a, 0x26, 0x8d, 0x73, 0xb8, 0x59, 0x1a, 0x13, 0x8f, 0x7d,\n    0x01, 0x92, 0x0e, 0xf0, 0x6c, 0x61, 0x7d, 0xf8, 0xea, 0xf5, 0xde, 0x91,\n    0xd9, 0x2b, 0x69, 0xa6, 0x77, 0x48, 0x0e, 0x3a, 0xd7, 0xb0, 0x14, 0x4a,\n    0xbb, 0xc0, 0x19, 0xe5, 0xfe, 0x81, 0xe3, 0x03, 0xb1, 0xab, 0x8e, 0x4e,\n    0x9a, 0xc7, 0xc5, 0x83, 0xe9, 0xc6, 0xb7, 0xba, 0x6b, 0x51, 0x8e, 0xd9,\n    0x0c, 0xdc, 0xde, 0x1a, 0xe5, 0xbd, 0xde, 0x93, 0xbf, 0xf8, 0xf3, 0xbf,\n    0xab, 0x63, 0xef, 0xa2, 0xe8, 0x4e, 0x62, 0x6a, 0x27, 0x15, 0xa3, 0x4d,\n    0xd8, 0xca, 0x47, 0x1e, 0x17, 0x7b, 0x96, 0xd9, 0x6f, 0xc9, 0xf4, 0x71,\n    0x03, 0xe9, 0xd6, 0xed, 0xb7, 0xc2, 0x24, 0x5e, 0x7a, 0x23, 0x1d, 0x40,\n    0xb2, 0xd7, 0x22, 0xdb, 0x5e, 0x99, 0x25, 0x1c, 0xac, 0x49, 0xc1, 0x96,\n    0x46, 0x58, 0x39, 0x46, 0xcd, 0x8c, 0xee, 0xc8, 0xd1, 0x18, 0xc0, 0xec,\n    0x66, 0x3c, 0xdd, 0x67, 0x49, 0x4e, 0xbf, 0x09, 0xc8, 0xe0, 0x1a, 0x7d,\n    0x98, 0x5e, 0x27, 0x83, 0x81, 0x15, 0xf0, 0x98, 0x4a, 0x18, 0x08, 0xfd\n};\n\nunsigned int encrypted_gcm_key_bin_len = 384;\n\nTEST_CASE(\"test_rsa_ds_decrypt_v15_padding\", \"[encrypted_img]\")\n{\n    esp_err_t err;\n    esp_decrypt_cfg_t cfg = {0};\n    esp_ds_data_ctx_t *ds_data = esp_secure_cert_get_ds_ctx();\n    if (ds_data == NULL) {\n        printf(\"Failed to get DS context\\n\");\n        vTaskDelete(NULL);\n    }\n    cfg.ds_data = ds_data;\n\n    // Prepare input data: magic + Encrypted GCM key + IV + Binary Size + Auth Tag + Reserved\n    size_t input_data_len = MAGIC_SIZE + ENC_GCM_KEY_SIZE;\n    uint8_t *input_data = (uint8_t *)malloc(input_data_len);\n    TEST_ASSERT_NOT_NULL(input_data);\n    uint32_t magic = 0x0788b6cf; // esp_enc_img_magic\n    memcpy(input_data, &magic, MAGIC_SIZE);\n    memcpy(input_data + MAGIC_SIZE, encrypted_gcm_key_bin, ENC_GCM_KEY_SIZE); // Encrypted GCM key\n\n    esp_decrypt_handle_t decrypt_ctx = esp_encrypted_img_decrypt_start(&cfg);\n    TEST_ASSERT_NOT_NULL(decrypt_ctx);\n\n    pre_enc_decrypt_arg_t *args = (pre_enc_decrypt_arg_t *)calloc(1, sizeof(pre_enc_decrypt_arg_t));\n    TEST_ASSERT_NOT_NULL(args);\n\n    args->data_in = (char *)input_data;\n    args->data_in_len = input_data_len;\n    args->data_out = NULL;\n    args->data_out_len = 0;\n\n    err = esp_encrypted_img_decrypt_data(decrypt_ctx, args);\n    TEST_ESP_ERR(ESP_ERR_NOT_FINISHED, err);\n\n    err = esp_encrypted_img_decrypt_abort(decrypt_ctx);\n    TEST_ASSERT_EQUAL(ESP_OK, err);\n    esp_secure_cert_free_ds_ctx(ds_data);\n    free(input_data);\n    free(args);\n}\n\n#endif // CONFIG_PRE_ENCRYPTED_OTA_USE_RSA && CONFIG_PRE_ENCRYPTED_RSA_USE_DS\n\nTEST_CASE(\"Sending all data at once\", \"[encrypted_img]\")\n{\n    esp_err_t err;\n\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n    esp_decrypt_cfg_t cfg = {0};\n#if defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    esp_ds_data_ctx_t *ds_data = esp_secure_cert_get_ds_ctx();\n    if (ds_data == NULL) {\n        printf(\"Failed to get DS context\\n\");\n        vTaskDelete(NULL);\n    }\n    cfg.ds_data = ds_data;\n#else\n    cfg.rsa_priv_key = (char *)rsa_private_pem_start;\n    cfg.rsa_priv_key_len = rsa_private_pem_end - rsa_private_pem_start;\n#endif /* CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n#else\n    esp_decrypt_cfg_t cfg = {0};\n    cfg.hmac_key_id = 2;\n#endif\n\n    esp_decrypt_handle_t ctx = esp_encrypted_img_decrypt_start(&cfg);\n    TEST_ASSERT_NOT_NULL(ctx);\n\n    pre_enc_decrypt_arg_t *args = calloc(1, sizeof(pre_enc_decrypt_arg_t));\n    TEST_ASSERT_NOT_NULL(args);\n\n    args->data_in = (char *)bin_start;\n    args->data_in_len = bin_end - bin_start;\n\n    err = esp_encrypted_img_decrypt_data(ctx, args);\n\n    TEST_ESP_OK(err);\n    printf(\"Successful\\n\");\n\n    err = esp_encrypted_img_decrypt_end(ctx);\n    TEST_ESP_OK(err);\n\n    if (args->data_out) {\n        free(args->data_out);\n    }\n\n#if defined (CONFIG_PRE_ENCRYPTED_OTA_USE_RSA) && defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    esp_secure_cert_free_ds_ctx(cfg.ds_data);\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_RSA && CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n\n    free(args);\n}\n\nTEST_CASE(\"Sending 1 byte data at once\", \"[encrypted_img]\")\n{\n    esp_err_t err;\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n    esp_decrypt_cfg_t cfg = {0};\n#if defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    esp_ds_data_ctx_t *ds_data = esp_secure_cert_get_ds_ctx();\n    if (ds_data == NULL) {\n        printf(\"Failed to get DS context\\n\");\n        vTaskDelete(NULL);\n    }\n    cfg.ds_data = ds_data;\n#else\n    cfg.rsa_priv_key = (char *)rsa_private_pem_start;\n    cfg.rsa_priv_key_len = rsa_private_pem_end - rsa_private_pem_start;\n#endif /* CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n#else\n    esp_decrypt_cfg_t cfg = {0};\n    cfg.hmac_key_id = 2;\n#endif\n    esp_decrypt_handle_t ctx = esp_encrypted_img_decrypt_start(&cfg);\n    TEST_ASSERT_NOT_NULL(ctx);\n\n    pre_enc_decrypt_arg_t *args = calloc(1, sizeof(pre_enc_decrypt_arg_t));\n    TEST_ASSERT_NOT_NULL(args);\n\n    int i = 0;\n    do {\n        args->data_in = (char *)(bin_start + i);\n        i++;\n        args->data_in_len = 1;\n        err = esp_encrypted_img_decrypt_data(ctx, args);\n        if (err == ESP_FAIL) {\n            printf(\"ESP_FAIL ERROR\\n\");\n            break;\n        }\n    } while (err != ESP_OK);\n    TEST_ESP_OK(err);\n\n    err = esp_encrypted_img_decrypt_end(ctx);\n    TEST_ESP_OK(err);\n    if (args->data_out) {\n        free(args->data_out);\n    }\n    free(args);\n#if defined (CONFIG_PRE_ENCRYPTED_OTA_USE_RSA) && defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    esp_secure_cert_free_ds_ctx(cfg.ds_data);\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_RSA && CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n}\n\nTEST_CASE(\"Invalid Magic\", \"[encrypted_img]\")\n{\n    static uint8_t cipher_invalid_magic[] = {\n        0x34, 0x12, 0xbc, 0xec, 0xe3, 0x02, 0x92, 0xb0, 0x3c, 0x3c, 0x37, 0x61,\n        0x99, 0x1b, 0x32, 0xeb, 0x28, 0x43, 0x92, 0x34, 0x8e, 0xb2, 0x98, 0x8e,\n        0xb4, 0x4a, 0xcb, 0xaa, 0xa9, 0x21, 0x6b, 0xc0, 0x52, 0xef, 0x4a, 0x2d,\n        0x93, 0xee, 0x9a, 0xec, 0x76, 0xf6, 0x18, 0xef, 0x7e, 0xb0, 0xaf, 0xdb,\n        0xae, 0x0e, 0x2b, 0x2c, 0xa5, 0x5c, 0x84, 0x8f, 0xef, 0x93, 0x68, 0xed,\n        0xff, 0xfa, 0x0a, 0xbb, 0xb7, 0x0b, 0xd0, 0x9b, 0x6b, 0xba, 0xf1, 0xf3,\n        0x69, 0xb7, 0xe1, 0x8b, 0x94, 0x61, 0x60, 0x96, 0x20, 0xe7, 0xaf, 0x6a,\n        0x7c, 0xca, 0x4a, 0xab, 0xab, 0x8f, 0x6a, 0x77, 0xaa, 0xf8, 0x9e, 0x6d,\n        0xc8, 0x70, 0x6f, 0xae, 0x66, 0xd2, 0x50, 0xb1, 0xef, 0x97, 0xd5, 0xd3,\n        0xc9, 0x9d, 0x14, 0x80, 0x1b, 0xa8, 0xb7, 0xc7, 0xaa, 0x88, 0xa4, 0x29,\n        0xd6, 0x64, 0xe9, 0xb9, 0x8f, 0x88, 0xca, 0xa9, 0x28, 0x64, 0x54, 0xe5,\n        0x6e, 0xdf, 0xef, 0xab, 0xdd, 0x1f, 0xbe, 0xa7, 0xfc, 0x34, 0x12, 0xf5,\n        0xea, 0x09, 0x7c, 0x36, 0xe9, 0x13, 0xf8, 0xb4, 0x37, 0xa4, 0x4d, 0x8d,\n        0xf4, 0x8a, 0xd8, 0xfa, 0x67, 0x42, 0x37, 0x93, 0xe6, 0x70, 0x1c, 0x59,\n        0x91, 0x98, 0xf5, 0x4e, 0xfc, 0xde, 0x05, 0x4f, 0xa8, 0x46, 0x68, 0xf9,\n        0xed, 0x1a, 0x8a, 0x52, 0xc9, 0xdb, 0xe1, 0x00, 0x48, 0x66, 0xf5, 0xb0,\n        0xae, 0x27, 0x28, 0x57, 0xd2, 0xfd, 0xbb, 0xf2, 0x80, 0xf7, 0xe4, 0x01,\n        0x28, 0xc6, 0xc9, 0x12, 0x60, 0xce, 0xc1, 0x1f, 0x4a, 0x0b, 0x2f, 0x02,\n        0x44, 0xf5, 0x41, 0x19, 0x7e, 0xb4, 0xe6, 0x4a, 0x58, 0x7a, 0x2b, 0xf9,\n        0xe3, 0x29, 0x62, 0xad, 0x61, 0x6e, 0x27, 0xea, 0x07, 0x60, 0x3f, 0x83,\n        0x05, 0x59, 0x6c, 0xbd, 0x6e, 0xc8, 0x97, 0xeb, 0x2e, 0x6a, 0x7c, 0x2e,\n        0x3c, 0x82, 0xbf, 0xaf, 0x2f, 0xd0, 0x0a, 0x6a, 0xbf, 0x24, 0xc5, 0x2b,\n        0xe3, 0x8a, 0x00, 0x6c, 0x04, 0xd8, 0xb2, 0x63, 0xca, 0x96, 0x64, 0xd2,\n        0xf5, 0x86, 0xb9, 0xc6, 0xcd, 0x2f, 0xd5, 0x97, 0xd8, 0x3f, 0xaf, 0x80,\n        0x66, 0x72, 0x8f, 0x60, 0xa8, 0x3a, 0xdd, 0x48, 0x01, 0xbc, 0xc1, 0xcb,\n        0x8d, 0x18, 0xc9, 0x6f, 0x83, 0x4c, 0xda, 0xb5, 0xa1, 0xcd, 0x99, 0xb1,\n        0xa4, 0x9d, 0xef, 0xa7, 0xed, 0xaf, 0xdd, 0xfd, 0xc7, 0x08, 0xc4, 0xcd,\n        0xf7, 0x5a, 0xda, 0x3b, 0x92, 0xcd, 0xcf, 0xe1, 0xe8, 0x7a, 0x6b, 0xe2,\n        0x24, 0x97, 0x6f, 0xd3, 0x40, 0xcf, 0x7d, 0xaf, 0x9b, 0xf1, 0xf2, 0xa2,\n        0xcd, 0x8d, 0xe8, 0x4b, 0xe6, 0x89, 0xb0, 0x76, 0x1a, 0xc6, 0xe5, 0x63,\n        0x59, 0x1f, 0x6a, 0xa8, 0x22, 0xe8, 0x04, 0x97, 0xca, 0xdd, 0x3d, 0x6e,\n        0xd1, 0x28, 0x71, 0x4b, 0x9e, 0xb6, 0xe0, 0xa7, 0xbe, 0x35, 0x7b, 0x35,\n        0xdc, 0xb2, 0x26, 0x0f, 0xdc, 0x35, 0xb5, 0xea, 0xa1, 0x6c, 0x7d, 0xbd,\n        0x49, 0x27, 0x58, 0xcb, 0x70, 0x16, 0x66, 0x26, 0x0a, 0x00, 0x00, 0x00,\n        0xfa, 0x7c, 0x1b, 0xc3, 0xb8, 0x1f, 0xf5, 0x7d, 0xab, 0xd4, 0x16, 0xfc,\n        0xd7, 0x9b, 0x45, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x5d, 0x8c, 0x97,\n        0x1f, 0xd4, 0x77, 0xf7, 0xbb, 0x31\n    };\n\n    esp_err_t err;\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n    esp_decrypt_cfg_t cfg = {0};\n#if defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    esp_ds_data_ctx_t *ds_data = esp_secure_cert_get_ds_ctx();\n    if (ds_data == NULL) {\n        printf(\"Failed to get DS context\\n\");\n        vTaskDelete(NULL);\n    }\n    cfg.ds_data = ds_data;\n#else\n    cfg.rsa_priv_key = (char *)rsa_private_pem_start;\n    cfg.rsa_priv_key_len = rsa_private_pem_end - rsa_private_pem_start;\n#endif /* CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n#else\n    esp_decrypt_cfg_t cfg = {0};\n    cfg.hmac_key_id = 2;\n#endif\n    esp_decrypt_handle_t ctx = esp_encrypted_img_decrypt_start(&cfg);\n    TEST_ASSERT_NOT_NULL(ctx);\n\n    pre_enc_decrypt_arg_t *args = calloc(1, sizeof(pre_enc_decrypt_arg_t));\n    TEST_ASSERT_NOT_NULL(args);\n\n    args->data_in = (char *)cipher_invalid_magic;\n    args->data_in_len = sizeof(cipher_invalid_magic);\n\n    err = esp_encrypted_img_decrypt_data(ctx, args);\n    TEST_ESP_ERR(ESP_FAIL, err);\n\n    err = esp_encrypted_img_decrypt_end(ctx);\n    free(args);\n#if defined (CONFIG_PRE_ENCRYPTED_OTA_USE_RSA) && defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    esp_secure_cert_free_ds_ctx(cfg.ds_data);\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_RSA && CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n}\n\nTEST_CASE(\"Invalid Image\", \"[encrypted_img]\")\n{\n    //\"Espressif\" is encoded using GCM key. After successful decoding, \"Espressif\" will be printed.\n    static uint8_t cipher_invalid_image[] = {\n        0xcf, 0xb6, 0x88, 0x07, 0xe3, 0x02, 0x92, 0xb0, 0x3c, 0x3c, 0x37, 0x61,\n        0x99, 0x1b, 0x32, 0xeb, 0x28, 0x43, 0x92, 0x34, 0x8e, 0xb2, 0x98, 0x8e,\n        0xb4, 0x4a, 0xcb, 0xaa, 0xa9, 0x21, 0x6b, 0xc0, 0x52, 0xef, 0x4a, 0x2d,\n        0x93, 0xee, 0x9a, 0xec, 0x76, 0xf6, 0x18, 0xef, 0x7e, 0xb0, 0xaf, 0xdb,\n        0xae, 0x0e, 0x2b, 0x2c, 0xa5, 0x5c, 0x84, 0x8f, 0xef, 0x93, 0x68, 0xed,\n        0xff, 0xfa, 0x0a, 0xbb, 0xb7, 0x0b, 0xd0, 0x9b, 0x6b, 0xba, 0xf1, 0xf3,\n        0x69, 0xb7, 0xe1, 0x8b, 0x94, 0x61, 0x60, 0x96, 0x20, 0xe7, 0xaf, 0x6a,\n        0x7c, 0xca, 0x4a, 0xab, 0xab, 0x8f, 0x6a, 0x77, 0xaa, 0xf8, 0x9e, 0x6d,\n        0xc8, 0x70, 0x6f, 0xae, 0x66, 0xd2, 0x50, 0xb1, 0xef, 0x97, 0xd5, 0xd3,\n        0xc9, 0x9d, 0x14, 0x80, 0x1b, 0xa8, 0xb7, 0xc7, 0xaa, 0x88, 0xa4, 0x29,\n        0xd6, 0x64, 0xe9, 0xb9, 0x8f, 0x88, 0xca, 0xa9, 0x28, 0x64, 0x54, 0xe5,\n        0x6e, 0xdf, 0xef, 0xab, 0xdd, 0x1f, 0xbe, 0xa7, 0xfc, 0x34, 0x12, 0xf5,\n        0xea, 0x09, 0x7c, 0x36, 0xe9, 0x13, 0xf8, 0xb4, 0x37, 0xa4, 0x4d, 0x8d,\n        0xf4, 0x8a, 0xd8, 0xfa, 0x67, 0x42, 0x37, 0x93, 0xe6, 0x70, 0x1c, 0x59,\n        0x91, 0x98, 0xf5, 0x4e, 0xfc, 0xde, 0x05, 0x4f, 0xa8, 0x46, 0x68, 0xf9,\n        0xed, 0x1a, 0x8a, 0x52, 0xc9, 0xdb, 0xe1, 0x00, 0x48, 0x66, 0xf5, 0xb0,\n        0xae, 0x27, 0x28, 0x57, 0xd2, 0xfd, 0xbb, 0xf2, 0x80, 0xf7, 0xe4, 0x01,\n        0x28, 0xc6, 0xc9, 0x12, 0x60, 0xce, 0xc1, 0x1f, 0x4a, 0x0b, 0x2f, 0x02,\n        0x44, 0xf5, 0x41, 0x19, 0x7e, 0xb4, 0xe6, 0x4a, 0x58, 0x7a, 0x2b, 0xf9,\n        0xe3, 0x29, 0x62, 0xad, 0x61, 0x6e, 0x27, 0xea, 0x07, 0x60, 0x3f, 0x83,\n        0x05, 0x59, 0x6c, 0xbd, 0x6e, 0xc8, 0x97, 0xeb, 0x2e, 0x6a, 0x7c, 0x2e,\n        0x3c, 0x82, 0xbf, 0xaf, 0x2f, 0xd0, 0x0a, 0x6a, 0xbf, 0x24, 0xc5, 0x2b,\n        0xe3, 0x8a, 0x00, 0x6c, 0x04, 0xd8, 0xb2, 0x63, 0xca, 0x96, 0x64, 0xd2,\n        0xf5, 0x86, 0xb9, 0xc6, 0xcd, 0x2f, 0xd5, 0x97, 0xd8, 0x3f, 0xaf, 0x80,\n        0x66, 0x72, 0x8f, 0x60, 0xa8, 0x3a, 0xdd, 0x48, 0x01, 0xbc, 0xc1, 0xcb,\n        0x8d, 0x18, 0xc9, 0x6f, 0x83, 0x4c, 0xda, 0xb5, 0xa1, 0xcd, 0x99, 0xb1,\n        0xa4, 0x9d, 0xef, 0xa7, 0xed, 0xaf, 0xdd, 0xfd, 0xc7, 0x08, 0xc4, 0xcd,\n        0xf7, 0x5a, 0xda, 0x3b, 0x92, 0xcd, 0xcf, 0xe1, 0xe8, 0x7a, 0x6b, 0xe2,\n        0x24, 0x97, 0x6f, 0xd3, 0x40, 0xcf, 0x7d, 0xaf, 0x9b, 0xf1, 0xf2, 0xa2,\n        0xcd, 0x8d, 0xe8, 0x4b, 0xe6, 0x89, 0xb0, 0x76, 0x1a, 0xc6, 0xe5, 0x63,\n        0x59, 0x1f, 0x6a, 0xa1, 0x22, 0xe8, 0x04, 0x97, 0xca, 0xdd, 0x3d, 0x6e,\n        0xd1, 0x28, 0x71, 0x4b, 0x92, 0xb6, 0xe0, 0xa7, 0xbe, 0x35, 0x7b, 0x35,\n        0xdc, 0xb2, 0x26, 0x0f, 0xdc, 0x35, 0xb5, 0xea, 0xa1, 0x6c, 0x7d, 0xbd,\n        0x49, 0x27, 0x58, 0xcb, 0x70, 0x16, 0x66, 0x26, 0x0a, 0x00, 0x00, 0x00,\n        0xfa, 0x7c, 0x1b, 0xc3, 0xb8, 0x1f, 0xf5, 0x7d, 0xab, 0xd4, 0x16, 0xfc,\n        0xd7, 0x9b, 0x35, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x5d, 0x8c, 0x97,\n        0x1f, 0xd4, 0x77, 0xf7, 0xbb, 0x31\n    };\n\n    esp_err_t err;\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n    esp_decrypt_cfg_t cfg = {0};\n#if defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    esp_ds_data_ctx_t *ds_data = esp_secure_cert_get_ds_ctx();\n    if (ds_data == NULL) {\n        printf(\"Failed to get DS context\\n\");\n        vTaskDelete(NULL);\n    }\n    cfg.ds_data = ds_data;\n#else\n    cfg.rsa_priv_key = (char *)rsa_private_pem_start;\n    cfg.rsa_priv_key_len = rsa_private_pem_end - rsa_private_pem_start;\n#endif /* CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n#else\n    esp_decrypt_cfg_t cfg = {0};\n    cfg.hmac_key_id = 2;\n#endif\n    esp_decrypt_handle_t ctx = esp_encrypted_img_decrypt_start(&cfg);\n    TEST_ASSERT_NOT_NULL(ctx);\n\n    pre_enc_decrypt_arg_t *args = calloc(1, sizeof(pre_enc_decrypt_arg_t));\n    TEST_ASSERT_NOT_NULL(args);\n\n    args->data_in = (char *)cipher_invalid_image;\n    args->data_in_len = sizeof(cipher_invalid_image);\n\n    err = esp_encrypted_img_decrypt_data(ctx, args);\n    TEST_ESP_ERR(ESP_FAIL, err);\n\n    err = esp_encrypted_img_decrypt_end(ctx);\n    TEST_ESP_ERR(ESP_FAIL, err);\n    if (args->data_out) {\n        free(args->data_out);\n    }\n    free(args);\n#if defined (CONFIG_PRE_ENCRYPTED_OTA_USE_RSA) && defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    esp_secure_cert_free_ds_ctx(cfg.ds_data);\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_RSA && CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n}\n\nTEST_CASE(\"Sending random size data at once\", \"[encrypted_img]\")\n{\n    esp_err_t err;\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n    esp_decrypt_cfg_t cfg = {0};\n#if defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    esp_ds_data_ctx_t *ds_data = esp_secure_cert_get_ds_ctx();\n    if (ds_data == NULL) {\n        printf(\"Failed to get DS context\\n\");\n        vTaskDelete(NULL);\n    }\n    cfg.ds_data = ds_data;\n#else\n    cfg.rsa_priv_key = (char *)rsa_private_pem_start;\n    cfg.rsa_priv_key_len = rsa_private_pem_end - rsa_private_pem_start;\n#endif /* CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n#else\n    esp_decrypt_cfg_t cfg = {0};\n    cfg.hmac_key_id = 2;\n#endif\n    esp_decrypt_handle_t ctx = esp_encrypted_img_decrypt_start(&cfg);\n    TEST_ASSERT_NOT_NULL(ctx);\n\n    pre_enc_decrypt_arg_t *args = calloc(1, sizeof(pre_enc_decrypt_arg_t));\n    TEST_ASSERT_NOT_NULL(args);\n\n    int i = 0;\n    do {\n        uint32_t y = esp_random();\n        y = (y % 16) + 1;\n        uint32_t x = y < ((bin_end - bin_start) - i) ? y : ((bin_end - bin_start) - i);\n        args->data_in = (char *)(bin_start + i);\n        i += x;\n        args->data_in_len = x;\n        err = esp_encrypted_img_decrypt_data(ctx, args);\n        if (err == ESP_FAIL) {\n            printf(\"ESP_FAIL ERROR\\n\");\n            break;\n        }\n    } while (err != ESP_OK);\n\n    TEST_ESP_OK(err);\n\n    err = esp_encrypted_img_decrypt_end(ctx);\n    TEST_ESP_OK(err);\n    if (args->data_out) {\n        free(args->data_out);\n    }\n    free(args);\n#if defined (CONFIG_PRE_ENCRYPTED_OTA_USE_RSA) && defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    esp_secure_cert_free_ds_ctx(cfg.ds_data);\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_RSA && CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n}\n\nTEST_CASE(\"Sending incomplete data\", \"[encrypted_img]\")\n{\n    esp_err_t err;\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n    esp_decrypt_cfg_t cfg = {0};\n#if defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    esp_ds_data_ctx_t *ds_data = esp_secure_cert_get_ds_ctx();\n    if (ds_data == NULL) {\n        printf(\"Failed to get DS context\\n\");\n        vTaskDelete(NULL);\n    }\n    cfg.ds_data = ds_data;\n#else\n    cfg.rsa_priv_key = (char *)rsa_private_pem_start;\n    cfg.rsa_priv_key_len = rsa_private_pem_end - rsa_private_pem_start;\n#endif /* CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n#else\n    esp_decrypt_cfg_t cfg = {0};\n    cfg.hmac_key_id = 2;\n#endif\n    esp_decrypt_handle_t ctx = esp_encrypted_img_decrypt_start(&cfg);\n    TEST_ASSERT_NOT_NULL(ctx);\n\n    pre_enc_decrypt_arg_t *args = calloc(1, sizeof(pre_enc_decrypt_arg_t));\n    TEST_ASSERT_NOT_NULL(args);\n\n    args->data_in = (char *)bin_start;\n    args->data_in_len = (bin_end - bin_start) - 1;\n\n    err = esp_encrypted_img_decrypt_data(ctx, args);\n    TEST_ESP_ERR(ESP_ERR_NOT_FINISHED, err);\n\n    TEST_ESP_ERR(false, esp_encrypted_img_is_complete_data_received(ctx));\n\n    err = esp_encrypted_img_decrypt_abort(ctx);\n    TEST_ESP_OK(err);\n    if (args->data_out) {\n        free(args->data_out);\n    }\n    free(args);\n#if defined (CONFIG_PRE_ENCRYPTED_OTA_USE_RSA) && defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    esp_secure_cert_free_ds_ctx(cfg.ds_data);\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_RSA && CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n}\n\nTEST_CASE(\"Test canceling decryption frees memory\", \"[encrypted_img]\")\n{\n    esp_err_t err;\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n    esp_decrypt_cfg_t cfg = {0};\n#if defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    esp_ds_data_ctx_t *ds_data = esp_secure_cert_get_ds_ctx();\n    if (ds_data == NULL) {\n        printf(\"Failed to get DS context\\n\");\n        vTaskDelete(NULL);\n    }\n    cfg.ds_data = ds_data;\n#else\n    cfg.rsa_priv_key = (char *)rsa_private_pem_start;\n    cfg.rsa_priv_key_len = rsa_private_pem_end - rsa_private_pem_start;\n#endif /* CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n#else\n    esp_decrypt_cfg_t cfg = {0};\n    cfg.hmac_key_id = 2;\n#endif\n    int free_bytes_start = xPortGetFreeHeapSize();\n    esp_decrypt_handle_t ctx = esp_encrypted_img_decrypt_start(&cfg);\n    TEST_ASSERT_NOT_NULL(ctx);\n\n    err = esp_encrypted_img_decrypt_abort(ctx);\n    TEST_ESP_OK(err);\n    int free_bytes_end = xPortGetFreeHeapSize();\n\n    // +/- 16 bytes to allow for some small fluctuations\n    TEST_ASSERT(abs(free_bytes_start - free_bytes_end) <= 16);\n#if defined (CONFIG_PRE_ENCRYPTED_OTA_USE_RSA) && defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    esp_secure_cert_free_ds_ctx(cfg.ds_data);\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_RSA && CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n}\n\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\n\nuint8_t server_pub[SERVER_ECC_KEY_LEN] = {\n    0x6b, 0x1e, 0xda, 0x43, 0xaf, 0xc4, 0x1d, 0x44, 0x28, 0x44, 0x5f, 0x06, 0x12, 0x07, 0xe3, 0x85,\n    0x8b, 0x93, 0x0d, 0x48, 0x09, 0xc3, 0xf2, 0x33, 0x3c, 0x04, 0x26, 0x64, 0xd6, 0x14, 0x1c, 0x62,\n    0x24, 0xd2, 0xf5, 0xc8, 0x2e, 0x10, 0x7c, 0xb5, 0x16, 0x2b, 0x4c, 0xd1, 0xa0, 0x1c, 0x93, 0xe4,\n    0x48, 0x2a, 0x03, 0x5d, 0x5e, 0x98, 0xb2, 0x82, 0xf6, 0x85, 0x70, 0x2a, 0x5e, 0x92, 0xd3, 0x6a,\n};\n\nuint8_t kdf_salt[KDF_SALT_SIZE] = {\n    0x1e, 0x74, 0x5d, 0xe2, 0x86, 0x03, 0x3f, 0x03, 0x73, 0x15, 0x80, 0xcb, 0x6e, 0xe1, 0x37, 0xaa,\n    0x1b, 0x4c, 0x2f, 0x8d, 0x3e, 0x5a, 0x6f, 0x7b, 0x9c, 0x8d, 0x4e, 0x2b, 0x1a, 0x3f, 0xd5, 0xe7\n};\n\nTEST_CASE(\"test_invalid_hmac_key\", \"[encrypted_img]\")\n{\n    // --- Test Setup ---\n    esp_decrypt_cfg_t cfg = {0};\n    cfg.hmac_key_id = -1; // Invalid HMAC key\n    esp_decrypt_handle_t decrypt_ctx = esp_encrypted_img_decrypt_start(&cfg);\n    TEST_ASSERT_NULL(decrypt_ctx);\n\n    cfg.hmac_key_id = HMAC_KEY_MAX + 1; // Invalid HMAC key\n    decrypt_ctx = esp_encrypted_img_decrypt_start(&cfg);\n    TEST_ASSERT_NULL(decrypt_ctx);\n\n    cfg.hmac_key_id = 1; // Invalid HMAC key\n    decrypt_ctx = esp_encrypted_img_decrypt_start(&cfg);\n    TEST_ASSERT_NULL(decrypt_ctx);\n}\n\nTEST_CASE(\"test_ecc_key_derivation\", \"[encrypted_img]\")\n{\n    // --- Test Setup ---\n    esp_decrypt_cfg_t cfg = {0};\n    cfg.hmac_key_id = 2;\n    esp_decrypt_handle_t decrypt_ctx = esp_encrypted_img_decrypt_start(&cfg);\n    TEST_ASSERT_NOT_NULL(decrypt_ctx);\n\n    pre_enc_decrypt_arg_t *args = (pre_enc_decrypt_arg_t *)calloc(1, sizeof(pre_enc_decrypt_arg_t));\n    TEST_ASSERT_NOT_NULL(args);\n\n    // Prepare input data: magic + ECC header (server_pub_key + kdf_salt_from_header + reserved)\n    size_t input_data_len = MAGIC_SIZE + SERVER_ECC_KEY_LEN + KDF_SALT_SIZE + RESERVED_SIZE;\n    uint8_t *input_data = (uint8_t *)malloc(input_data_len);\n    TEST_ASSERT_NOT_NULL(input_data);\n\n    uint32_t magic = 0x0788b6cf; // esp_enc_img_magic\n    memcpy(input_data, &magic, MAGIC_SIZE);\n    memcpy(input_data + MAGIC_SIZE, server_pub, SERVER_ECC_KEY_LEN); // Dummy server_pub_key from header\n    memcpy(input_data + MAGIC_SIZE + SERVER_ECC_KEY_LEN, kdf_salt, KDF_SALT_SIZE); // Dummy kdf_salt from header\n    memset(input_data + MAGIC_SIZE + SERVER_ECC_KEY_LEN + KDF_SALT_SIZE, 0x00, RESERVED_SIZE); // Dummy reserved data\n\n    args->data_in = (char *)input_data;\n    args->data_in_len = input_data_len;\n    args->data_out = NULL;\n    args->data_out_len = 0;\n\n    // --- Execute ---\n    // This call will trigger reading magic, then ECC header.\n    // derive_gcm_key -> derive_ota_ecc_device_key -> compute_ecc_key_with_hmac -> esp_encrypted_img_pbkdf2_hmac_sha256\n    esp_err_t err = esp_encrypted_img_decrypt_data(decrypt_ctx, args);\n\n    // --- Assert ---\n    // After processing the header, it expects more data (IV, etc.), so it should return ESP_ERR_NOT_FINISHED.\n    TEST_ESP_ERR(ESP_ERR_NOT_FINISHED, err);\n\n    esp_encrypted_img_decrypt_abort(decrypt_ctx); // Use abort as we didn't provide full data\n    free(input_data);\n    if (args->data_out) {\n        free(args->data_out);\n    }\n    free(args);\n}\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES */\n\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\nunsigned char rsa_pub_der[] = {\n    0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xf5, 0xea, 0x28,\n    0x86, 0xaa, 0x25, 0xa3, 0x0d, 0xb3, 0xe8, 0x9b, 0x2e, 0x06, 0xfa, 0x8b,\n    0x2c, 0xff, 0xa3, 0x7c, 0x0f, 0xe1, 0x6b, 0xcb, 0x74, 0xde, 0xc9, 0x11,\n    0xd0, 0x5e, 0x1c, 0x28, 0xc5, 0xcd, 0x16, 0x87, 0x36, 0x41, 0xba, 0x9d,\n    0x62, 0x34, 0x41, 0x68, 0x53, 0xab, 0x92, 0x85, 0x03, 0xfc, 0xa0, 0xb6,\n    0x4f, 0x3b, 0xc2, 0x8d, 0x4d, 0xce, 0x67, 0x7c, 0x2e, 0x18, 0x30, 0xe3,\n    0x15, 0x65, 0x11, 0xb1, 0xec, 0xd4, 0x79, 0x80, 0x87, 0xfa, 0xbe, 0x0f,\n    0x70, 0x5f, 0xea, 0x13, 0xab, 0xd7, 0x5b, 0x59, 0x15, 0xb9, 0xe1, 0x39,\n    0x8c, 0x89, 0x93, 0xb7, 0x14, 0xac, 0x9e, 0xdd, 0x47, 0x2c, 0x50, 0x06,\n    0x89, 0x49, 0xc8, 0x2d, 0x42, 0x7b, 0xc6, 0x2d, 0xdc, 0x77, 0xce, 0x98,\n    0xf2, 0x61, 0x74, 0x54, 0x7d, 0xb0, 0x7e, 0x60, 0xca, 0xa3, 0xc1, 0x12,\n    0x05, 0x16, 0xde, 0xbf, 0x47, 0x82, 0x84, 0x22, 0x40, 0xc5, 0xdc, 0xa7,\n    0xba, 0xec, 0xa8, 0xd2, 0x6f, 0x88, 0x37, 0xda, 0xfb, 0x70, 0xd4, 0xad,\n    0x08, 0xac, 0xf7, 0x8e, 0x09, 0x62, 0xa6, 0x39, 0xc8, 0xe7, 0xe3, 0xb1,\n    0xb4, 0x98, 0x30, 0xff, 0x47, 0xcc, 0x68, 0x27, 0xe3, 0xb6, 0x7e, 0xca,\n    0x20, 0x59, 0x2d, 0x18, 0x47, 0x97, 0xa8, 0x9d, 0x6b, 0xb9, 0x10, 0x40,\n    0x2c, 0xdf, 0xa2, 0xef, 0x4c, 0xd9, 0x8e, 0x30, 0xed, 0x26, 0x3d, 0xfb,\n    0x14, 0xbe, 0x6d, 0xe0, 0xb0, 0xa0, 0xae, 0x42, 0x26, 0xc0, 0xba, 0x41,\n    0x00, 0xb5, 0x58, 0x15, 0x7c, 0xb5, 0xc1, 0x78, 0x4c, 0x5e, 0xae, 0xe1,\n    0xe5, 0xc5, 0x36, 0x11, 0xce, 0x9b, 0x45, 0x50, 0x65, 0xe8, 0x61, 0xf5,\n    0xc7, 0x1d, 0xa5, 0x00, 0x14, 0x35, 0x2d, 0x51, 0x70, 0xae, 0x29, 0x60,\n    0x92, 0x52, 0xe3, 0x63, 0x95, 0x13, 0x77, 0x1f, 0x06, 0x1c, 0x4f, 0xef,\n    0x79, 0x1e, 0x12, 0x95, 0xad, 0xdd, 0x63, 0x21, 0x39, 0x30, 0xa2, 0xc9,\n    0xdc, 0xa9, 0x9c, 0xec, 0xdc, 0x65, 0x3e, 0x55, 0xa7, 0x59, 0x39, 0x94,\n    0x28, 0x05, 0x98, 0x20, 0x98, 0x91, 0x23, 0x00, 0x47, 0x48, 0x19, 0xed,\n    0x52, 0x01, 0xb2, 0x05, 0x80, 0x6a, 0xcd, 0xf0, 0x52, 0x60, 0x55, 0x8b,\n    0xde, 0x09, 0x93, 0x9a, 0xf5, 0x7f, 0x25, 0x0e, 0x35, 0x95, 0xa5, 0xfb,\n    0xab, 0x29, 0x1d, 0x69, 0xbb, 0xe0, 0x74, 0x64, 0x91, 0x2c, 0x91, 0x7a,\n    0xc1, 0x93, 0x1d, 0xa4, 0x9a, 0x6f, 0x69, 0xf6, 0x03, 0x05, 0x1c, 0x15,\n    0xee, 0x9b, 0x2f, 0x84, 0xf9, 0x07, 0x11, 0x70, 0x54, 0x49, 0xed, 0x9d,\n    0xb5, 0xf5, 0x8a, 0x4a, 0xd8, 0x94, 0x3d, 0x3e, 0xe0, 0x71, 0x91, 0x35,\n    0x20, 0x23, 0x31, 0x4f, 0x6e, 0x90, 0x95, 0xa7, 0xfd, 0x4f, 0x61, 0xaf,\n    0x63, 0x0c, 0xaa, 0xe1, 0x60, 0x64, 0x12, 0x7b, 0x73, 0x02, 0x03, 0x01,\n    0x00, 0x01\n};\nunsigned int rsa_pub_der_len = 398;\n#else\nuint8_t ecies_public_key[] = {\n    0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,\n    0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,\n    0x42, 0x00, 0x04, 0x6d, 0x45, 0xfd, 0xc5, 0xdf, 0xc8, 0x83, 0x30, 0x7e,\n    0x28, 0x0b, 0x5a, 0xb1, 0x2b, 0x3d, 0x10, 0x30, 0x0f, 0x30, 0xb6, 0x3a,\n    0xca, 0x4a, 0x0e, 0x0f, 0x78, 0x43, 0xb9, 0xd0, 0x46, 0xb9, 0x4e, 0x2e,\n    0x57, 0xf4, 0x4b, 0xc9, 0x69, 0x79, 0x8a, 0x63, 0x9a, 0x9e, 0x7f, 0x4c,\n    0x64, 0x1b, 0xcc, 0x73, 0xe1, 0xaa, 0xfb, 0xeb, 0x3e, 0xce, 0x5b, 0x45,\n    0x7a, 0xef, 0xdb, 0xc5, 0xc8, 0x61, 0xbe\n};\nsize_t ecies_public_key_len = sizeof(ecies_public_key);\n#endif // CONFIG_PRE_ENCRYPTED_OTA_USE_RSA\n\nTEST_CASE(\"Test getting public key NULL\", \"[encrypted_img]\")\n{\n#ifdef CONFIG_HEAP_TRACING\n    heap_trace_init_standalone(trace_record, NUM_RECORDS);\n    heap_trace_start(HEAP_TRACE_LEAKS);\n#endif\n    size_t pub_key_len = 0;\n    // We have not started decryption yet, so public key should be NULL\n    uint8_t *pub_key = NULL;\n    esp_err_t err = esp_encrypted_img_export_public_key(NULL, NULL, &pub_key_len);\n    TEST_ASSERT_NULL(pub_key);\n    TEST_ESP_ERR(ESP_ERR_INVALID_ARG, err);\n\n    err = esp_encrypted_img_export_public_key(NULL, &pub_key, NULL);\n    TEST_ASSERT_NULL(pub_key);\n    TEST_ESP_ERR(ESP_ERR_INVALID_ARG, err);\n\n    err = esp_encrypted_img_export_public_key(NULL, NULL, NULL);\n    TEST_ASSERT_NULL(pub_key);\n    TEST_ESP_ERR(ESP_ERR_INVALID_ARG, err);\n#ifdef CONFIG_HEAP_TRACING\n    heap_trace_stop();\n    heap_trace_dump();\n#endif\n}\n\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\nTEST_CASE(\"Test getting public key wrong hmac id\", \"[encrypted_img]\")\n{\n#ifdef CONFIG_HEAP_TRACING\n    heap_trace_init_standalone(trace_record, NUM_RECORDS);\n    heap_trace_start(HEAP_TRACE_LEAKS);\n#endif\n    esp_decrypt_cfg_t cfg = {0};\n    cfg.hmac_key_id = 1;\n\n    size_t pub_key_len = 0;\n    // We have not started decryption yet, so public key should be NULL\n    uint8_t *pub_key = NULL;\n    esp_err_t err = esp_encrypted_img_export_public_key(NULL, &pub_key, &pub_key_len);\n    TEST_ASSERT_NULL(pub_key);\n    TEST_ESP_ERR(ESP_ERR_INVALID_ARG, err);\n\n    esp_decrypt_handle_t ctx = esp_encrypted_img_decrypt_start(&cfg);\n    TEST_ASSERT_NULL(ctx);\n\n    err = esp_encrypted_img_export_public_key(ctx, &pub_key, &pub_key_len);\n    TEST_ASSERT_NULL(pub_key);\n    TEST_ESP_ERR(ESP_ERR_INVALID_ARG, err);\n#ifdef CONFIG_HEAP_TRACING\n    heap_trace_stop();\n    heap_trace_dump();\n#endif\n}\n#endif // CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES\n\nTEST_CASE(\"Test getting public key\", \"[encrypted_img]\")\n{\n#ifdef CONFIG_HEAP_TRACING\n    heap_trace_init_standalone(trace_record, NUM_RECORDS);\n    heap_trace_start(HEAP_TRACE_LEAKS);\n#endif\n    esp_decrypt_cfg_t cfg = {0};\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n#if defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    esp_ds_data_ctx_t *ds_data = esp_secure_cert_get_ds_ctx();\n    if (ds_data == NULL) {\n        printf(\"Failed to get DS context\\n\");\n        vTaskDelete(NULL);\n    }\n    cfg.ds_data = ds_data;\n#else\n    cfg.rsa_priv_key = (char *)rsa_private_pem_start;\n    cfg.rsa_priv_key_len = rsa_private_pem_end - rsa_private_pem_start;\n#endif /* CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n#else\n    cfg.hmac_key_id = 2;\n#endif\n    size_t pub_key_len = 0;\n    // We have not started decryption yet, so public key should be NULL\n    uint8_t *pub_key = NULL;\n    esp_err_t err = esp_encrypted_img_export_public_key(NULL, &pub_key, &pub_key_len);\n    TEST_ASSERT_NULL(pub_key);\n    TEST_ESP_ERR(ESP_ERR_INVALID_ARG, err);\n    // Start decryption to get the public key\n    esp_decrypt_handle_t ctx = esp_encrypted_img_decrypt_start(&cfg);\n    TEST_ASSERT_NOT_NULL(ctx);\n\n    err = esp_encrypted_img_export_public_key(ctx, &pub_key, &pub_key_len);\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_RSA)\n#if defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, err);\n    TEST_ASSERT_NULL(pub_key);\n    TEST_ASSERT(pub_key_len == 0);\n#else\n    TEST_ESP_ERR(ESP_OK, err);\n    TEST_ASSERT_NOT_NULL(pub_key);\n    TEST_ASSERT(pub_key_len > 0);\n    TEST_ASSERT_EQUAL(rsa_pub_der_len, pub_key_len);\n    TEST_ASSERT_EQUAL_MEMORY(rsa_pub_der, pub_key, rsa_pub_der_len);\n#endif /* CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n#endif // CONFIG_PRE_ENCRYPTED_OTA_USE_RSA\n    // In case of RSA, public key is in DER format.\n#if defined(CONFIG_PRE_ENCRYPTED_OTA_USE_ECIES)\n    // In case of ECIES, public key is in DER format.\n    TEST_ASSERT_EQUAL(ecies_public_key_len, pub_key_len);\n    TEST_ASSERT_EQUAL_MEMORY(ecies_public_key, pub_key, ecies_public_key_len);\n#endif\n    // Clean up\n    esp_encrypted_img_decrypt_end(ctx);\n    if (pub_key) {\n        free(pub_key);\n    }\n#if defined (CONFIG_PRE_ENCRYPTED_OTA_USE_RSA) && defined(CONFIG_PRE_ENCRYPTED_RSA_USE_DS)\n    esp_secure_cert_free_ds_ctx(cfg.ds_data);\n#endif /* CONFIG_PRE_ENCRYPTED_OTA_USE_RSA && CONFIG_PRE_ENCRYPTED_RSA_USE_DS */\n#ifdef CONFIG_HEAP_TRACING\n    heap_trace_stop();\n    heap_trace_dump();\n#endif\n}\n"
  },
  {
    "path": "esp_encrypted_img/test_apps/main/test_mocks.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"test_mocks.h\"\n#include \"esp_efuse_chip.h\"\n#include \"sdkconfig.h\"\n#include <string.h>\n#include <stdlib.h>\n\nuint8_t dummy_pbkdf2_output[32] = {\n    0x83, 0x17, 0x93, 0x66, 0x0d, 0xe4, 0x91, 0x33, 0x66, 0xae, 0x1e, 0x37, 0x9b, 0x2c, 0xeb, 0x43,\n    0x17, 0xc8, 0x87, 0x00, 0xcc, 0x07, 0x91, 0xd9, 0x8e, 0x5a, 0x2a, 0x2d, 0x5c, 0x71, 0xaf, 0x66\n};\n\nbool esp_encrypted_is_hmac_key_burnt_in_efuse(hmac_key_id_t hmac_key_id)\n{\n    // Simulate the behavior of checking if the HMAC key is burnt in efuse\n    // For this example, we'll assume that the key is always burnt in for key ID 2\n    if (hmac_key_id == 2) {\n        return true;\n    }\n    return false;\n}\n\nint esp_encrypted_img_pbkdf2_hmac_sha256(hmac_key_id_t hmac_key_id, const unsigned char *salt, size_t salt_len,\n        size_t iteration_count, size_t key_length, unsigned char *output)\n{\n    // Simulate the behavior of PBKDF2 HMAC-SHA256 key derivation\n    // For this example, we'll just fill the output with a known pattern\n    memcpy(output, dummy_pbkdf2_output, key_length);\n    return 0; // Indicate success\n}\n\nesp_err_t esp_ds_start_sign(const void *message,\n                            const esp_ds_data_t *data,\n                            hmac_key_id_t key_id,\n                            esp_ds_context_t **esp_ds_ctx)\n{\n    return 0;\n}\n\nstatic const unsigned int expected_signature[] = {\n    0x006c3450, 0xdea677a2, 0x926820c4, 0x6d785259, 0x4b843538, 0x615aec9d, 0x56e0fcad, 0x749b45da,\n    0x3f791700, 0x967ce676, 0x58b031b8, 0xef426f54, 0xb4f2fd90, 0x75a7a818, 0xb39fa150, 0x21e1502e,\n    0xf7108fa4, 0x8c46f51c, 0x14e98795, 0x22667e59, 0xcb6cab5e, 0xdb961c2f, 0x0bdf10a7, 0xecc2fcc7,\n    0x570753d3, 0xcbc6e011, 0x2ea88de6, 0xd7c81c73, 0xa2d9f65c, 0xa74fd309, 0x2a7a764b, 0x750bc352,\n    0x8b27341a, 0x9ab95d23, 0x9caebeea, 0x5b410b4e, 0x5f26d119, 0xf1946d20, 0x8037e8f1, 0x5955b934,\n    0x2b7ef75d, 0x69b7e85a, 0x330f056c, 0x92e47389, 0xcb715480, 0xb551e0fe, 0x4c7b3beb, 0xed67a7d1,\n    0x53d19879, 0x3712444b, 0x25f6d982, 0x525ee85c, 0xba7d8521, 0xfcd73dbd, 0xe0ee096b, 0x779b61c7,\n    0xba30c40d, 0xf9d53b71, 0x1581062b, 0x15163231, 0x65dc89e5, 0x6de575fc, 0x32058194, 0x550b64da,\n    0xbff2ec40, 0x5fbd699d, 0x133656ff, 0xf34e3ac7, 0xbd054ce3, 0x8b89110d, 0xb9804481, 0xb7600a29,\n    0x78435580, 0x3e1e3757, 0xd2d619a0, 0x8f2c327c, 0xb1c4901d, 0xf319e804, 0x966adf5b, 0x1ac533a0,\n    0x76696abd, 0xe6289296, 0xcdbec067, 0xf77a5edd, 0xed0df021, 0xdd7cb0c2, 0x8bbc8f9b, 0xb9c41aaa,\n    0xc7eca1e0, 0xe4238236, 0x4b22b649, 0x0897f841, 0xb94c9516, 0x2344ab37, 0xa73de816, 0x00029aa6\n};\n\nstatic const unsigned int expected_signature_v21[] = {\n    0x6ca95ae, 0xd1c2279, 0xdaf72229, 0xc50df9a8, 0xd4e184e1, 0x3a883bd2, 0x3f04c148, 0x209cad26,\n    0xedcc056c, 0x40b043dd, 0x52cf3120, 0x70e5bd4d, 0x4028643c, 0x52dcbf4a, 0xb8993492, 0x2499b64b,\n    0x623b6eb9, 0x8036d4a7, 0x95fafae3, 0x84fc859a, 0x5155a788, 0x694ac880, 0x70e66556, 0xdbecc366,\n    0xa4ff26c, 0xc8a334bf, 0xeb4335a2, 0x982a8be2, 0x2ae8f5ac, 0x2525d6f1, 0x9f262467, 0x3586b3c9,\n    0xbb18232, 0x7554c1e8, 0x93c2bdfc, 0x6e19ebf5, 0x5aadad7a, 0x3d7ce80b, 0x4b18f02e, 0x1233a570,\n    0x975e6b8d, 0x23d2db5a, 0x5086f2b7, 0xd4af50b3, 0xe6ce39d9, 0x63f7a444, 0x70462926, 0x8a93269a,\n    0x652eb454, 0xe5490beb, 0x99e15fc1, 0x9b469a28, 0x41ac40b5, 0x293a6a47, 0xdefae40c, 0xa5698edf,\n    0xaeaf684d, 0xf3d89453, 0xd454cf12, 0xe7b06ff9, 0xcb44d09c, 0x146763ae, 0xbe8010f, 0x56320865,\n    0xb99cd520, 0x5f30746, 0x2dfda54, 0x167c9567, 0xc8adfa3a, 0x7bb6926e, 0x23a6d1f7, 0x778fdad9,\n    0xb6f44670, 0x80932338, 0xb84ead8a, 0x4fb237ca, 0x8621e9a9, 0x644be6e1, 0x885d1fa7, 0xfb005fea,\n    0xe52344e6, 0x99b1d23, 0x5f1abe8a, 0x7cf28a53, 0x9eefaf2d, 0x5dfe59fa, 0xaa5605bd, 0xf41bf913,\n    0xb988adf2, 0x5ba95896, 0xdb847d45, 0x76d1b452, 0xcb166f50, 0xeb48c6ca, 0x8c7960ae, 0xa12cd8\n};\n\nstatic const unsigned char padded_gcm_key_bin[] = {\n    0xb7, 0x40, 0x28, 0x42, 0x8b, 0xa1, 0xb5, 0x81, 0x4e, 0x98, 0x52, 0xfc,\n    0xbc, 0xc1, 0xd5, 0x40, 0x9a, 0x18, 0x5b, 0xdf, 0x43, 0x8e, 0x15, 0x29,\n    0xeb, 0x55, 0x90, 0xa2, 0x72, 0xa7, 0xd3, 0x81, 0x00, 0xad, 0xb1, 0x40,\n    0x2e, 0xa5, 0x17, 0x97, 0x51, 0x50, 0xf7, 0xee, 0x1d, 0xbf, 0x10, 0xb5,\n    0xba, 0x39, 0xf8, 0x66, 0x45, 0x1b, 0xc2, 0x0b, 0xd8, 0x5b, 0x8b, 0xfc,\n    0x35, 0xb8, 0x93, 0xc4, 0xd9, 0xf9, 0x97, 0x38, 0xbf, 0x26, 0x3a, 0xa8,\n    0xcb, 0x17, 0x69, 0x31, 0x83, 0xaa, 0x30, 0x54, 0x9f, 0x11, 0xb3, 0xea,\n    0x52, 0x2e, 0x0a, 0x14, 0xde, 0x93, 0x66, 0xc5, 0x69, 0x74, 0xa8, 0x1b,\n    0xe1, 0x94, 0x11, 0x1a, 0x22, 0x62, 0xe9, 0x1a, 0x17, 0x43, 0x60, 0x1f,\n    0x95, 0x1a, 0x46, 0x94, 0xc0, 0xa5, 0x81, 0x0f, 0x1a, 0x5b, 0x5a, 0x9c,\n    0x74, 0x29, 0xcd, 0xee, 0x79, 0xc0, 0xd9, 0xe6, 0x53, 0x3a, 0x10, 0x1b,\n    0xf7, 0xa2, 0xa2, 0xf0, 0xc3, 0x7a, 0x84, 0xd0, 0x51, 0x28, 0xa9, 0x15,\n    0x89, 0x65, 0xcb, 0xb1, 0xa2, 0x59, 0x69, 0x2c, 0x12, 0x4c, 0x3e, 0xf1,\n    0x77, 0xf6, 0xe1, 0x54, 0x06, 0xbd, 0x53, 0x0b, 0xd0, 0x5e, 0x88, 0xc6,\n    0xc7, 0x18, 0xa5, 0x85, 0x3f, 0xf7, 0x36, 0x0d, 0x81, 0xfa, 0x40, 0xbb,\n    0x83, 0xe2, 0x9c, 0x61, 0x34, 0xc6, 0x8e, 0x31, 0xd4, 0x38, 0x17, 0x32,\n    0xc2, 0xcb, 0x04, 0x88, 0x44, 0xee, 0xc1, 0x4c, 0x36, 0x7e, 0x74, 0x7f,\n    0xc6, 0x83, 0x45, 0xa8, 0x6b, 0x76, 0xa8, 0x21, 0xf6, 0x08, 0x69, 0x52,\n    0xb9, 0xfd, 0xf1, 0xd4, 0x8d, 0xbf, 0x1f, 0x60, 0x52, 0x21, 0x24, 0x0e,\n    0x2d, 0x8a, 0xd7, 0x72, 0x46, 0x39, 0x42, 0xb9, 0x3f, 0xc7, 0xe0, 0x19,\n    0xe7, 0xed, 0x4a, 0xbc, 0x24, 0x5e, 0xbd, 0x94, 0x38, 0x6f, 0xd8, 0xce,\n    0x0c, 0xff, 0x01, 0x2c, 0x29, 0x56, 0x7b, 0x19, 0xdc, 0xf3, 0x1b, 0x3a,\n    0x56, 0xa7, 0xef, 0x26, 0x84, 0x60, 0xdf, 0x22, 0x1a, 0x56, 0xe6, 0x05,\n    0xb1, 0x0f, 0x62, 0xff, 0x1d, 0x6c, 0x2c, 0x24, 0x4c, 0x3e, 0xb1, 0xf8,\n    0x53, 0x44, 0x32, 0xa5, 0xb6, 0x0d, 0xc2, 0x20, 0x13, 0x71, 0x85, 0x4b,\n    0xa2, 0x21, 0xd7, 0x6d, 0x95, 0x20, 0xc9, 0x4a, 0x85, 0xc2, 0x3a, 0xea,\n    0x6a, 0xa0, 0x87, 0x17, 0x3a, 0xe8, 0x6b, 0x82, 0xb6, 0x4d, 0x44, 0xd5,\n    0x8b, 0x11, 0x7e, 0x78, 0x22, 0xbc, 0x01, 0xd2, 0x1d, 0xcf, 0xfa, 0xd5,\n    0xfc, 0x6e, 0xa0, 0x5a, 0x21, 0x57, 0x70, 0x24, 0x27, 0x1d, 0x93, 0x7d,\n    0x96, 0xc6, 0x6f, 0xe4, 0xb4, 0x5d, 0x1d, 0xaa, 0x33, 0x26, 0xf3, 0x18,\n    0xac, 0x62, 0xf0, 0x14, 0xd3, 0x7e, 0x6f, 0x5a, 0xb1, 0x94, 0x62, 0xfb,\n    0x7d, 0x64, 0xea, 0xe3, 0x08, 0xb0, 0xd4, 0x4b, 0x7b, 0xf7, 0x02, 0x00\n};\nunsigned int padded_gcm_key_bin_len = 384;\n\nesp_ds_data_ctx_t *esp_secure_cert_get_ds_ctx()\n{\n    esp_ds_data_ctx_t *ds_ctx = (esp_ds_data_ctx_t *)malloc(sizeof(esp_ds_data_ctx_t));\n    if (ds_ctx == NULL) {\n        return NULL;\n    }\n    ds_ctx->esp_ds_data = calloc(1, sizeof(esp_ds_data_t));\n    if (ds_ctx->esp_ds_data == NULL) {\n        free(ds_ctx);\n        return NULL;\n    }\n    ds_ctx->esp_ds_data->rsa_length = 95;\n\n    ds_ctx->efuse_key_id = 0;\n    ds_ctx->rsa_length_bits = 3072;\n    return ds_ctx;\n}\n\nvoid esp_secure_cert_free_ds_ctx(esp_ds_data_ctx_t *ds_ctx)\n{\n    if (ds_ctx) {\n        if (ds_ctx->esp_ds_data) {\n            free(ds_ctx->esp_ds_data);\n        }\n        free(ds_ctx);\n    }\n}\n\nesp_err_t esp_ds_finish_sign(void *signature, esp_ds_context_t *esp_ds_ctx)\n{\n    unsigned char *sig = (unsigned char *)signature;\n    if (sig[0] == 0xb1) {\n        memcpy(signature, expected_signature, sizeof(expected_signature));\n    } else if (sig[0] == 0xa3) {\n        memcpy(signature, padded_gcm_key_bin, sizeof(padded_gcm_key_bin));\n    } else {\n        memcpy(signature, expected_signature_v21, sizeof(expected_signature_v21));\n    }\n    return 0;\n}\n\n#if CONFIG_PRE_ENCRYPTED_RSA_USE_DS\nesp_efuse_purpose_t __wrap_esp_efuse_get_key_purpose(esp_efuse_block_t block)\n{\n    // Simulate the behavior of getting the efuse key purpose\n    // For this example, we'll assume that the purpose is always HMAC_DOWN_DIGITAL_SIGNATURE for key blocks 0 and 1\n    if (block == EFUSE_BLK_KEY0 || block == EFUSE_BLK_KEY1) {\n        return ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE;\n    }\n    return 0; // Indicate no purpose\n}\n#endif // CONFIG_PRE_ENCRYPTED_RSA_USE_DS\n"
  },
  {
    "path": "esp_encrypted_img/test_apps/main/test_mocks.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n\ntypedef void *esp_ds_context_t;\ntypedef int hmac_key_id_t;\ntypedef int esp_err_t;\n\n#define ESP_DS_IV_BIT_LEN 128\n#define ESP_DS_SIGNATURE_MAX_BIT_LEN 3072\n#define ESP_DS_SIGNATURE_MD_BIT_LEN 256\n#define ESP_DS_SIGNATURE_M_PRIME_BIT_LEN 32\n#define ESP_DS_SIGNATURE_L_BIT_LEN 32\n#define ESP_DS_SIGNATURE_PADDING_BIT_LEN 64\n\n#define ESP_DS_C_LEN (((ESP_DS_SIGNATURE_MAX_BIT_LEN * 3 \\\n        + ESP_DS_SIGNATURE_MD_BIT_LEN   \\\n        + ESP_DS_SIGNATURE_M_PRIME_BIT_LEN   \\\n        + ESP_DS_SIGNATURE_L_BIT_LEN   \\\n        + ESP_DS_SIGNATURE_PADDING_BIT_LEN) / 8))\n\ntypedef enum {\n    ESP_DS_RSA_1024 = (1024 / 32) - 1,\n    ESP_DS_RSA_2048 = (2048 / 32) - 1,\n    ESP_DS_RSA_3072 = (3072 / 32) - 1,\n    ESP_DS_RSA_4096 = (4096 / 32) - 1\n} esp_digital_signature_length_t;\n\ntypedef struct esp_digital_signature_data {\n    esp_digital_signature_length_t rsa_length;\n    uint32_t iv[ESP_DS_IV_BIT_LEN / 32];\n    uint8_t c[ESP_DS_C_LEN];\n} esp_ds_data_t;\n\ntypedef struct esp_ds_data_ctx {\n    esp_ds_data_t *esp_ds_data;\n    uint8_t efuse_key_id; /* efuse block id in which DS_KEY is stored e.g. 0,1*/\n    uint16_t rsa_length_bits; /* length of RSA private key in bits e.g. 2048 */\n} esp_ds_data_ctx_t;\n\n#define HMAC_KEY_MAX 5\n\n/**\n * @brief Check if the HMAC key is burnt in efuse.\n *\n * @param hmac_key_id[in] The HMAC key ID to check.\n *\n * @return\n *      - true If the HMAC key is burnt.\n *      - false If the HMAC key is not burnt.\n */\nbool esp_encrypted_is_hmac_key_burnt_in_efuse(hmac_key_id_t hmac_key_id);\n\n/**\n * @brief Perform PBKDF2 HMAC-SHA256 key derivation.\n *\n * @param hmac_key_id[in] HMAC key ID.\n * @param salt[in] Pointer to the salt.\n * @param salt_len[in] Length of the salt.\n * @param iteration_count[in] Number of iterations for the key derivation.\n * @param key_length[in] Desired length of the derived key.\n * @param output[out] Buffer to store the derived key.\n *\n * @return\n *     - 0 on success.\n *     - -1 on failure.\n */\nint esp_encrypted_img_pbkdf2_hmac_sha256(hmac_key_id_t hmac_key_id, const unsigned char *salt, size_t salt_len,\n        size_t iteration_count, size_t key_length, unsigned char *output);\n\n/**\n * @brief Get the digital signature context for secure certificate.\n *\n * @return esp_ds_data_ctx_t* Pointer to the digital signature context.\n */\nesp_ds_data_ctx_t *esp_secure_cert_get_ds_ctx(void);\n\n/**\n * @brief Free the digital signature context.\n *\n * @param ds_ctx Pointer to the digital signature context to free.\n */\nvoid esp_secure_cert_free_ds_ctx(esp_ds_data_ctx_t *ds_ctx);\n"
  },
  {
    "path": "esp_encrypted_img/test_apps/partitions.csv",
    "content": "# Name,   Type, SubType, Offset,   Size,     Flags\nesp_secure_cert,0x3F,,,0x2000,\nnvs,      data, nvs,     ,        0x4000,\notadata,  data, ota,     ,        0x2000,\nphy_init, data, phy,     ,        0x1000,\nfactory,  app,  factory, ,        0x10B000,\n# ota_0,    app,  ota_0,   ,        0x10B000,\n# ota_1,    app,  ota_1,   ,        0x14B000,\n"
  },
  {
    "path": "esp_encrypted_img/test_apps/pytest_esp_encrypted_img.py",
    "content": "import pytest\nimport os\n\n\n@pytest.mark.parametrize(\n    \"marker\",\n    [\n        pytest.param(\"qemu\", marks=pytest.mark.qemu),\n        pytest.param(\"generic\", marks=pytest.mark.generic),\n    ],\n)\ndef test_esp_encrypted_img(dut, marker) -> None:\n    binary_path = getattr(dut.app, \"binary_path\", None)\n    if not binary_path or not os.path.exists(binary_path):\n        pytest.skip(f\"Build was skipped or binary not found: {binary_path}\")\n    dut.run_all_single_board_cases()\n"
  },
  {
    "path": "esp_encrypted_img/test_apps/sdkconfig.ci.ds_peripheral",
    "content": "# CI sdkconfig for testing DS peripheral based RSA decryption\n# This config is only supported on IDF >= 5.3 and targets with HMAC support\nCONFIG_IDF_TARGET=\"esp32c3\"\nCONFIG_PARTITION_TABLE_CUSTOM=y\nCONFIG_ESP_TASK_WDT_INIT=n\nCONFIG_PRE_ENCRYPTED_RSA_USE_DS=y\n"
  },
  {
    "path": "esp_encrypted_img/test_apps/sdkconfig.defaults",
    "content": "# This file was generated using idf.py save-defconfig. It can be edited manually.\n# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration\n#\nCONFIG_ESP_TASK_WDT_INIT=n\n"
  },
  {
    "path": "esp_encrypted_img/test_apps/sdkconfig.defaults.esp32",
    "content": "# This file was generated using idf.py save-defconfig. It can be edited manually.\n# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration\n#\nCONFIG_ESP_TASK_WDT_INIT=n\nCONFIG_PRE_ENCRYPTED_OTA_USE_RSA=y\nCONFIG_PRE_ENCRYPTED_OTA_USE_ECIES=n"
  },
  {
    "path": "esp_encrypted_img/test_apps/sdkconfig.defaults.esp32s3",
    "content": "# This file was generated using idf.py save-defconfig. It can be edited manually.\n# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration\n#\nCONFIG_ESP_TASK_WDT_INIT=n\nCONFIG_PRE_ENCRYPTED_OTA_USE_RSA=n\nCONFIG_PRE_ENCRYPTED_OTA_USE_ECIES=y\n"
  },
  {
    "path": "esp_encrypted_img/tools/esp_enc_img_gen.py",
    "content": "#!/usr/bin/env python\n#\n# Encrypted image generation tool. This tool helps in generating encrypted binary image\n# in pre-defined format with assistance of RSA-3072 bit key.\n#\n# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n\nimport argparse\nimport os\nimport sys\n\nfrom cryptography.hazmat.primitives import serialization\nfrom cryptography.hazmat.primitives.asymmetric import padding\nfrom cryptography.hazmat.primitives.ciphers.aead import AESGCM\nfrom cryptography.hazmat.primitives.asymmetric import ec, rsa\nfrom cryptography.hazmat.primitives.kdf.hkdf import HKDF\nfrom cryptography.hazmat.primitives import hashes\nfrom cryptography.hazmat.backends import default_backend\nimport hashlib\n\n# Magic Byte is created using command: echo -n \"esp_encrypted_img\" | sha256sum\nesp_enc_img_magic = 0x0788b6cf\n\nGCM_KEY_SIZE = 32\n\n# Header sizes\nMAGIC_SIZE = 4\nENC_GCM_KEY_SIZE = 384\n\nKDF_SALT_SIZE = 32\nSERVER_PUB_KEY_SIZE = 64\nRESERVED_SIZE_ECC = ENC_GCM_KEY_SIZE - (SERVER_PUB_KEY_SIZE + KDF_SALT_SIZE)\n\nIV_SIZE = 16\nBIN_SIZE_DATA = 4\nAUTH_SIZE = 16\n\nRESERVED_HEADER = (512 - (MAGIC_SIZE + ENC_GCM_KEY_SIZE + IV_SIZE + BIN_SIZE_DATA + AUTH_SIZE))\n\nHMAC_KEY_SIZE = 32\n\nPREDEFINED_SALT = b'\\x0e\\x21\\x60\\x64\\x2d\\xae\\x76\\xd3\\x34\\x48\\xe4\\x3d\\x77\\x20\\x12\\x3d' \\\n    b'\\x9f\\x3b\\x1e\\xce\\xb8\\x8e\\x57\\x3a\\x4e\\x8f\\x7f\\xb9\\x4f\\xf0\\xc8\\x69'\n\nITERATIONS = 2048\n\ndef generate_key_GCM(size: int, shared_secret: bytes, random_salt: bytes = None) -> tuple:\n    if shared_secret is None:\n        return os.urandom(int(size)), None\n    else:\n        if random_salt is None:\n            random_salt = os.urandom(KDF_SALT_SIZE)\n        # Perform HKDF key derivation using the random salt\n        info = \"_esp_enc_img_ecc\"\n        info_bytes = info.encode('utf-8')\n        derived_key = HKDF(\n            algorithm=hashes.SHA256(),\n            length=size,\n            salt=random_salt,\n            info=info_bytes,\n            backend=default_backend()\n        ).derive(shared_secret)\n        return derived_key, random_salt\n\n\ndef generate_IV_GCM() -> bytes:\n    return os.urandom(IV_SIZE)\n\n\ndef encrypt_binary(plaintext: bytes, key: bytes, IV: bytes) -> tuple:\n    encobj = AESGCM(key)\n    ct = encobj.encrypt(IV, plaintext, None)\n    return ct[:len(plaintext)], ct[len(plaintext):]\n\n\ndef load_rsa_key(key_file_name: str) -> str:\n    if key_file_name is None:\n        print('No key file provided')\n        raise SystemExit(1)\n    if not os.path.exists(key_file_name):\n        print('Error: Key file does not exist')\n        raise SystemExit(1)\n    with open(key_file_name, 'rb') as key_file:\n        key_data = key_file.read()\n        if b\"-BEGIN RSA PRIVATE KEY\" in key_data or b\"-BEGIN PRIVATE KEY\" in key_data:\n            private_key = serialization.load_pem_private_key(key_data, password=None)\n            public_key = private_key.public_key()\n        elif b\"-BEGIN PUBLIC KEY\" in key_data:\n            private_key = None\n            public_key = serialization.load_pem_public_key(key_data)\n        else:\n            print(\"Error: Please specify encryption key in PEM format\")\n            raise SystemExit(1)\n    return public_key\n\n\ndef load_ecc_key(key_file_name: str) -> tuple:\n    if key_file_name is None:\n        print('No key file provided, generating new keypair')\n        _, device_pub_key = generate_hmac_key()\n    else:\n        with open(key_file_name, 'rb') as key_file:\n            device_pub_key = serialization.load_pem_public_key(key_file.read(), default_backend())\n    server_priv_key, server_pub_key = generate_random_ecc_keypair()\n    shared_secret = perform_ecdh(server_priv_key, device_pub_key)\n    return shared_secret, server_pub_key\n\n\ndef encrypt(input_file: str, key_file_name: str, output_file: str, scheme: str) -> None:\n    print('Encrypting image ...')\n    with open(input_file, 'rb') as image:\n        data = image.read()\n\n    iv = generate_IV_GCM()\n\n    if scheme == 'RSA-3072':\n        public_key = load_rsa_key(key_file_name)\n        gcm_key, _ = generate_key_GCM(GCM_KEY_SIZE, None, None)\n        encrypted_gcm_key = public_key.encrypt(gcm_key, padding.PKCS1v15())\n    elif scheme == 'ECC-256':\n        shared_secret, public_key = load_ecc_key(key_file_name)\n        gcm_key, kdf_salt = generate_key_GCM(GCM_KEY_SIZE, shared_secret, None)\n\n    ciphertext, authtag = encrypt_binary(data, gcm_key, iv)\n\n    with open(output_file, 'wb') as image:\n        image.write(esp_enc_img_magic.to_bytes(MAGIC_SIZE, 'little'))\n        if scheme == 'RSA-3072':\n            image.write((encrypted_gcm_key))\n        elif scheme == 'ECC-256':\n            # Write the raw ECC public key to the file\n            public_key_to_write = public_key.public_bytes(\n                encoding=serialization.Encoding.X962,\n                format=serialization.PublicFormat.UncompressedPoint\n            )\n            # Public key is 65 bytes, first byte is 0x04\n            # Remove the first byte and make the size back to 64\n            public_key_to_write = public_key_to_write[1:]\n            image.write(public_key_to_write)\n            image.write(kdf_salt)\n            image.write(bytearray(RESERVED_SIZE_ECC))\n        image.write(iv)\n        image.write(len(ciphertext).to_bytes(BIN_SIZE_DATA, 'little'))\n        image.write(authtag)\n        image.write(bytearray(RESERVED_HEADER))\n        image.write(ciphertext)\n    print('Done')\n\n\ndef decrypt_binary(ciphertext: bytes, authTag: bytes, key: bytes, IV: bytes) -> bytes:\n    encobj = AESGCM(key)\n    plaintext = encobj.decrypt(IV, ciphertext + authTag, None)\n    return plaintext\n\n\ndef decrypt(input_file: str, key_file: str, output_file: str, scheme: str) -> None:\n    print('Decrypting image ...')\n    if key_file is not None:\n        with open(key_file, 'rb') as key_file:\n            private_key = serialization.load_pem_private_key(key_file.read(), password=None)\n    else:\n        print('Error: No key file provided for decryption')\n        raise SystemExit(1)\n\n    with open(input_file, 'rb') as file:\n        recv_magic = file.read(MAGIC_SIZE)\n        if (int.from_bytes(recv_magic, 'little') != esp_enc_img_magic):\n            print('Error: Magic Verification Failed', file=sys.stderr)\n            raise SystemExit(1)\n\n        if scheme == 'RSA-3072':\n            encrypted_gcm_key = file.read(ENC_GCM_KEY_SIZE)\n            gcm_key = private_key.decrypt(encrypted_gcm_key, padding.PKCS1v15())\n        elif scheme == 'ECC-256':\n            server_pub_key = file.read(SERVER_PUB_KEY_SIZE)\n            server_pub_key = b'\\x04' + server_pub_key\n\n            try:\n                server_pub_key = ec.EllipticCurvePublicKey.from_encoded_point(ec.SECP256R1(), server_pub_key)\n            except ValueError:\n                print('Error: Invalid server public key format', file=sys.stderr)\n                raise SystemExit(1)\n            shared_secret = perform_ecdh(private_key, server_pub_key)\n            kdf_salt = file.read(KDF_SALT_SIZE)\n            gcm_key, _ = generate_key_GCM(GCM_KEY_SIZE, shared_secret, kdf_salt)\n            _ = file.read(RESERVED_SIZE_ECC)\n        print('Magic verified successfully')\n\n        iv = file.read(IV_SIZE)\n        bin_size = int.from_bytes(file.read(BIN_SIZE_DATA), 'little')\n        auth = file.read(AUTH_SIZE)\n        print('Binary size:', bin_size)\n        if scheme == 'RSA-3072':\n            file.read(RESERVED_HEADER)\n        elif scheme == 'ECC-256':\n            file.read(RESERVED_HEADER)\n        enc_bin = file.read(bin_size)\n\n    decrypted_binary = decrypt_binary(enc_bin, auth, gcm_key, iv)\n\n    with open(output_file, 'wb') as file:\n        file.write(decrypted_binary)\n    print('Done')\n\n\ndef generate_hmac_key() -> ec.EllipticCurvePublicKey:\n    valid_ecc_key = False\n\n    while not valid_ecc_key:\n        # Generate a HMAC key for ECC-256\n        hmac_key = os.urandom(HMAC_KEY_SIZE)\n        curve = ec.SECP256R1()\n        raw_hmac = hashlib.pbkdf2_hmac('sha256', hmac_key, PREDEFINED_SALT, ITERATIONS)\n        candidate_scalar = int.from_bytes(raw_hmac, byteorder='big')\n        if candidate_scalar == 0:\n            print('Candidate scalar is zero, retrying...')\n            continue\n\n        private_key = ec.derive_private_key(candidate_scalar, curve, default_backend())\n        public_key = private_key.public_key()\n\n        # Check if the private key is valid\n        try:\n            private_key.private_numbers()\n        except ValueError:\n            print('Invalid private key, retrying...')\n            continue\n\n        print('ECC-256 key generated successfully')\n        valid_ecc_key = True\n        # Save the public key to a file\n        with open('device_pub_key.pem', 'wb') as key_file:\n            key_file.write(public_key.public_bytes(\n                encoding=serialization.Encoding.PEM,\n                format=serialization.PublicFormat.SubjectPublicKeyInfo\n            ))\n        # Also save the hmac key to a file\n        with open('device_hmac_key.bin', 'wb') as hmac_file:\n            hmac_file.write(hmac_key)\n    return private_key, public_key\n\n\ndef generate_random_ecc_keypair() -> tuple:\n    # Generate a random ECC keypair\n    curve = ec.SECP256R1()\n    private_key = ec.generate_private_key(curve, default_backend())\n    public_key = private_key.public_key()\n    print('Server ECC-256 keypair generated successfully')\n    return private_key, public_key\n\n\ndef generate_rsa_keypair() -> tuple:\n    # Generate a random RSA keypair\n    private_key = rsa.generate_private_key(\n        public_exponent=65537,\n        key_size=3072,\n        backend=default_backend()\n    )\n    public_key = private_key.public_key()\n    # Save the public key to a file\n    with open('rsa_pub_key.pem', 'wb') as key_file:\n        key_file.write(public_key.public_bytes(\n            encoding=serialization.Encoding.PEM,\n            format=serialization.PublicFormat.SubjectPublicKeyInfo\n        ))\n    # Save the private key to a file\n    with open('rsa_priv_key.pem', 'wb') as key_file:\n        key_file.write(private_key.private_bytes(\n            encoding=serialization.Encoding.PEM,\n            format=serialization.PrivateFormat.TraditionalOpenSSL,\n            encryption_algorithm=serialization.NoEncryption()\n        ))\n    print('Server RSA-3072 keypair generated successfully')\n    return private_key, public_key\n\n\ndef perform_ecdh(priv_key, pub_key) -> bytes:\n    # Perform ECDH key exchange\n    shared_key = priv_key.exchange(ec.ECDH(), pub_key)\n    print('ECDH key exchange completed successfully')\n    return shared_key\n\n\ndef get_scheme(key_file: str) -> str:\n    # Based on the keyfile provided, we can determine the scheme\n    if key_file is not None:\n        with open(key_file, 'rb') as key_file:\n            key_data = key_file.read()\n            try:\n                # Try reading as private key\n                private_key = serialization.load_pem_private_key(key_data, password=None)\n                public_key = private_key.public_key()\n                # If we can read the private key, check if it is RSA or ECC\n                if isinstance(private_key, ec.EllipticCurvePrivateKey):\n                    scheme = 'ECC-256'\n                elif isinstance(private_key, rsa.RSAPrivateKey):\n                    scheme = 'RSA-3072'\n                else:\n                    print('Error: Unsupported key type')\n                    raise SystemExit(1)\n            except Exception:\n                # If we cannot read the private key, check if it is public key\n                try:\n                    public_key = serialization.load_pem_public_key(key_data)\n                    if isinstance(public_key, ec.EllipticCurvePublicKey):\n                        scheme = 'ECC-256'\n                    elif isinstance(public_key, rsa.RSAPublicKey):\n                        scheme = 'RSA-3072'\n                    else:\n                        print('Error: Unsupported key type')\n                        raise SystemExit(1)\n                except Exception:\n                    print('Error: Invalid key file format')\n                    raise SystemExit(1)\n    else:\n        scheme = 'ECC-256'\n    return scheme\n\n\ndef main() -> None:\n    parser = argparse.ArgumentParser('Encrypted Image Tool')\n    parser.add_argument('--generate_ecc_key', action='store_true', help='Generate ECC keypair and exit')\n    parser.add_argument('--generate_rsa_key', action='store_true', help='Generate RSA keypair and exit')\n    subparsers = parser.add_subparsers(dest='operation', help='run enc_image -h for additional help')\n\n    encrypt_parser = subparsers.add_parser('encrypt', help='Encrypt a binary')\n    encrypt_parser.add_argument('input_file', help='Input file to encrypt')\n    encrypt_parser.add_argument('key_file', help='Public key for encryption (PEM format)')\n    encrypt_parser.add_argument('output_file', help='Output file for encrypted image')\n\n    decrypt_parser = subparsers.add_parser('decrypt', help='Decrypt an encrypted image')\n    decrypt_parser.add_argument('input_file', help='Input file to decrypt')\n    decrypt_parser.add_argument('key_file', help='Private key for decryption')\n    decrypt_parser.add_argument('output_file', help='Output file for decrypted binary')\n\n    args = parser.parse_args()\n\n    if args.generate_ecc_key:\n        generate_hmac_key()\n        generate_random_ecc_keypair()\n        print('Key generation completed successfully')\n        raise SystemExit(0)\n\n    if args.generate_rsa_key:\n        generate_rsa_keypair()\n        print('Key generation completed successfully')\n        raise SystemExit(0)\n\n    if not args.operation:\n        parser.print_help()\n        raise SystemExit(1)\n\n    # Get the scheme from the key file\n    scheme = get_scheme(args.key_file)\n\n    # Supported schemes will be rsa and ecc\n    supported_schemes = ['RSA-3072', 'ECC-256']\n    if scheme not in supported_schemes:\n        print('Error: Unsupported scheme, supported schemes are:', supported_schemes)\n        raise SystemExit(1)\n\n    if (args.operation == 'encrypt'):\n        encrypt(args.input_file, args.key_file, args.output_file, scheme)\n    elif (args.operation == 'decrypt'):\n        decrypt(args.input_file, args.key_file, args.output_file, scheme)\n    else:\n        print('Error: Invalid operation specified')\n        raise SystemExit(1)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "esp_ext_part_tables/.build-test-rules.yml",
    "content": "esp_ext_part_tables/examples/basic:\n  enable:\n    - if: ((IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR >= 2) or (IDF_VERSION_MAJOR >= 6)) and IDF_TARGET == \"linux\"\n      reason: Host test is enough, linux build support is from IDF v5.2\n"
  },
  {
    "path": "esp_ext_part_tables/CMakeLists.txt",
    "content": "set(srcs \"src/esp_ext_part_tables.c\"\n         \"src/esp_mbr.c\"\n         \"src/esp_mbr_utils.c\")\n\nset(requires \"log\" \"esp_common\")\n\nif(\"${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}\" VERSION_GREATER_EQUAL \"6.0\")\n    list(APPEND requires \"esp_blockdev\")\nendif()\n\nidf_component_register(SRCS ${srcs}\n                    INCLUDE_DIRS \"include\"\n                    REQUIRES ${requires})\n"
  },
  {
    "path": "esp_ext_part_tables/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2020 Thesis projects\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "esp_ext_part_tables/README.md",
    "content": "# ESP External Partition Tables\n\nThis component provides an API to parse and generate external partition tables.\n\nCurrently only [MBR (Master boot record)](https://en.wikipedia.org/wiki/Master_boot_record) is supported.\n\n## Features\n\n- Parse MBR partition tables from raw data (e.g., SD card, USB drive)\n- Generate and manipulate partition lists in memory\n- Deep copy and de-initialize partition lists\n- Access partition information (address, size, type, label)\n- Example projects included\n\n## Example code\n\n```c\n// loaded_mbr -> Pointer to an array of 512 bytes containing MBR loaded from somewhere (SD card, etc.)\n\n#include <stdio.h>\n#include <inttypes.h>\n#include \"esp_err.h\"\n#include \"esp_ext_part_tables.h\"\n#include \"esp_mbr.h\"\n\nesp_err_t err = ESP_OK;\nesp_ext_part_list_t part_list = {0};\n\nerr = esp_mbr_parse((void*) loaded_mbr, &part_list, NULL); // Parse the array containing MBR and fill `esp_ext_part_list_t part_list` structure\nif (err != ESP_OK) {\n    return err;\n}\n\nesp_ext_part_list_item_t* item;\nitem = esp_ext_part_list_item_head(&part_list); // Get the first partition\n\nfor (int i = 0; item != NULL; i++) {\n    printf(\"Partition %d:\\n\n        address: %\" PRIu64 \"\\n\n        size: %\" PRIu64 \"\\n\n        type: %\" PRIu32 \"\\n,\n        label: %s\\n\",\n    i, item->info.address, item->info.size, (uint32_t) item->info.type, item->label ? item->label : \"\"); // item->info.type is of `esp_ext_part_type_known_t` enum type\n\n    item = esp_ext_part_list_item_next(item); // Get the next partition\n}\n\n// ...\n\n// Clean up when done\nesp_ext_part_list_deinit(&part_list);\n```\n\n## More Examples\n\nRunnable example projects can be found in [`examples/`](/esp_ext_part_tables/examples/) folder.\n\n## API Reference\n\nSee [`esp_ext_part_tables.h`](/esp_ext_part_tables/include/esp_ext_part_tables.h) for the full API documentation.\n\nMore advanced API documentation can be found here: [`esp_mbr.h`](/esp_ext_part_tables/include/esp_mbr.h), [`esp_mbr_utils.h`](/esp_ext_part_tables/include/esp_mbr_utils.h).\n"
  },
  {
    "path": "esp_ext_part_tables/examples/basic/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\nset(COMPONENTS main)\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nproject(esp_ext_part_tables_example_basic)\n"
  },
  {
    "path": "esp_ext_part_tables/examples/basic/README.md",
    "content": "# esp_ext_part_tables basic example\n\nThis example demonstrates how to use an ESP32 to read and parse the Master Boot Record (MBR) from a (micro)SD card. It shows how to extract and display information about the card's partitions, such as their type, size, and starting sector, using the ESP-IDF framework.\n\n## Requirements\n\n- any ESP32 board which supports SPI with a (micro)SD card slot or breakout board connected\n- formatted (micro)SD card using MBR (not GPT) as a partition table\n\n## Build and Flash\n\nThe example runs on any ESP development board with SD card connected via SPI (use `idf.py menuconfig` -> `Example config` to set used GPIO pins). To build and run the code on e.g. ESP32-S3, use:\n\n```\nidf.py set-target esp32s3\nidf.py menuconfig\nidf.py build flash monitor\n```\n\n*NOTE 1*: This example uses SDSPI instead of SDMMC to connect to SD card due to more ESP32 devices supporting it but it doesn't matter which one one you use in your project to load the first sector containing MBR. \n\n*NOTE 2*: ESP-IDF 5.1 or newer environment must be set properly before running the example.\n\n## Example output\n\nMicroSD card used in the example showcase has capacity 64GiB and was formatted using Windows Disk Management program to two ~32GiB FAT32 partitions as seen in the picture:\n\n![Screenshot of Disk Management Windows program showing removable Disk 0 (a microSD card) containing 2 FAT32 partitions both roughly 30GB is size](/esp_ext_part_tables/examples/basic/assets/two_fat_partitions.png)\n\nThe example code parsed the MBR and printed the loaded partition information (`type 4` corresponds to `ESP_EXT_PART_TYPE_FAT32` in `esp_ext_part_type_known_t` enum, etc.). The second task generated MBR from `esp_ext_part_list_t` definition and then parsed it again and printed the output.\n\n```log\nI (275) esp_ext_part_tables_example_basic: Example started\nI (275) esp_ext_part_tables_example_basic: Starting MBR parsing example task\nI (335) esp_ext_part_tables_example_basic: MBR loaded successfully\nI (335) esp_ext_part_tables_example_basic: MBR parsed successfully\nPartition 0:\n        LBA start sector: 2048, address: 1048576,\n        sector count: 59392000, size: 30408704000,\n        type: FAT32\n\nPartition 1:\n        LBA start sector: 59394048, address: 30409752576,\n        sector count: 62746624, size: 32126271488,\n        type: FAT32\n\nI (365) esp_ext_part_tables_example_basic: Starting MBR generation example task\nI (365) esp_ext_part_tables_example_basic: MBR generated successfully\nPartition 0:\n        LBA start sector: 2048, address: 1048576,\n        sector count: 7953, size: 4071936,\n        type: FAT12\n\nPartition 1:\n        LBA start sector: 10240, address: 5242880,\n        sector count: 10240, size: 5242880,\n        type: FAT12\n\nI (395) esp_ext_part_tables_example_basic: Example ended\n```\n\nYour output will be different based on (micro)SD card used, partitioning and formatting applied.\n\n## Documentation\n\nSee the esp_ext_part_tables component's README.md file.\n"
  },
  {
    "path": "esp_ext_part_tables/examples/basic/main/CMakeLists.txt",
    "content": "idf_build_get_property(target IDF_TARGET)\n\nset(requires heap)\nif(NOT ${target} STREQUAL \"linux\")\n    list(APPEND requires driver sdmmc esp_driver_sdspi)\nendif()\n\nidf_component_register(\n    SRCS \"main.c\" \"example_utils.c\"\n    REQUIRES ${requires}\n)\n"
  },
  {
    "path": "esp_ext_part_tables/examples/basic/main/Kconfig.projbuild",
    "content": "menu \"Example Configuration\"\n    depends on !IDF_TARGET_LINUX\n\n    config EXAMPLE_PIN_MOSI\n        int \"MOSI GPIO number\"\n        default 15 if IDF_TARGET_ESP32\n        default 35 if IDF_TARGET_ESP32S2\n        default 4 if IDF_TARGET_ESP32S3\n        default 5  if IDF_TARGET_ESP32H2\n        default 36 if IDF_TARGET_ESP32P4\n        default 4  # C3 and others\n\n    config EXAMPLE_PIN_MISO\n        int \"MISO GPIO number\"\n        default 2 if IDF_TARGET_ESP32\n        default 37 if IDF_TARGET_ESP32S2\n        default 5 if IDF_TARGET_ESP32S3\n        default 0  if IDF_TARGET_ESP32H2\n        default 47 if IDF_TARGET_ESP32P4\n        default 6  # C3 and others\n\n    config EXAMPLE_PIN_CLK\n        int \"CLK GPIO number\"\n        default 14 if IDF_TARGET_ESP32\n        default 36 if IDF_TARGET_ESP32S2\n        default 2 if IDF_TARGET_ESP32S3\n        default 4  if IDF_TARGET_ESP32H2\n        default 53 if IDF_TARGET_ESP32P4\n        default 5  # C3 and others\n\n    config EXAMPLE_PIN_CS\n        int \"CS GPIO number\"\n        default 13 if IDF_TARGET_ESP32\n        default 34 if IDF_TARGET_ESP32S2\n        default 8 if IDF_TARGET_ESP32S3\n        default 33 if IDF_TARGET_ESP32P4\n        default 1  # C3 and others\n\n    config EXAMPLE_SD_PWR_CTRL_LDO_INTERNAL_IO\n        depends on SOC_SDMMC_IO_POWER_EXTERNAL\n        bool \"SD power supply comes from internal LDO IO (READ HELP!)\"\n        default n\n        help\n            Only needed when the SD card is connected to specific IO pins which can be used for high-speed SDMMC.\n            Please read the schematic first and check if the SD VDD is connected to any internal LDO output.\n            Unselect this option if the SD card is powered by an external power supply.\n\n    config EXAMPLE_SD_PWR_CTRL_LDO_IO_ID\n        depends on SOC_SDMMC_IO_POWER_EXTERNAL && EXAMPLE_SD_PWR_CTRL_LDO_INTERNAL_IO\n        int \"LDO ID\"\n        default 4 if IDF_TARGET_ESP32P4\n        help\n            Please read the schematic first and input your LDO ID.\nendmenu\n\nmenu \"Example Configuration\"\n    depends on IDF_TARGET_LINUX\nendmenu\n"
  },
  {
    "path": "esp_ext_part_tables/examples/basic/main/example_utils.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n#include \"esp_err.h\"\n#include \"esp_log.h\"\n\n#if !CONFIG_IDF_TARGET_LINUX\n#include \"driver/sdspi_host.h\"\n#include \"sdmmc_cmd.h\"\n#if SOC_SDMMC_IO_POWER_EXTERNAL\n#include \"sd_pwr_ctrl_by_on_chip_ldo.h\"\n#endif // SOC_SDMMC_IO_POWER_EXTERNAL\n#endif // !CONFIG_IDF_TARGET_LINUX\n\n#include \"esp_ext_part_tables.h\"\n\nstatic const char *TAG = \"esp_ext_part_tables_example_basic_utils\";\n\n#define PIN_NUM_MISO  CONFIG_EXAMPLE_PIN_MISO\n#define PIN_NUM_MOSI  CONFIG_EXAMPLE_PIN_MOSI\n#define PIN_NUM_CLK   CONFIG_EXAMPLE_PIN_CLK\n#define PIN_NUM_CS    CONFIG_EXAMPLE_PIN_CS\n\n#if CONFIG_IDF_TARGET_LINUX\n// MBR with 2 FAT12 entries\nuint8_t mbr_bin[512] = {\n    [440] = 0xc4, 0x9d, 0x92, 0x4d, 0x00, 0x00, 0x00, 0x20, 0x21, 0x00,\n    0x01, 0x9e, 0x2f, 0x00, 0x00, 0x08, 0x00, 0x00, 0x11, 0x1f,\n    0x00, 0x00, 0x00, 0xa2, 0x23, 0x00, 0x01, 0x46, 0x05, 0x01,\n    0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x55, 0xaa\n};\n\nunsigned int mbr_bin_len = 512;\n#endif // CONFIG_IDF_TARGET_LINUX\n\nesp_err_t load_first_sector_from_sd_card(void *mbr_buffer)\n{\n    ESP_LOGI(TAG, \"Loading first sector from SD card\");\n#if CONFIG_IDF_TARGET_LINUX\n    memcpy(mbr_buffer, mbr_bin, mbr_bin_len);\n#else\n    // This function loads the first sector (MBR) from the SD card into the provided buffer\n    // It uses SDSPI but can be adapted for SDMMC as well\n    esp_err_t ret = ESP_OK;\n    sdmmc_host_t host = SDSPI_HOST_DEFAULT();\n\n    // For SoCs where the SD power can be supplied both via an internal or external (e.g. on-board LDO) power supply.\n    // When using specific IO pins (which can be used for ultra high-speed SDMMC) to connect to the SD card\n    // and the internal LDO power supply, we need to initialize the power supply first.\n#if CONFIG_EXAMPLE_SD_PWR_CTRL_LDO_INTERNAL_IO\n    sd_pwr_ctrl_ldo_config_t ldo_config = {\n        .ldo_chan_id = CONFIG_EXAMPLE_SD_PWR_CTRL_LDO_IO_ID,\n    };\n    sd_pwr_ctrl_handle_t pwr_ctrl_handle = NULL;\n\n    ret = sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &pwr_ctrl_handle);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to create a new on-chip LDO power control driver\");\n        return;\n    }\n    host.pwr_ctrl_handle = pwr_ctrl_handle;\n#endif\n\n    spi_bus_config_t bus_cfg = {\n        .mosi_io_num = PIN_NUM_MOSI,\n        .miso_io_num = PIN_NUM_MISO,\n        .sclk_io_num = PIN_NUM_CLK,\n        .quadwp_io_num = -1,\n        .quadhd_io_num = -1,\n        .max_transfer_sz = 4000,\n    };\n\n    ret = spi_bus_initialize(host.slot, &bus_cfg, SDSPI_DEFAULT_DMA);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to initialize bus.\");\n        return ret;\n    }\n\n    sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();\n    slot_config.gpio_cs = PIN_NUM_CS;\n    slot_config.host_id = host.slot;\n\n    ret = host.init();\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to initialize host.\");\n        spi_bus_free(host.slot);\n        return ret;\n    }\n\n    int slot = -1;\n    ret = sdspi_host_init_device((const sdspi_device_config_t *)&slot_config, &slot);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to initialize SPI device.\");\n        spi_bus_free(host.slot);\n        return ret;\n    }\n    host.slot = slot;\n\n    sdmmc_card_t card = {0};\n    ret = sdmmc_card_init(&host, &card);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to initialize SD card.\");\n        spi_bus_free(host.slot);\n        return ret;\n    }\n\n    ret = sdmmc_read_sectors(&card, mbr_buffer, 0, 1);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to read first sector from SD card.\");\n        spi_bus_free(host.slot);\n        return ret;\n    }\n#endif // !CONFIG_IDF_TARGET_LINUX\n    return ESP_OK;\n}\n\nchar *parsed_type_to_str(uint8_t type)\n{\n    switch (type) {\n    case ESP_EXT_PART_TYPE_NONE:\n        return \"none/empty\";\n    case ESP_EXT_PART_TYPE_FAT12:\n        return \"FAT12\";\n    case ESP_EXT_PART_TYPE_FAT16:\n        return \"FAR16\";\n    case ESP_EXT_PART_TYPE_FAT32:\n        return \"FAT32\";\n    case ESP_EXT_PART_TYPE_LITTLEFS:\n        return \"LittleFS\";\n    default:\n        break;\n    }\n    return \"unknown\";\n}\n"
  },
  {
    "path": "esp_ext_part_tables/examples/basic/main/example_utils.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include \"esp_err.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nesp_err_t load_first_sector_from_sd_card(void *mbr_buffer);\nchar *parsed_type_to_str(uint8_t type);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_ext_part_tables/examples/basic/main/idf_component.yml",
    "content": "dependencies:\n  idf: \">=5.1\"\n  esp_ext_part_tables:\n    version: \"*\"\n    override_path: '../../..'\n"
  },
  {
    "path": "esp_ext_part_tables/examples/basic/main/main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <inttypes.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"esp_err.h\"\n#include \"esp_log.h\"\n#include \"esp_heap_caps.h\"\n\n#include \"esp_ext_part_tables.h\"\n#include \"esp_mbr.h\"\n#include \"esp_mbr_utils.h\"\n\n#include \"example_utils.h\"\n\nstatic const char *TAG = \"esp_ext_part_tables_example_basic\";\n\nvoid print_loaded_ext_partitions(esp_ext_part_list_item_t *head)\n{\n    esp_ext_part_list_item_t *it = head;\n    int i = 0;\n    do {\n        printf(\"Partition %d:\\n\\tLBA start sector: %\" PRIu64 \", address: %\" PRIu64 \",\\n\\tsector count: %\" PRIu64 \", size: %\" PRIu64 \",\\n\\ttype: %s\\n\\n\",\n               i,\n               esp_ext_part_bytes_to_sector_count(it->info.address, ESP_EXT_PART_SECTOR_SIZE_512B), it->info.address,\n               esp_ext_part_bytes_to_sector_count(it->info.size, ESP_EXT_PART_SECTOR_SIZE_512B), it->info.size,\n               parsed_type_to_str(it->info.type));\n        i++;\n    } while ((it = esp_ext_part_list_item_next(it)) != NULL);\n    fflush(stdout);\n}\n\nvoid esp_ext_part_tables_mbr_parse_example_task(void *pvParameters)\n{\n    TaskHandle_t main_task_handle;\n    ESP_LOGI(TAG, \"Starting MBR parsing example task\");\n    esp_err_t err;\n\n    // Allocate memory for the MBR\n    mbr_t *mbr = (mbr_t *) heap_caps_malloc(sizeof(mbr_t), (MALLOC_CAP_DMA | MALLOC_CAP_8BIT));\n    if (mbr == NULL) {\n        ESP_LOGE(TAG, \"Failed to allocate memory for MBR\");\n        goto end_task;\n    }\n\n    // Load the first sector (MBR) from the SD card into the allocated buffer\n    err = load_first_sector_from_sd_card(mbr);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to load MBR from SD card: %s\", esp_err_to_name(err));\n        free(mbr);\n        goto end_task;\n    }\n    ESP_LOGI(TAG, \"MBR loaded successfully\");\n\n    // Parse the MBR to get the partition list\n    esp_ext_part_list_t part_list = {0};\n    err = esp_mbr_parse((void *) mbr, &part_list, NULL);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to parse MBR: %s\", esp_err_to_name(err));\n        free(mbr);\n        esp_ext_part_list_deinit(&part_list);\n        goto end_task;\n    }\n    free(mbr); // Free the MBR buffer after parsing as it is no longer needed\n    ESP_LOGI(TAG, \"MBR parsed successfully\");\n\n    // Get the first partition\n    esp_ext_part_list_item_t *it = esp_ext_part_list_item_head(&part_list);\n    if (it == NULL) {\n        ESP_LOGE(TAG, \"No partitions found in the MBR\");\n        esp_ext_part_list_deinit(&part_list);\n        goto end_task;\n    }\n\n    // Print the loaded partition list\n    print_loaded_ext_partitions(it);\n\n    // Deinitialize the partition list\n    esp_ext_part_list_deinit(&part_list);\n\n    ESP_LOGI(TAG, \"MBR parsing example task completed successfully\");\n\n    // Notify the main task that the example is done and end the current task\nend_task:\n    main_task_handle = (TaskHandle_t) pvParameters;\n    xTaskNotifyGive(main_task_handle);\n    vTaskDelete(NULL); // Delete the current task\n}\n\nvoid esp_ext_part_tables_mbr_generate_example_task(void *pvParameters)\n{\n    TaskHandle_t main_task_handle;\n    ESP_LOGI(TAG, \"Starting MBR generation example task\");\n    esp_err_t err;\n    esp_ext_part_list_t part_list = {0};\n\n    esp_mbr_generate_extra_args_t mbr_args = {\n        .sector_size = ESP_EXT_PART_SECTOR_SIZE_512B,\n        .alignment = ESP_EXT_PART_ALIGN_1MiB\n    };\n\n    // 2 FAT12 partitions (random parameters)\n    esp_ext_part_list_item_t item1 = {\n        .info = {\n            // Original MBR starts at 2048, but we use 8 for testing ->\n            .address = esp_ext_part_sector_count_to_bytes(8, mbr_args.sector_size), // Should be round up to 2048 sectors (aligned to 1MiB) due to defined sector size and alignment in `esp_mbr_generate_extra_args_t args` above\n            .size = esp_ext_part_sector_count_to_bytes(7953, mbr_args.sector_size),\n            .type = ESP_EXT_PART_TYPE_FAT12,\n            .label = NULL,\n        }\n    };\n    err = esp_ext_part_list_insert(&part_list, &item1);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to insert first partition: %s\", esp_err_to_name(err));\n        goto end_task;\n    }\n\n    esp_ext_part_list_item_t item2 = {\n        .info = {\n            .address = esp_ext_part_sector_count_to_bytes(10240, mbr_args.sector_size),\n            .size = esp_ext_part_sector_count_to_bytes(10240, mbr_args.sector_size),\n            .type = ESP_EXT_PART_TYPE_FAT12,\n            .label = NULL,\n        }\n    };\n    esp_ext_part_list_insert(&part_list, &item2);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to insert second partition: %s\", esp_err_to_name(err));\n        goto end_task;\n    }\n\n    mbr_t *mbr = (mbr_t *) calloc(1, sizeof(mbr_t));\n    if (mbr == NULL) {\n        ESP_LOGE(TAG, \"Failed to allocate memory for MBR\");\n        esp_ext_part_list_deinit(&part_list);\n        goto end_task;\n    }\n    // Generate the MBR\n    err = esp_mbr_generate(mbr, &part_list, &mbr_args);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to generate MBR: %s\", esp_err_to_name(err));\n        free(mbr);\n        esp_ext_part_list_deinit(&part_list);\n        goto end_task;\n    }\n    ESP_LOGI(TAG, \"MBR generated successfully\");\n\n    // Deinitialize the partition list\n    esp_ext_part_list_deinit(&part_list);\n\n    esp_ext_part_list_t part_list_from_gen_mbr = {0};\n    // Parse the generated MBR to get the partition list\n    err = esp_mbr_parse((void *) mbr, &part_list_from_gen_mbr, NULL);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to parse generated MBR: %s\", esp_err_to_name(err));\n        free(mbr);\n        goto end_task;\n    }\n    free(mbr); // Free the MBR buffer after parsing as it is no longer needed\n\n    // Get the first partition\n    esp_ext_part_list_item_t *it = esp_ext_part_list_item_head(&part_list_from_gen_mbr);\n    if (it == NULL) {\n        ESP_LOGE(TAG, \"No partitions found in the MBR\");\n        esp_ext_part_list_deinit(&part_list_from_gen_mbr);\n        goto end_task;\n    }\n\n    // Print the loaded partition list\n    print_loaded_ext_partitions(it);\n\n    // Deinitialize the partition list\n    esp_ext_part_list_deinit(&part_list_from_gen_mbr);\n\n    ESP_LOGI(TAG, \"MBR generation example task completed successfully\");\n\n    // Notify the main task that the example is done and end the current task\nend_task:\n    main_task_handle = (TaskHandle_t) pvParameters;\n    xTaskNotifyGive(main_task_handle);\n    vTaskDelete(NULL); // Delete the current task\n}\n\nvoid app_main(void)\n{\n    ESP_LOGI(TAG, \"Example started\");\n    TaskHandle_t main_task_handle = xTaskGetCurrentTaskHandle(); // Get the handle of the main task\n\n    // Create new tasks with bigger stack size just in case\n    xTaskCreate(esp_ext_part_tables_mbr_parse_example_task, \"esp_ext_part_tables_mbr_parse_example_task\", 4096, (void *) main_task_handle, 5, NULL);\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY); // Wait for the example task to complete\n\n    xTaskCreate(esp_ext_part_tables_mbr_generate_example_task, \"esp_ext_part_tables_mbr_generate_example_task\", 4096, (void *) main_task_handle, 5, NULL);\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY); // Wait for the example task to complete\n\n    ESP_LOGI(TAG, \"Example ended\");\n}\n"
  },
  {
    "path": "esp_ext_part_tables/examples/basic/pytest_esp_ext_part_tables_example_basic.py",
    "content": "# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: CC0-1.0\n\nimport pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.utils import idf_parametrize\n\n@pytest.mark.host_test\n@idf_parametrize('target', ['linux'], indirect=['target'])\ndef test_esp_ext_part_tables_example_basic_linux(dut: Dut) -> None:\n    dut.expect_exact('Starting MBR parsing example task')\n    dut.expect_exact('MBR parsing example task completed successfully')\n    dut.expect_exact('Starting MBR generation example task')\n    dut.expect_exact('MBR generation example task completed successfully')\n"
  },
  {
    "path": "esp_ext_part_tables/examples/basic/sdkconfig.defaults.ci",
    "content": "CONFIG_IDF_TARGET=\"linux\"\nCONFIG_IDF_TARGET_LINUX=y\n"
  },
  {
    "path": "esp_ext_part_tables/idf_component.yml",
    "content": "version: \"0.2.0\"\ndescription: ESP External Partition Tables\nurl: https://github.com/espressif/idf-extra-components/tree/master/esp_ext_part_tables\nissues: https://github.com/espressif/idf-extra-components/issues\nrepository: https://github.com/espressif/idf-extra-components.git\ndependencies:\n  idf:\n    version: \">=5.1\"\n"
  },
  {
    "path": "esp_ext_part_tables/include/esp_ext_part_tables.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include \"esp_err.h\"\n#include \"esp_idf_version.h\"\n\n#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0))\n#include \"esp_blockdev.h\"\n#endif // (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0))\n\n#if __has_include(<bsd/sys/queue.h>)\n#include <bsd/sys/queue.h>\n#else\n#include \"sys/queue.h\"\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef enum {\n    ESP_EXT_PART_SECTOR_SIZE_UNKNOWN = 0, // Unknown sector size\n    ESP_EXT_PART_SECTOR_SIZE_512B = 512, // 512 B sector size (SD, eMMC, USB flash, legacy or emulated mode HDD/SSD)\n    ESP_EXT_PART_SECTOR_SIZE_2KiB = 2048, // 2 KiB sector size (optical disks)\n    ESP_EXT_PART_SECTOR_SIZE_4KiB = 4096, // 4 kiB sector size (modern HDD/SSD)\n} esp_ext_part_sector_size_t;\n\ntypedef enum {\n    ESP_EXT_PART_ALIGN_NONE = 0, // No alignment\n    ESP_EXT_PART_ALIGN_4KiB = 4096, // 4 KiB alignment\n    ESP_EXT_PART_ALIGN_1MiB = (1024 * 1024), // 1 MiB alignment\n} esp_ext_part_align_t;\n\ntypedef enum __attribute__((packed))\n{\n    ESP_EXT_PART_TYPE_NONE = 0x00,\n    ESP_EXT_PART_TYPE_FAT12,\n    ESP_EXT_PART_TYPE_FAT16, /*!< FAT16 with LBA addressing */\n    ESP_EXT_PART_TYPE_FAT32, /*!< FAT32 with LBA addressing */\n    ESP_EXT_PART_TYPE_LITTLEFS, /*!< Possibly LittleFS (MBR CHS field => LittleFS block size hack) */\n// Note: The following types are not supported, but we can return a type for them\n    ESP_EXT_PART_TYPE_LINUX_ANY, /*!< Linux partition (any type) */\n    ESP_EXT_PART_TYPE_EXFAT_OR_NTFS, /*!< Not supported, but we can return a type for it */\n    ESP_EXT_PART_TYPE_GPT_PROTECTIVE_MBR, /*!< Not supported, but we can return a type for it */\n} esp_ext_part_type_known_t;\n\ntypedef enum {\n    ESP_EXT_PART_FLAG_NONE = 0,\n    ESP_EXT_PART_FLAG_ACTIVE = 1 << 0,  /*!< Active / bootable partition */\n    ESP_EXT_PART_FLAG_EXTRA = 1 << 1, /*!< Additional information stored in `extra` field (e.g. LittleFS block size stored in CHS hack) */\n} esp_ext_part_flags_t;\n\ntypedef enum {\n    ESP_EXT_PART_LIST_FLAG_NONE = 0,\n    ESP_EXT_PART_LIST_FLAG_READ_ONLY = 1 << 0, /*!< Read-only partition list */\n} esp_ext_part_list_flags_t;\n\ntypedef enum {\n    ESP_EXT_PART_LIST_SIGNATURE_MBR, /*!< MBR signature type */\n} esp_ext_part_signature_type_t;\n\ntypedef struct {\n    uint32_t data[1];\n    esp_ext_part_signature_type_t type;\n} esp_ext_part_list_signature_t;\n\ntypedef struct {\n    uint64_t address; /*!< Start address in bytes */\n    uint64_t size; /*!< Size in bytes */\n    uint64_t extra; /*!< Extra information (e.g. LittleFS block size stored in CHS hack, etc.) */\n    char *label;\n    esp_ext_part_flags_t flags; /*!< Flags for the partition */\n    uint8_t type; /*!< Known partition type for this component (usually a part of `esp_ext_part_type_known_t`) */\n} esp_ext_part_t;\n\ntypedef struct esp_ext_part_list_item_ {\n    esp_ext_part_t info;\n    SLIST_ENTRY(esp_ext_part_list_item_) next;\n} esp_ext_part_list_item_t;\n\ntypedef struct {\n    esp_ext_part_list_signature_t signature; /*!< Disk signature or identifier */\n    SLIST_HEAD(esp_ext_part_list_head_, esp_ext_part_list_item_) head; /*!< Head of the partition list */\n    esp_ext_part_list_flags_t flags; /*!< Flags for the partition list */\n    esp_ext_part_sector_size_t sector_size; /*!< Sector size (storage medium property) */\n} esp_ext_part_list_t;\n\n/**\n * @brief Convert bytes to sector count based on the sector size.\n *\n * This function performs a ceiling division to ensure that any remaining bytes\n * that do not fill a complete sector are counted as an additional sector.\n *\n * @param total_bytes Total number of bytes.\n * @param sector_size Size of a single sector.\n *\n * @return Number of sectors or 0 if the sector size is unknown to avoid a division by zero.\n */\nuint64_t esp_ext_part_bytes_to_sector_count(uint64_t total_bytes, esp_ext_part_sector_size_t sector_size);\n\n/**\n * @brief Convert sector count to bytes based on the sector size.\n *\n * @param sector_count Number of sectors.\n * @param sector_size Size of a single sector.\n *\n * @return Total size in bytes.\n */\nuint64_t esp_ext_part_sector_count_to_bytes(uint64_t sector_count, esp_ext_part_sector_size_t sector_size);\n\n/**\n * @brief Deinitialize an external partition list structure and free all resources.\n *\n * This function releases all the memory and resources associated with the partition list referenced by 'part_list' parameter.\n *\n * @note This function is not thread-safe.\n *\n * @param[in] part_list Pointer to the partition list structure to deinitialize.\n *\n * @return\n *     - ESP_OK: Deinitialization was successful.\n *     - ESP_ERR_INVALID_ARG: `part_list` is NULL.\n */\nesp_err_t esp_ext_part_list_deinit(esp_ext_part_list_t *part_list);\n\n/**\n * @brief Insert a partition item into an external partition list.\n *\n * This function inserts a copy of the given partition item into the partition list.\n *\n * @note This function is not thread-safe.\n *\n * @param[in] part_list Pointer to the partition list structure.\n * @param[in] item      Pointer to the partition item to insert (will be copied).\n *\n * @return\n *     - ESP_OK: Insertion was successful.\n *     - ESP_ERR_INVALID_ARG: `part_list` or `item` is NULL.\n *     - ESP_ERR_NO_MEM: Memory allocation failed.\n */\nesp_err_t esp_ext_part_list_insert(esp_ext_part_list_t *part_list, esp_ext_part_list_item_t *item);\n\n/**\n * @brief Deep copy an external partition list.\n *\n * This function creates a deep copy of the source partition list into the destination partition list.\n * It allocates memory for the destination list and copies all items, including their labels.\n *\n * @note This function is not thread-safe.\n *\n * @param[out] dst Pointer to the destination partition list structure (must be allocated before but not initialized, i.e. \"empty\").\n * @param[in] src Pointer to the source partition list structure to copy from.\n *\n * @return\n *     - ESP_OK: Deep copy was successful.\n *     - ESP_ERR_INVALID_ARG: `dst` or `src` is NULL.\n *     - ESP_ERR_NO_MEM: Memory allocation failed.\n */\nesp_err_t esp_ext_part_list_deep_copy(esp_ext_part_list_t *dst, esp_ext_part_list_t *src);\n\n/**\n * @brief Get the head (first item) of an external partition list.\n *\n * @param[in] part_list Pointer to the partition list structure.\n *\n * @return Pointer to the first partition list item, or NULL if the list is empty or uninitialized.\n */\nesp_ext_part_list_item_t *esp_ext_part_list_item_head(esp_ext_part_list_t *part_list);\n\n/**\n * @brief Get the next item in an external partition list.\n *\n * @param[in] item Pointer to the current partition list item.\n *\n * @return Pointer to the next partition list item, or NULL if there are no more items.\n */\nesp_ext_part_list_item_t *esp_ext_part_list_item_next(esp_ext_part_list_item_t *item);\n\n/**\n * @brief Get the signature of an external partition list.\n *\n * This function retrieves the disk signature or identifier from the partition list.\n *\n * @param[in] part_list Pointer to the partition list structure.\n * @param[out] signature Pointer to a buffer where the signature will be stored.\n *\n * @return\n *     - ESP_OK: Signature retrieval was successful.\n *     - ESP_ERR_INVALID_ARG: `part_list` or signature is NULL.\n */\nesp_err_t esp_ext_part_list_signature_get(esp_ext_part_list_t *part_list, void *signature);\n\n/**\n * @brief Set the signature of an external partition list.\n *\n * This function sets the disk signature or identifier for the partition list.\n *\n * @param[in] part_list Pointer to the partition list structure.\n * @param[in] signature Pointer to the signature data to set.\n * @param[in] type      Type of the signature (e.g., MBR).\n *\n * @return\n *     - ESP_OK: Signature was successfully set.\n *     - ESP_ERR_INVALID_ARG: `part_list` or `signature` is NULL.\n *     - ESP_ERR_NOT_SUPPORTED: Unsupported signature type.\n */\nesp_err_t esp_ext_part_list_signature_set(esp_ext_part_list_t *part_list, const void *signature, esp_ext_part_signature_type_t type);\n\n#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0))\n/**\n * @brief Read a aprtition table and from a block device handle and parse it.\n *\n * This function reads the partition table from the specified block device and populates the provided partition list structure.\n * The type of partition table to read is specified by the 'type' parameter.\n * Additional arguments for parsing can be provided through the 'extra_args' parameter.\n *\n * @note This function is not thread-safe.\n *\n * @param[in] handle       Block device handle to read from.\n * @param[out] part_list   Pointer to the partition list structure to populate from the partition table.\n * @param[in] type         Type of partition table to read (e.g., MBR).\n * @param[in] extra_args   Pointer to additional arguments for parsing dependent on the partition type (optional, can be NULL).\n *\n * @return\n *     - ESP_OK: Partition list was successfully loaded.\n *     - ESP_ERR_INVALID_ARG: `handle` or `part_list` is NULL.\n *     - ESP_ERR_NOT_SUPPORTED: Unsupported partition table type.\n *     - ESP_ERR_NO_MEM: Memory allocation failed.\n *     - propagated errors from BDL operations or partition table parsing functions.\n */\nesp_err_t esp_ext_part_list_bdl_read(esp_blockdev_handle_t handle, esp_ext_part_list_t *part_list, esp_ext_part_signature_type_t type, void *extra_args);\n\n/**\n * @brief Generate a partition table and write it to a block device handle.\n *\n * This function writes the provided partition list to the specified block device.\n * The type of partition table to write is specified by the 'type' parameter.\n * Additional arguments for generation can be provided through the 'extra_args' parameter.\n *\n * @note This function is not thread-safe.\n *\n * @param[in] handle       Block device handle to write to.\n * @param[in] part_list    Pointer to the partition list structure generate the partition table from.\n * @param[in] type         Type of partition table to write (e.g., MBR).\n * @param[in] extra_args   Pointer to additional arguments for generation dependent on the partition type (optional, can be NULL).\n *\n * @return\n *     - ESP_OK: Partition list was successfully written.\n *     - ESP_ERR_INVALID_ARG: `handle` or `part_list` is NULL.\n *     - ESP_ERR_NOT_SUPPORTED: Unsupported partition table type.\n *     - ESP_ERR_NO_MEM: Memory allocation failed.\n *     - propagated errors from BDL operations or partition table generation functions.\n */\nesp_err_t esp_ext_part_list_bdl_write(esp_blockdev_handle_t handle, esp_ext_part_list_t *part_list, esp_ext_part_signature_type_t type, void *extra_args);\n#endif // (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0))\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_ext_part_tables/include/esp_mbr.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include \"esp_err.h\"\n#include \"esp_ext_part_tables.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define MBR_SIZE 512\n#define MBR_SIGNATURE 0xAA55\n#define MBR_COPY_PROTECTED 0x5A5A\n#define MBR_PARTITION_TABLE_OFFSET 0x1BE\n#define MBR_PARTITION_STATUS_ACTIVE 0x80\n#define MBR_MAX_PARTITION_COUNT 4\n\n// MBR partition entry structure - https://en.wikipedia.org/wiki/Master_boot_record#Partition_table_entries\n#pragma pack(push, 1)\ntypedef struct {\n    uint8_t status;\n    union {\n        struct {\n            uint8_t h_start;\n            uint16_t cs_start;\n        };\n        uint8_t chs_start[3];\n    };\n    uint8_t type;\n    union {\n        struct {\n            uint8_t h_end;\n            uint16_t cs_end;\n        };\n        uint8_t chs_end[3];\n    };\n    uint32_t lba_start;\n    uint32_t sector_count;\n} mbr_partition_t;\n#pragma pack(pop)\n\n// MBR structure - https://en.wikipedia.org/wiki/Master_boot_record#Sector_layout\n#pragma pack(push, 1)\ntypedef struct {\n    union {\n        uint8_t bootstrap_code_classical[446];\n        struct {\n            uint8_t bootstrap_code_modern_part1[218];\n            uint16_t _reserved;\n            uint8_t original_physical_drive;\n            uint8_t seconds;\n            uint8_t minutes;\n            uint8_t hours;\n            uint8_t bootstrap_code_modern_part2[216];\n            uint32_t disk_signature;\n            uint16_t copy_protected;\n        };\n    };\n    mbr_partition_t partition_table[4];\n    uint16_t boot_signature;\n} mbr_t;\n#pragma pack(pop)\n\ntypedef struct {\n    esp_ext_part_sector_size_t sector_size; // Sector size hint, pulled from a storage device driver query\n    bool (*esp_mbr_parse_custom_supported_partition_types)(uint8_t, uint8_t *); // Custom function for parsing supported MBR partition types, optional\n} esp_mbr_parse_extra_args_t;\n\ntypedef struct {\n    esp_ext_part_sector_size_t sector_size; // Sector size hint for correct LBA alignment\n    esp_ext_part_align_t alignment; // Alignment hint for correct LBA alignment\n    bool keep_signature; // If true, the disk signature will be preserved in the generated MBR and not overwritten with a random value\n    uint8_t (*esp_mbr_generate_custom_supported_partition_types)(uint8_t); // Custom function for generating supported MBR partition types, optional\n} esp_mbr_generate_extra_args_t;\n\n/**\n * @brief Parses a Master Boot Record (MBR) buffer and extracts partition information.\n *\n * This function reads the provided MBR buffer, validates its signature, and populates\n * the given partition list structure with the partition entries found in the MBR.\n * Additional parsing options can be provided via the extra_args parameter.\n *\n * @note This function is not thread-safe.\n *\n * @param[in]  mbr_buf    Pointer to a buffer containing the raw MBR data (must be at least `MBR_SIZE` bytes and start of the MBR must align with start of the buffer).\n * @param[out] part_list  Pointer to the partition list structure to be filled with parsed entries.\n * @param[in]  extra_args Optional extra arguments for parsing (can be NULL for defaults).\n *\n * @return\n *     - ESP_OK:              Parsing was successful.\n *     - ESP_ERR_INVALID_ARG: Invalid arguments were provided.\n *     - ESP_ERR_NOT_FOUND:   MBR signature not found or invalid MBR.\n *     - ESP_ERR_NO_MEM:      Memory allocation failed during parsing.\n *     - Other error codes from `esp_ext_part_list_insert`.\n */\nesp_err_t esp_mbr_parse(void *mbr_buf,\n                        esp_ext_part_list_t *part_list,\n                        esp_mbr_parse_extra_args_t *extra_args);\n\n/**\n * @brief Generates a Master Boot Record (MBR) from a partition list.\n *\n * This function fills the provided MBR structure based on the given partition list.\n * It sets up the partition table, disk signature, and other MBR fields. Generation\n * options such as sector size, alignment, and signature preservation can be specified\n * via the extra_args parameter.\n *\n * @note This function is not thread-safe.\n *\n * @param[out] mbr         Pointer to the blank MBR structure to be filled (must already be allocated and be at least `MBR_SIZE` bytes).\n * @param[in]  part_list   Pointer to the partition list structure containing partition entries to encode.\n * @param[in]  extra_args  Optional extra arguments for generation (can be NULL for defaults).\n *\n * @return\n *     - ESP_OK:                Generation was successful.\n *     - ESP_ERR_INVALID_ARG:   Invalid arguments were provided.\n *     - ESP_ERR_INVALID_STATE: Error filling partition entry.\n *     - ESP_ERR_NOT_SUPPORTED: Partition address or size (sector count) exceeds 32-bit limit of MBR.\n *     - Other error codes from `esp_ext_part_list_signature_get` or `esp_mbr_partition_set`.\n */\nesp_err_t esp_mbr_generate(mbr_t *mbr,\n                           esp_ext_part_list_t *part_list,\n                           esp_mbr_generate_extra_args_t *extra_args);\n\n/**\n * @brief Sets a partition entry in the MBR (Master Boot Record).\n *\n * This function updates the specified partition entry in the provided MBR structure\n * with the information from the given partition list item. Additional arguments for\n * partition generation must be supplied via the extra_args parameter.\n *\n * @note This function is not thread-safe.\n *\n * @warning If the partition entry is empty (i.e., `item->info.type` is `ESP_EXT_PART_TYPE_NONE`), it will be cleared in the MBR.\n *          If there is an empty gap between partition entries, partition entries after the gap will most likely be ignored when the MBR is parsed (MBR does not allow gaps in the partition table).\n *          To avoid this, you can use `esp_mbr_remove_gaps_between_partiton_entries()` function to remove gaps in the MBR partition table.\n *\n * @param[in,out] mbr               Pointer to the MBR structure to be updated.\n * @param[in]     partition_index   Index of the partition entry to set (0-3).\n * @param[in]     item              Pointer to the partition list item structure containing partition information.\n * @param[in]     extra_args        Extra arguments for partition entry setting (required).\n *\n * @return\n *     - ESP_OK:                Success.\n *     - ESP_ERR_INVALID_ARG:   Invalid arguments were provided.\n *     - ESP_ERR_INVALID_STATE: Error filling partition entry.\n *     - ESP_ERR_NOT_SUPPORTED: Partition address or size (sector count) exceeds 32-bit limit of MBR.\n */\nesp_err_t esp_mbr_partition_set(mbr_t *mbr, uint8_t partition_index, esp_ext_part_list_item_t *item, esp_mbr_generate_extra_args_t *extra_args);\n\n/**\n * @brief Removes gaps in the MBR partition table by shifting partitions.\n *\n * @note This function is not thread-safe.\n *\n * @param[in,out] mbr Pointer to the MBR structure to be updated.\n * @return\n *     - ESP_OK: Success.\n *     - ESP_ERR_INVALID_ARG: Invalid pointer to MBR structure.\n */\nesp_err_t esp_mbr_remove_gaps_between_partiton_entries(mbr_t *mbr);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_ext_part_tables/include/esp_mbr_utils.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include <stdint.h>\n#include \"esp_ext_part_tables.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define MBR_CHS_HEADS 255\n#define MBR_CHS_SECTORS_PER_TRACK 63\n#define MBR_CHS_MAX_CYLINDER 1023\n#define MBR_CHS_MAX_HEAD 254\n#define MBR_CHS_MAX_SECTOR 63\n\n// Helper functions for MBR CHS conversion and LBA alignment\n\n/**\n * @brief Set a 3-byte CHS array from a 24-bit value.\n *\n * @param[out] chs 3-byte array to store the CHS value.\n * @param[in]  val 24-bit value representing CHS.\n */\nvoid esp_mbr_chs_arr_val_set(uint8_t chs[3], uint32_t val);\n\n/**\n * @brief Get a 24-bit value from a 3-byte CHS array.\n *\n * @param[in] chs 3-byte array containing the CHS value.\n * @return 24-bit value representing CHS stored in `uint32_t`.\n */\nuint32_t esp_mbr_chs_arr_val_get(const uint8_t chs[3]);\n\n/**\n * @brief Convert an LBA value to a 3-byte CHS array.\n *\n * @param[out] chs 3-byte array to store the CHS value.\n * @param[in]  lba Logical Block Address to convert.\n */\nvoid esp_mbr_lba_to_chs_arr(uint8_t chs[3], uint32_t lba);\n\n/**\n * @brief Align an LBA value according to sector size and alignment requirements.\n *\n * @param[in] lba         Logical Block Address to align.\n * @param[in] sector_size Sector size enumeration.\n * @param[in] alignment   Alignment requirement enumeration.\n * @return Aligned LBA value.\n */\nuint32_t esp_mbr_lba_align(uint32_t lba, esp_ext_part_sector_size_t sector_size, esp_ext_part_align_t alignment);\n\n/**\n * @brief Generate default supported MBR partition types for a given internal type.\n *\n * @param[in] type Internal artition type to generate supported types from internal `esp_ext_part_type_known_t` enum.\n * @return MBR partition type code.\n */\nuint8_t esp_mbr_generate_default_supported_partition_types(uint8_t type);\n\n/**\n * @brief Parse default supported MBR partition types into internal types (`esp_ext_part_type_known_t`).\n *\n * @param[in]  type             MBR partition type code to parse.\n * @param[out] out_type_parsed  Pointer to store the parsed internal partition type (from `esp_ext_part_type_known_t`).\n * @return true if the partition type is known and supported, false otherwise.\n */\nbool esp_mbr_parse_default_supported_partition_types(uint8_t type, uint8_t *out_type_parsed);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_ext_part_tables/src/esp_ext_part_tables.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdint.h>\n#include <string.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"esp_err.h\"\n#include \"esp_log.h\"\n#include \"esp_idf_version.h\"\n\n#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0))\n#include \"esp_blockdev.h\"\n#endif // (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0))\n\n#include \"esp_ext_part_tables.h\"\n#include \"esp_mbr.h\"\n\n#if __has_include(<bsd/sys/queue.h>)\n#include <bsd/sys/queue.h>\n#else\n#include \"sys/queue.h\"\n#endif\n\nuint64_t esp_ext_part_bytes_to_sector_count(uint64_t total_bytes, esp_ext_part_sector_size_t sector_size)\n{\n    if (sector_size == ESP_EXT_PART_SECTOR_SIZE_UNKNOWN) {\n        return 0; // Avoid division by zero\n    }\n    // Ceiling division for integers: (a + b - 1) / b\n    return ((total_bytes + (uint64_t) sector_size - 1) / (uint64_t) sector_size);\n}\n\nuint64_t esp_ext_part_sector_count_to_bytes(uint64_t sector_count, esp_ext_part_sector_size_t sector_size)\n{\n    return sector_count * (uint64_t) sector_size;\n}\n\nesp_err_t esp_ext_part_list_deinit(esp_ext_part_list_t *part_list)\n{\n    if (part_list == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    esp_ext_part_list_item_t *it = NULL;\n    esp_ext_part_list_item_t *tmp = NULL;\n    SLIST_FOREACH_SAFE(it, &part_list->head, next, tmp) {\n        SLIST_REMOVE(&part_list->head, it, esp_ext_part_list_item_, next);\n        free(it->info.label); // Deep free the label if it was allocated\n        free(it); // Free the item itself\n    }\n    memset(part_list, 0, sizeof(esp_ext_part_list_t)); // Reset the part_list structure\n    return ESP_OK;\n}\n\nesp_err_t esp_ext_part_list_insert(esp_ext_part_list_t *part_list, esp_ext_part_list_item_t *item)\n{\n    if (part_list == NULL || item == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    esp_ext_part_list_item_t *_item = (esp_ext_part_list_item_t *) malloc(sizeof(esp_ext_part_list_item_t));\n    if (_item == NULL) {\n        return ESP_ERR_NO_MEM;\n    }\n\n    memcpy(_item, item, sizeof(esp_ext_part_list_item_t)); // Copy the item\n    if (_item->info.label != NULL) {\n        _item->info.label = strdup(item->info.label); // Deep copy the label\n        if (_item->info.label == NULL) {\n            free(_item);\n            return ESP_ERR_NO_MEM;\n        }\n    }\n\n    esp_ext_part_list_item_t *it = NULL;\n    esp_ext_part_list_item_t *last = NULL;\n    SLIST_FOREACH(it, &part_list->head, next) {\n        last = it;\n    }\n    if (last == NULL) {\n        SLIST_INSERT_HEAD(&part_list->head, _item, next);\n    } else {\n        SLIST_INSERT_AFTER(last, _item, next);\n    }\n    return ESP_OK;\n}\n\nesp_err_t esp_ext_part_list_deep_copy(esp_ext_part_list_t *dst, esp_ext_part_list_t *src)\n{\n    if (dst == NULL || src == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    memcpy(dst, src, sizeof(esp_ext_part_list_t)); // Copy the structure\n    memset(&dst->head, 0, sizeof(dst->head)); // Reset the head of the destination list\n\n    esp_err_t err;\n    esp_ext_part_list_item_t *it = NULL;\n    SLIST_FOREACH(it, &src->head, next) {\n        err = esp_ext_part_list_insert(dst, it); // Insert copies the item from src to dst\n        if (err != ESP_OK) {\n            esp_ext_part_list_deinit(dst);\n            return err;\n        }\n    }\n    return ESP_OK;\n}\n\nesp_ext_part_list_item_t *esp_ext_part_list_item_head(esp_ext_part_list_t *part_list)\n{\n    if (part_list == NULL) {\n        return NULL;\n    }\n    return SLIST_FIRST(&part_list->head);\n}\n\nesp_ext_part_list_item_t *esp_ext_part_list_item_next(esp_ext_part_list_item_t *item)\n{\n    if (item == NULL) {\n        return NULL;\n    }\n    return SLIST_NEXT(item, next);\n}\n\nesp_err_t esp_ext_part_list_signature_get(esp_ext_part_list_t *part_list, void *signature)\n{\n    if (part_list == NULL || signature == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    uint32_t out = 0;\n    switch (part_list->signature.type) {\n    case ESP_EXT_PART_LIST_SIGNATURE_MBR:\n        out = (uint32_t) part_list->signature.data[0];\n        memcpy(signature, &out, sizeof(uint32_t));\n        break;\n    default:\n        return ESP_ERR_NOT_SUPPORTED; // Unsupported signature type\n    }\n    return ESP_OK;\n}\n\nesp_err_t esp_ext_part_list_signature_set(esp_ext_part_list_t *part_list, const void *signature, esp_ext_part_signature_type_t type)\n{\n    if (part_list == NULL || signature == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    part_list->signature.type = type;\n    switch (type) {\n    case ESP_EXT_PART_LIST_SIGNATURE_MBR:\n        part_list->signature.data[0] = *((const uint32_t *) signature);\n        break;\n    default:\n        return ESP_ERR_NOT_SUPPORTED; // Unsupported signature type\n    }\n    return ESP_OK;\n}\n\n#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0))\nesp_err_t esp_ext_part_list_bdl_read(esp_blockdev_handle_t handle, esp_ext_part_list_t *part_list, esp_ext_part_signature_type_t type, void *extra_args)\n{\n    if (handle == NULL || part_list == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    esp_err_t err = ESP_OK;\n    uint8_t *buf = NULL;\n\n    switch (type) {\n    case ESP_EXT_PART_LIST_SIGNATURE_MBR:\n        buf = malloc(MBR_SIZE);\n        if (buf == NULL) {\n            return ESP_ERR_NO_MEM;\n        }\n\n        err = handle->ops->read(handle, buf, MBR_SIZE, 0, MBR_SIZE);\n        if (err != ESP_OK) {\n            free(buf);\n            return err;\n        }\n\n        err = esp_mbr_parse(buf, part_list, (esp_mbr_parse_extra_args_t *) extra_args);\n        free(buf);\n        break;\n\n    default:\n        err = ESP_ERR_NOT_SUPPORTED; // Unsupported signature type\n        break;\n    }\n\n    return err;\n}\n\nesp_err_t esp_ext_part_list_bdl_write(esp_blockdev_handle_t handle, esp_ext_part_list_t *part_list, esp_ext_part_signature_type_t type, void *extra_args)\n{\n    if (handle == NULL || part_list == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    esp_err_t err = ESP_OK;\n    uint8_t *buf = NULL;\n\n    switch (type) {\n    case ESP_EXT_PART_LIST_SIGNATURE_MBR:\n        buf = malloc(MBR_SIZE);\n        if (buf == NULL) {\n            return ESP_ERR_NO_MEM;\n        }\n\n        err = esp_mbr_generate((mbr_t *) buf, part_list, (esp_mbr_generate_extra_args_t *) extra_args);\n        if (err != ESP_OK) {\n            free(buf);\n            return err;\n        }\n\n        err = handle->ops->write(handle, buf, 0, MBR_SIZE);\n        free(buf);\n        break;\n\n    default:\n        err = ESP_ERR_NOT_SUPPORTED; // Unsupported signature type\n        break;\n    }\n\n    return err;\n}\n#endif // (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0))\n"
  },
  {
    "path": "esp_ext_part_tables/src/esp_mbr.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdint.h>\n#include <string.h>\n#include \"esp_err.h\"\n#include \"esp_log.h\"\n#include \"esp_random.h\"\n\n#include \"esp_ext_part_tables.h\"\n#include \"esp_mbr.h\"\n#include \"esp_mbr_utils.h\"\n\nstatic const char *TAG = \"esp_mbr\";\n\nstatic void ext_part_list_item_do_extra(esp_ext_part_list_item_t *item, mbr_partition_t *partition)\n{\n    // This function is for any extra actions that might be needed for specific partition types.\n    // It can be used to set flags, perform additional operations or checks if needed.\n\n    switch (item->info.type) { // Parsed type\n    case ESP_EXT_PART_TYPE_LITTLEFS:\n        item->info.flags |= ESP_EXT_PART_FLAG_EXTRA; // Set the extra flag to indicate that this partition has extra information\n        item->info.extra = (uint64_t) esp_mbr_chs_arr_val_get(partition->chs_start); // Put LittleFS block size which was stored in `chs_start` to `extra` field\n        break;\n    default:\n        break;\n    }\n}\n\nesp_err_t esp_mbr_parse(void *mbr_buf,\n                        esp_ext_part_list_t *part_list,\n                        esp_mbr_parse_extra_args_t *extra_args)\n{\n    if (mbr_buf == NULL || part_list == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    mbr_t *mbr = (mbr_t *) mbr_buf;\n    // Check MBR signature\n    if (mbr->boot_signature != MBR_SIGNATURE) {\n        ESP_LOGE(TAG, \"MBR signature not found\");\n        return ESP_ERR_NOT_FOUND;\n    }\n\n    // Set defaults\n    part_list->sector_size = ESP_EXT_PART_SECTOR_SIZE_512B; // Default sector size\n    bool (*f_parse_supported_partition_types)(uint8_t, uint8_t *) = esp_mbr_parse_default_supported_partition_types;\n\n    // Load extra arguments if provided\n    if (extra_args) {\n        if (extra_args->sector_size != ESP_EXT_PART_SECTOR_SIZE_UNKNOWN) {\n            part_list->sector_size = extra_args->sector_size; // Use the sector size hint from extra_args\n        }\n        if (extra_args->esp_mbr_parse_custom_supported_partition_types) {\n            f_parse_supported_partition_types = extra_args->esp_mbr_parse_custom_supported_partition_types; // Use a custom function for supported partition types\n        }\n    }\n\n    esp_err_t err = ESP_OK;\n    if (mbr->copy_protected == MBR_COPY_PROTECTED) {\n        part_list->flags |= ESP_EXT_PART_LIST_FLAG_READ_ONLY;\n    }\n\n    err = esp_ext_part_list_signature_set(part_list, &mbr->disk_signature, ESP_EXT_PART_LIST_SIGNATURE_MBR);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to set partition list (disk) signature\");\n        return err;\n    }\n\n    mbr_partition_t *partition;\n    for (int i = 0; i < 4; i++) {\n        partition = (mbr_partition_t *) &mbr->partition_table[i];\n\n        // Check if the partition entry is empty and if so, skip it\n        if (partition->type == 0x00) {\n            break; // No more partitions, exit the loop (MBR partition table cannot have holes in it)\n        }\n\n        // If the partition entry is not supported, skip it as well\n        uint8_t parsed_type = ESP_EXT_PART_TYPE_NONE;\n        bool is_supported = f_parse_supported_partition_types(partition->type, &parsed_type);\n        if (!is_supported) {\n            continue;\n        }\n\n        // Create a new partition item and populate it with the partition info\n        esp_ext_part_list_item_t item = {\n            .info = {\n                .address = esp_ext_part_sector_count_to_bytes((uint64_t) partition->lba_start, part_list->sector_size),\n                .size = esp_ext_part_sector_count_to_bytes((uint64_t) partition->sector_count, part_list->sector_size),\n                .extra = 0,\n                .label = NULL, // MBR does not have labels\n                .flags = ESP_EXT_PART_FLAG_NONE,\n                .type = parsed_type,\n            }\n        };\n\n        if (partition->status == MBR_PARTITION_STATUS_ACTIVE) {\n            item.info.flags |= ESP_EXT_PART_FLAG_ACTIVE;\n        }\n\n        // Set the flags or extra field based on the partition type or do any extra actions needed\n        ext_part_list_item_do_extra(&item, partition);\n\n        // Add the partition info to the output table\n        err = esp_ext_part_list_insert(part_list, &item);\n        if (err != ESP_OK) {\n            ESP_LOGD(TAG, \"Failed to add partition info to list\");\n            return err;\n        }\n    }\n    return ESP_OK;\n}\n\nstatic bool mbr_partition_fill(mbr_partition_t *partition, esp_ext_part_list_item_t *item)\n{\n    uint32_t lba_start = partition->lba_start;\n    uint32_t lba_end = lba_start - 1 + partition->sector_count;\n\n    switch (item->info.type) {\n    case ESP_EXT_PART_TYPE_FAT12:\n    case ESP_EXT_PART_TYPE_FAT16:\n    case ESP_EXT_PART_TYPE_FAT32:\n        // Set CHS values based on LBA start and end\n        esp_mbr_lba_to_chs_arr(partition->chs_start, lba_start);\n        esp_mbr_lba_to_chs_arr(partition->chs_end, lba_end);\n        break;\n    case ESP_EXT_PART_TYPE_LITTLEFS:\n        // Use `chs_start` to store LittleFS block size (if stored in `extra` field)\n        if (item->info.extra != 0) {\n            // If the extra flag is set, use the extra field to store the LittleFS block size\n            esp_mbr_chs_arr_val_set(partition->chs_start, (uint32_t) item->info.extra);\n\n            if (!(item->info.flags & ESP_EXT_PART_FLAG_EXTRA)) {\n                // If the extra flag is not set but the extra field is set, log a warning\n                ESP_LOGW(TAG, \"LittleFS partition with extra field set but extra flag was not set\");\n            }\n        } else {\n            ESP_LOGE(TAG, \"LittleFS partition with 0xC3 type without any block size value in `extra` field\");\n            return false; // Error\n        }\n        break;\n    default:\n        break;\n    }\n    return true; // OK\n}\n\nesp_err_t esp_mbr_partition_set(mbr_t *mbr, uint8_t partition_index, esp_ext_part_list_item_t *item, esp_mbr_generate_extra_args_t *extra_args)\n{\n    if (mbr == NULL || partition_index >= 4 || item == NULL || extra_args == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    // Set defaults\n    mbr_partition_t *partition = &mbr->partition_table[partition_index];\n    uint8_t (*f_generate_supported_partition_types)(uint8_t) = esp_mbr_generate_default_supported_partition_types;\n\n    // Load extra arguments if provided\n    if (extra_args->esp_mbr_generate_custom_supported_partition_types) {\n        f_generate_supported_partition_types = extra_args->esp_mbr_generate_custom_supported_partition_types;  // Use a custom function for supported partition types\n    }\n\n    // Check if the partition entry is empty and if so, skip it\n    if (item->info.type == ESP_EXT_PART_TYPE_NONE) {\n        memset(partition, 0, sizeof(mbr_partition_t));\n        return ESP_OK; // No partition to set\n    }\n\n    // Check if we have enough space in the MBR partition table\n    uint64_t first_sector_address = esp_ext_part_bytes_to_sector_count(item->info.address, extra_args->sector_size);\n    uint64_t sector_count = esp_ext_part_bytes_to_sector_count(item->info.size, extra_args->sector_size);\n    if (first_sector_address > UINT32_MAX || sector_count > UINT32_MAX) {\n        ESP_LOGE(TAG, \"Partition address or size exceeds 32-bit limit of MBR\");\n        return ESP_ERR_NOT_SUPPORTED; // Address or size too large for MBR\n    }\n\n    // Set the partition info\n    if (item->info.flags & ESP_EXT_PART_FLAG_ACTIVE) {\n        partition->status = MBR_PARTITION_STATUS_ACTIVE;\n    }\n    partition->lba_start = esp_mbr_lba_align((uint32_t) first_sector_address, extra_args->sector_size, extra_args->alignment);\n    partition->sector_count = (uint32_t) sector_count;\n    partition->type = f_generate_supported_partition_types(item->info.type);\n\n    if (mbr_partition_fill(partition, item) == false) {\n        return ESP_ERR_INVALID_STATE; // Error filling partition\n    }\n\n    return ESP_OK;\n}\n\nesp_err_t esp_mbr_generate(mbr_t *mbr,\n                           esp_ext_part_list_t *part_list,\n                           esp_mbr_generate_extra_args_t *extra_args)\n{\n    if (mbr == NULL || part_list == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    esp_err_t err = ESP_OK;\n\n    // Set default arguments for MBR generation\n    esp_mbr_generate_extra_args_t args = {\n        .sector_size = part_list->sector_size != ESP_EXT_PART_SECTOR_SIZE_UNKNOWN ? part_list->sector_size : ESP_EXT_PART_SECTOR_SIZE_512B, // Default sector size\n        .alignment = ESP_EXT_PART_ALIGN_1MiB, // Default alignment\n        .keep_signature = false, // Default is to generate a new disk signature\n    };\n\n    // Load extra arguments if provided\n    if (extra_args) {\n        if (extra_args->sector_size != ESP_EXT_PART_SECTOR_SIZE_UNKNOWN) {\n            args.sector_size = extra_args->sector_size;\n        }\n        if (extra_args->alignment != ESP_EXT_PART_ALIGN_NONE) {\n            args.alignment = extra_args->alignment;\n        }\n        args.keep_signature = extra_args->keep_signature;\n        if (extra_args->esp_mbr_generate_custom_supported_partition_types) {\n            args.esp_mbr_generate_custom_supported_partition_types = extra_args->esp_mbr_generate_custom_supported_partition_types;\n        }\n    }\n\n    mbr->boot_signature = MBR_SIGNATURE;\n    if (args.keep_signature) {\n        // Use the disk signature from the partition list\n        err = esp_ext_part_list_signature_get(part_list, &mbr->disk_signature);\n        if (err != ESP_OK) {\n            ESP_LOGE(TAG, \"Failed to get disk signature from partition list\");\n            return err;\n        }\n    } else {\n        mbr->disk_signature = esp_random();\n    }\n\n    if (part_list->flags & ESP_EXT_PART_LIST_FLAG_READ_ONLY) {\n        mbr->copy_protected = MBR_COPY_PROTECTED;\n    }\n\n    esp_ext_part_list_item_t *it = NULL;\n    int i = 0;\n    SLIST_FOREACH(it, &part_list->head, next) {\n        if (i >= MBR_MAX_PARTITION_COUNT) {\n            ESP_LOGW(TAG, \"More than %d partitions in the list, only the first %d will be added to the MBR\", MBR_MAX_PARTITION_COUNT, MBR_MAX_PARTITION_COUNT);\n            break; // MBR can only hold 4 partitions\n        }\n        err = esp_mbr_partition_set(mbr, i, it, &args);\n        if (err != ESP_OK) {\n            ESP_LOGE(TAG, \"Failed to set partition %d: %s\", i, esp_err_to_name(err));\n            return err; // Error setting partition\n        }\n        i += 1;\n    }\n\n    return ESP_OK;\n}\n\nesp_err_t esp_mbr_remove_gaps_between_partiton_entries(mbr_t *mbr)\n{\n    if (mbr == NULL) {\n        return ESP_ERR_INVALID_ARG; // Invalid MBR pointer\n    }\n\n    // Iterate through the partition table and remove gaps\n    mbr_partition_t *partition;\n    uint8_t gap_index = 0; // Next index to fill\n    for (int i = 0; i < 4; i++) {\n        partition = &mbr->partition_table[i];\n        if (partition->type == 0x00) {\n            continue; // Skip empty entries\n        }\n        if (gap_index != i) {\n            // Move the partition to the next available index\n            memcpy(&mbr->partition_table[gap_index], partition, sizeof(mbr_partition_t));\n            memset(partition, 0, sizeof(mbr_partition_t)); // Clear the old entry\n        }\n        gap_index++;\n    }\n\n    return ESP_OK;\n}\n"
  },
  {
    "path": "esp_ext_part_tables/src/esp_mbr_utils.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdint.h>\n#include <string.h>\n#include \"esp_log.h\"\n#include \"esp_ext_part_tables.h\"\n#include \"esp_mbr_utils.h\"\n\nstatic const char *TAG = \"esp_mbr_utils\";\n\nvoid esp_mbr_chs_arr_val_set(uint8_t chs[3], uint32_t val)\n{\n    chs[0] = val & 0xFF;\n    chs[1] = (val >> 8) & 0xFF;\n    chs[2] = (val >> 16) & 0xFF;\n}\n\nuint32_t esp_mbr_chs_arr_val_get(const uint8_t chs[3])\n{\n    return chs[0] | (chs[1] << 8) | (chs[2] << 16);\n}\n\nvoid esp_mbr_lba_to_chs_arr(uint8_t chs[3], uint32_t lba)\n{\n    uint16_t cylinder;\n    uint8_t head;\n    uint8_t sector;\n\n    uint32_t sectors_per_cylinder = MBR_CHS_HEADS * MBR_CHS_SECTORS_PER_TRACK;\n    uint32_t temp;\n\n    cylinder = lba / sectors_per_cylinder;\n    temp = lba % sectors_per_cylinder;\n    head = temp / MBR_CHS_SECTORS_PER_TRACK;\n    sector = (temp % MBR_CHS_SECTORS_PER_TRACK) + 1;\n\n    // Clamp to BIOS CHS limits\n    if (cylinder > MBR_CHS_MAX_CYLINDER) {\n        cylinder = MBR_CHS_MAX_CYLINDER;\n    }\n    if (head > MBR_CHS_MAX_HEAD) {\n        head = MBR_CHS_MAX_HEAD;\n    }\n    if (sector > MBR_CHS_MAX_SECTOR) {\n        sector = MBR_CHS_MAX_SECTOR;\n    }\n\n    uint8_t chs_bytes[3];\n    chs_bytes[0] = head & 0xFF;\n    chs_bytes[1] = ((cylinder >> 2) & 0xC0) | (sector & 0x3F); // high 2 bits of cylinder + 6-bit sector\n    chs_bytes[2] = cylinder & 0xFF;\n\n    if (chs != NULL) {\n        memcpy(chs, chs_bytes, 3);\n    }\n}\n\nuint32_t esp_mbr_lba_align(uint32_t lba, esp_ext_part_sector_size_t sector_size, esp_ext_part_align_t alignment)\n{\n    if (sector_size == 0 || alignment == 0) {\n        return lba; // No alignment\n    }\n    uint32_t alignment_sectors = alignment / sector_size;\n    return (lba + alignment_sectors - 1) & ~(alignment_sectors - 1);\n}\n\nstatic bool default_known_supported_partition_types(uint8_t type, esp_ext_part_type_known_t *out_type_parsed)\n{\n    bool supported = true;\n    esp_ext_part_type_known_t parsed_type = ESP_EXT_PART_TYPE_NONE;\n    switch (type) {\n    // Supported types:\n    case 0x01: // FAT12\n        parsed_type = ESP_EXT_PART_TYPE_FAT12;\n        break;\n    case 0x04: __attribute__((fallthrough));\n    case 0x06: __attribute__((fallthrough));\n    case 0x0E: // FAT16B with LBA addressing (also uses 0x04 and 0x06 but on modern system shouldn't matter)\n        parsed_type = ESP_EXT_PART_TYPE_FAT16;\n        break;\n    case 0x0B: __attribute__((fallthrough));\n    case 0x0C: // FAT32 with LBA addressing (0x0B is for CHS addressing)\n        parsed_type = ESP_EXT_PART_TYPE_FAT32;\n        break;\n    case 0xC3: // Possibly LittleFS (MBR CHS field => LittleFS block size hack)\n        parsed_type = ESP_EXT_PART_TYPE_LITTLEFS;\n        break;\n\n    // Unsupported types:\n    case 0x07: // exFAT or NTFS\n        parsed_type = ESP_EXT_PART_TYPE_EXFAT_OR_NTFS;\n        supported = false; // Not supported\n        break;\n    case 0x83: // Linux partition (any type)\n        parsed_type = ESP_EXT_PART_TYPE_LINUX_ANY;\n        supported = false; // Not supported\n        break;\n    case 0xEE: // GPT protective MBR\n        parsed_type = ESP_EXT_PART_TYPE_GPT_PROTECTIVE_MBR;\n        supported = false; // Not supported\n        break;\n    case 0x05: __attribute__((fallthrough)); // Extended partition with CHS addressing\n    case 0x0F: __attribute__((fallthrough)); // Extended partition with LBA addressing\n    default:\n        supported = false;\n        break;\n    }\n\n    if (out_type_parsed != NULL) {\n        *out_type_parsed = parsed_type;\n    }\n    if (supported == false) {\n        ESP_LOGD(TAG, \"Unknown or unsupported partition type: 0x%02X\", type);\n    }\n    return supported;\n}\n\nbool esp_mbr_parse_default_supported_partition_types(uint8_t type, uint8_t *out_type_parsed)\n{\n    esp_ext_part_type_known_t parsed_type = ESP_EXT_PART_TYPE_NONE;\n    bool is_supported = default_known_supported_partition_types(type, &parsed_type);\n\n    if (out_type_parsed != NULL) {\n        *out_type_parsed = (uint8_t) parsed_type;\n    }\n    return is_supported;\n}\n\nuint8_t esp_mbr_generate_default_supported_partition_types(uint8_t type)\n{\n    switch ((esp_ext_part_type_known_t) type) {\n    case ESP_EXT_PART_TYPE_FAT12:\n        return 0x01; // FAT12\n    case ESP_EXT_PART_TYPE_FAT16:\n        return 0x0E; // FAT16B with LBA addressing\n    case ESP_EXT_PART_TYPE_FAT32:\n        return 0x0C; // FAT32 with LBA addressing\n    /*\n    LittleFS is not a standard MBR partition type, but we can use a custom type `0xC3`, which is not usually used nowadays.\n    This allows us to identify LittleFS partitions in the MBR.\n\n    Explanation why `0xC3` was chosen:\n    0xC    3\n      1100 0011\n      ↑↑ ↑ ↑↑↑↑\n      └│─│─┴┴┴┴── 0x83 => a modern filesystem (e.g. Linux)\n       └─│─────── 0x40 => CHS used as LittleFS block size\n         └─────── 0x10 => a hidden filesystem\n    */\n    case ESP_EXT_PART_TYPE_LITTLEFS:\n        return 0xC3; // Possibly LittleFS (MBR CHS field => LittleFS block size hack)\n    case ESP_EXT_PART_TYPE_EXFAT_OR_NTFS: // Not supported, but we can return a type for it\n        return 0x07; // exFAT or NTFS\n    case ESP_EXT_PART_TYPE_LINUX_ANY: // Not supported, but we can return a type for it\n        return 0x83; // Linux partition (any type)\n    case ESP_EXT_PART_TYPE_GPT_PROTECTIVE_MBR: // Not supported, but we can return a type for it\n        return 0xEE; // GPT protective MBR\n    default:\n        return 0x00; // Unknown type\n    }\n}\n"
  },
  {
    "path": "esp_ext_part_tables/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(esp_ext_part_tables_parse_test)\n"
  },
  {
    "path": "esp_ext_part_tables/test_apps/main/CMakeLists.txt",
    "content": "set(priv_requires \"unity\")\n\nif(\"${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}\" VERSION_GREATER_EQUAL \"6.0\")\n    list(APPEND priv_requires \"esp_blockdev\")\nendif()\n\nidf_component_register(SRCS \"test_esp_ext_part.c\"\n                    INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES ${priv_requires}\n                    WHOLE_ARCHIVE)\n"
  },
  {
    "path": "esp_ext_part_tables/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  idf: \">=5.1\"\n  espressif/esp_ext_part_tables:\n    version: \"*\"\n    override_path: \"../..\"\n"
  },
  {
    "path": "esp_ext_part_tables/test_apps/main/test_esp_ext_part.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdlib.h>\n#include <stdbool.h>\n#include <string.h>\n#include <stdio.h>\n#include <inttypes.h>\n#include \"esp_err.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_idf_version.h\"\n\n#if !CONFIG_IDF_TARGET_LINUX\n#include \"esp_newlib.h\"\n#endif // !CONFIG_IDF_TARGET_LINUX\n\n#include \"unity.h\"\n#include \"unity_test_runner.h\"\n#include \"unity_test_utils_memory.h\"\n\n#include \"esp_ext_part_tables.h\"\n#include \"esp_mbr.h\"\n\nvoid setUp(void)\n{\n    unity_utils_record_free_mem();\n}\n\nvoid tearDown(void)\n{\n#if !CONFIG_IDF_TARGET_LINUX\n    esp_reent_cleanup();    //clean up some of the newlib's lazy allocations\n#endif // !CONFIG_IDF_TARGET_LINUX\n    unity_utils_evaluate_leaks_direct(0);\n}\n\n// MBR with 2 FAT12 entries\nuint8_t mbr_bin[512] = {\n    [440] = 0xc4, 0x9d, 0x92, 0x4d, 0x00, 0x00, 0x00, 0x20, 0x21, 0x00,\n    0x01, 0x9e, 0x2f, 0x00, 0x00, 0x08, 0x00, 0x00, 0x11, 0x1f,\n    0x00, 0x00, 0x00, 0xa2, 0x23, 0x00, 0x01, 0x46, 0x05, 0x01,\n    0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x55, 0xaa\n};\n\nunsigned int mbr_bin_len = 512;\n\nstatic void print_esp_ext_part_list_items(esp_ext_part_list_item_t *head)\n{\n    esp_ext_part_list_item_t *it = head;\n    int i = 0;\n    do {\n        printf(\"Partition %d:\\n\\tLBA start sector: %\" PRIu64 \", address: %\" PRIu64 \",\\n\\tsector count: %\" PRIu64 \", size: %\" PRIu64 \",\\n\\ttype: %\" PRIu32 \"\\n\\n\",\n               i,\n               esp_ext_part_bytes_to_sector_count(it->info.address, ESP_EXT_PART_SECTOR_SIZE_512B), it->info.address,\n               esp_ext_part_bytes_to_sector_count(it->info.size, ESP_EXT_PART_SECTOR_SIZE_512B), it->info.size,\n               (uint32_t) (it->info.type));\n        i++;\n    } while ((it = esp_ext_part_list_item_next(it)) != NULL);\n}\n\nTEST_CASE(\"Test mbr_bin struct\", \"[esp_ext_part_table]\")\n{\n    mbr_t *mbr = (mbr_t *) mbr_bin;\n    TEST_ASSERT_NOT_NULL(mbr);\n    TEST_ASSERT_EQUAL(MBR_SIGNATURE, mbr->boot_signature);\n    printf(\"MBR boot signature: 0x%\" PRIX16 \"\\n\", mbr->boot_signature);\n    printf(\"MBR disk signature: 0x%\" PRIX32 \"\\n\", mbr->disk_signature);\n}\n\nTEST_CASE(\"Test esp_mbr_parse\", \"[esp_ext_part_table]\")\n{\n    esp_ext_part_list_t part_list = {0};\n    TEST_ESP_OK(esp_mbr_parse((void *) mbr_bin, &part_list, NULL));\n    esp_ext_part_list_item_t *it = esp_ext_part_list_item_head(&part_list);\n    TEST_ASSERT_NOT_NULL(it);\n\n    print_esp_ext_part_list_items(it);\n    fflush(stdout);\n\n    do {\n        TEST_ASSERT_NOT_EQUAL(0, it->info.address);\n        TEST_ASSERT_NOT_EQUAL(0, it->info.size);\n        TEST_ASSERT_NOT_EQUAL(0, it->info.type);\n    } while ((it = esp_ext_part_list_item_next(it)) != NULL);\n    esp_ext_part_list_deinit(&part_list);\n    TEST_ASSERT_EQUAL(0, part_list.head.slh_first);\n}\n\nvoid generate_original_mbr(mbr_t *mbr)\n{\n    esp_mbr_generate_extra_args_t mbr_args = {\n        .sector_size = ESP_EXT_PART_SECTOR_SIZE_512B,\n        .alignment = ESP_EXT_PART_ALIGN_1MiB\n    };\n\n    esp_ext_part_list_t part_list = {0};\n\n    // 2 FAT12 partitions with same parameters as in the original MBR in the array\n    esp_ext_part_list_item_t item1 = {\n        .info = {\n            // Original MBR starts at 2048, but we use 8 for testing ->\n            .address = esp_ext_part_sector_count_to_bytes(8, mbr_args.sector_size), // Should be round up to 2048 sectors (aligned to 1MiB) due to defined sector size and alignment in `esp_mbr_generate_extra_args_t args` below\n            .size = esp_ext_part_sector_count_to_bytes(7953, mbr_args.sector_size),\n            .type = ESP_EXT_PART_TYPE_FAT12,\n            .label = NULL,\n        }\n    };\n    esp_ext_part_list_item_t item2 = {\n        .info = {\n            .address = esp_ext_part_sector_count_to_bytes(10240, mbr_args.sector_size),\n            .size = esp_ext_part_sector_count_to_bytes(10240, mbr_args.sector_size),\n            .type = ESP_EXT_PART_TYPE_FAT12,\n            .label = NULL,\n        }\n    };\n\n    TEST_ESP_OK(esp_ext_part_list_insert(&part_list, &item1));\n    TEST_ESP_OK(esp_ext_part_list_insert(&part_list, &item2));\n\n    // Generate the MBR\n    TEST_ESP_OK(esp_mbr_generate(mbr, &part_list, &mbr_args));\n\n    // Deinitialize the part list\n    TEST_ESP_OK(esp_ext_part_list_deinit(&part_list));\n}\n\nTEST_CASE(\"Test esp_mbr_generate generates the (almost) same MBR as the original\", \"[esp_ext_part_table]\")\n{\n    mbr_t *mbr = (mbr_t *) calloc(1, sizeof(mbr_t));\n    TEST_ASSERT_NOT_NULL(mbr);\n    generate_original_mbr(mbr);\n\n    esp_ext_part_list_t part_list1 = {0};\n    TEST_ESP_OK(esp_mbr_parse((void *) mbr, &part_list1, NULL));\n    esp_ext_part_list_item_t *it1 = esp_ext_part_list_item_head(&part_list1);\n    TEST_ASSERT_NOT_NULL(it1);\n\n    esp_ext_part_list_t part_list2 = {0};\n    TEST_ESP_OK(esp_mbr_parse((void *) mbr_bin, &part_list2, NULL));\n    esp_ext_part_list_item_t *it2 = esp_ext_part_list_item_head(&part_list2);\n    TEST_ASSERT_NOT_NULL(it2);\n\n    print_esp_ext_part_list_items(it1);\n    print_esp_ext_part_list_items(it2);\n    fflush(stdout);\n\n    uint8_t *mbr_bin_from_part_table = (uint8_t *) mbr_bin + MBR_PARTITION_TABLE_OFFSET;\n    uint8_t *mbr_from_part_table = (uint8_t *) mbr + MBR_PARTITION_TABLE_OFFSET;\n    uint8_t compare_size = mbr_bin_len - MBR_PARTITION_TABLE_OFFSET;\n    // Test if the generated MBR is the same as the original MBR - only from partition table part\n    // Disk signature is randomly generated, so we don't compare it\n    TEST_ASSERT_EQUAL_MEMORY(mbr_bin_from_part_table, mbr_from_part_table, compare_size);\n    free(mbr);\n    esp_ext_part_list_deinit(&part_list1);\n    esp_ext_part_list_deinit(&part_list2);\n}\n\nTEST_CASE(\"Test esp_mbr_generate with esp_mbr_parse\", \"[esp_ext_part_table]\")\n{\n    mbr_t *mbr;\n    mbr = (mbr_t *) calloc(1, sizeof(mbr_t));\n    TEST_ASSERT_NOT_NULL(mbr);\n    generate_original_mbr(mbr);\n\n    esp_ext_part_list_t part_list = {0};\n    TEST_ESP_OK(esp_mbr_parse((void *) mbr, &part_list, NULL));\n    free(mbr);\n\n    esp_ext_part_list_item_t *it;\n    it = esp_ext_part_list_item_head(&part_list);\n    TEST_ASSERT_NOT_NULL(it);\n\n    // Print the partition list\n    print_esp_ext_part_list_items(it);\n    fflush(stdout);\n\n    do {\n        TEST_ASSERT_NOT_EQUAL(0, it->info.address);\n        TEST_ASSERT_NOT_EQUAL(0, it->info.size);\n        TEST_ASSERT_NOT_EQUAL(0, it->info.type);\n    } while ((it = esp_ext_part_list_item_next(it)) != NULL);\n    // Deinitialize the part list\n    esp_ext_part_list_deinit(&part_list);\n    it = NULL;\n    TEST_ASSERT_EQUAL(0, part_list.head.slh_first);\n\n    // Another MBR\n\n    mbr = (mbr_t *) calloc(1, sizeof(mbr_t));\n    TEST_ASSERT_NOT_NULL(mbr);\n\n    esp_mbr_generate_extra_args_t mbr_args = {\n        .sector_size = ESP_EXT_PART_SECTOR_SIZE_512B,\n        .alignment = ESP_EXT_PART_ALIGN_1MiB\n    };\n\n    // 2 FAT12 partitions with same parameters as in the original MBR in the array\n    esp_ext_part_list_item_t item1 = {\n        .info = {\n            .address = 8, // Should be round up to 2048 (aligned to 1MiB) due to defined sector size and alignment in `esp_mbr_generate_extra_args_t args` below\n            .size = esp_ext_part_sector_count_to_bytes(7953, mbr_args.sector_size),\n            .type = ESP_EXT_PART_TYPE_FAT12,\n            .label = NULL,\n        }\n    };\n    esp_ext_part_list_item_t item2 = {\n        .info = {\n            .address = 10000, // Should be round up to 10240 (aligned to 1MiB) due to defined sector size and alignment in `esp_mbr_generate_extra_args_t args` below\n            .size = esp_ext_part_sector_count_to_bytes(2 * 10240, mbr_args.sector_size),\n            .type = ESP_EXT_PART_TYPE_LITTLEFS,\n            .label = NULL,\n            .extra = 4096, // LittleFS block size stored in CHS hack\n            .flags = ESP_EXT_PART_FLAG_EXTRA, // Extra flag set to indicate that the extra field is used\n        }\n    };\n\n    TEST_ESP_OK(esp_ext_part_list_insert(&part_list, &item1));\n    TEST_ESP_OK(esp_ext_part_list_insert(&part_list, &item2));\n\n    // Generate the MBR\n    TEST_ESP_OK(esp_mbr_generate(mbr, &part_list, &mbr_args));\n    // Deinitialize the part list\n    esp_ext_part_list_deinit(&part_list);\n\n    // Parse the MBR\n    TEST_ESP_OK(esp_mbr_parse((void *) mbr, &part_list, NULL));\n    free(mbr);\n\n    // Print the partition list\n    it = esp_ext_part_list_item_head(&part_list);\n    TEST_ASSERT_NOT_NULL(it);\n    print_esp_ext_part_list_items(it);\n    fflush(stdout);\n\n    // Deinitialize the part list\n    esp_ext_part_list_deinit(&part_list);\n    it = NULL;\n}\n\nTEST_CASE(\"Test esp_ext_part_list_signature_t get and set\", \"[esp_ext_part_table]\")\n{\n    esp_ext_part_list_t part_list = {0};\n    TEST_ESP_OK(esp_mbr_parse((void *) mbr_bin, &part_list, NULL));\n    TEST_ASSERT_EQUAL(part_list.signature.type, ESP_EXT_PART_LIST_SIGNATURE_MBR);\n\n    uint32_t disk_signature = 0;\n    uint32_t new_signature = 0x12345678;\n    TEST_ESP_OK(esp_ext_part_list_signature_get(&part_list, &disk_signature));\n    TEST_ASSERT_NOT_EQUAL(disk_signature, new_signature);\n\n    TEST_ESP_OK(esp_ext_part_list_signature_set(&part_list, &new_signature, ESP_EXT_PART_LIST_SIGNATURE_MBR));\n    TEST_ESP_OK(esp_ext_part_list_signature_get(&part_list, &disk_signature));\n    TEST_ASSERT_EQUAL(disk_signature, new_signature);\n\n    // Deinitialize the part list\n    TEST_ESP_OK(esp_ext_part_list_deinit(&part_list));\n}\n\nTEST_CASE(\"Test esp_mbr_partition_set and esp_mbr_remove_gaps_between_partiton_entries\", \"[esp_ext_part_table]\")\n{\n    esp_ext_part_list_t part_list = {0};\n\n    esp_mbr_generate_extra_args_t mbr_args = {\n        .sector_size = ESP_EXT_PART_SECTOR_SIZE_512B,\n        .alignment = ESP_EXT_PART_ALIGN_1MiB\n    };\n\n    // 4 FAT12 partitions\n    esp_ext_part_list_item_t item = {\n        .info = {\n            .size = 10 * 1024 * 1024, // 10 MiB\n            .type = ESP_EXT_PART_TYPE_FAT12,\n        }\n    };\n\n    for (int i = 0; i < 4; i++) {\n        item.info.address = 1024 * 1024 + i * item.info.size; // First partition starts at 1 MiB offset, next partitions are 10 MiB apart\n        TEST_ESP_OK(esp_ext_part_list_insert(&part_list, &item));\n    }\n\n    printf(\"Partition list after creation:\\n\");\n    esp_ext_part_list_item_t *it = esp_ext_part_list_item_head(&part_list);\n    TEST_ASSERT_NOT_NULL(it);\n    print_esp_ext_part_list_items(it);\n    fflush(stdout);\n\n    // Generate the MBR\n    mbr_t *mbr = (mbr_t *) calloc(1, sizeof(mbr_t));\n    TEST_ASSERT_NOT_NULL(mbr);\n\n    TEST_ESP_OK(esp_mbr_generate(mbr, &part_list, &mbr_args));\n    // Deinitialize the part list\n    TEST_ESP_OK(esp_ext_part_list_deinit(&part_list));\n\n    // Create gaps in MBR at index 1 and 2\n    // This will remove the second and third partitions from the MBR\n    esp_ext_part_list_item_t empty_item = {\n        .info = {\n            .type = ESP_EXT_PART_TYPE_NONE, // No type\n        }\n    };\n    esp_mbr_partition_set(mbr, 1, &empty_item, &mbr_args);\n    esp_mbr_partition_set(mbr, 2, &empty_item, &mbr_args);\n    printf(\"Partition 1 and 2 removed, 0 and 3 remained, gaps created\\n\\n\");\n\n    // Parse the MBR to get the partition list without removing the gaps\n    esp_ext_part_list_t part_list_from_mbr = {0};\n    TEST_ESP_OK(esp_mbr_parse((void *) mbr, &part_list_from_mbr, NULL));\n\n    it = esp_ext_part_list_item_head(&part_list_from_mbr);\n    TEST_ASSERT_NOT_NULL(it);\n    int partition_count = 1;\n    while ((it = esp_ext_part_list_item_next(it)) != NULL) {\n        partition_count++;\n    }\n    TEST_ASSERT_EQUAL(partition_count, 1);\n\n    // Print the partition list\n    printf(\"Partition list after creating gaps (partition 3 is missing because the gaps were created and not shifted out):\\n\");\n    it = esp_ext_part_list_item_head(&part_list_from_mbr);\n    TEST_ASSERT_NOT_NULL(it);\n    print_esp_ext_part_list_items(it);\n    fflush(stdout);\n\n    // Deinitialize the part list\n    TEST_ESP_OK(esp_ext_part_list_deinit(&part_list_from_mbr));\n\n    // Now remove the gaps between partition entries\n    esp_mbr_remove_gaps_between_partiton_entries(mbr);\n    // Parse the MBR to get the partition list with gaps removed\n    esp_ext_part_list_t part_list_from_mbr_correct = {0};\n    TEST_ESP_OK(esp_mbr_parse((void *) mbr, &part_list_from_mbr_correct, NULL));\n    free(mbr);\n\n    // Now the partition list should contain 2 partitions (originally partition 0 and 3, now partition 0 and 1)\n    it = esp_ext_part_list_item_head(&part_list_from_mbr_correct);\n    TEST_ASSERT_NOT_NULL(it);\n    partition_count = 1;\n    while ((it = esp_ext_part_list_item_next(it)) != NULL) {\n        partition_count++;\n    }\n    TEST_ASSERT_EQUAL(partition_count, 2);\n\n    // Print the partition list\n    printf(\"Partition list after removing gaps (partition 0 stayed the same, partition 3 was shifted and now is partition 1):\\n\");\n    it = esp_ext_part_list_item_head(&part_list_from_mbr_correct);\n    TEST_ASSERT_NOT_NULL(it);\n    print_esp_ext_part_list_items(it);\n    fflush(stdout);\n\n    // Deinitialize the part list\n    TEST_ESP_OK(esp_ext_part_list_deinit(&part_list_from_mbr_correct));\n}\n\n#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0))\n#include \"esp_blockdev.h\"\n\n// BDL simulated block device implementation for testing\n\nstatic esp_err_t bdl_simulated_read(esp_blockdev_handle_t handle, uint8_t *dst_buf, size_t dst_buf_size, uint64_t src_addr, size_t data_read_len)\n{\n    if (handle == NULL || dst_buf == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    uint8_t *buffer = (uint8_t *) handle->ctx;\n\n    if (src_addr + data_read_len > handle->geometry.disk_size || data_read_len > dst_buf_size) {\n        return ESP_ERR_INVALID_SIZE;\n    }\n\n    memcpy(dst_buf, buffer + src_addr, data_read_len);\n    return ESP_OK;\n}\n\nstatic esp_err_t bdl_simulated_write(esp_blockdev_handle_t handle, const uint8_t *src_buf, uint64_t dst_addr, size_t data_write_len)\n{\n    if (handle == NULL || src_buf == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    uint8_t *buffer = (uint8_t *) handle->ctx;\n\n    if (dst_addr + data_write_len > handle->geometry.disk_size) {\n        return ESP_ERR_INVALID_SIZE;\n    }\n\n    memcpy(buffer + dst_addr, src_buf, data_write_len);\n    return ESP_OK;\n}\n\nstatic esp_err_t bdl_simulated_release_blockdev(esp_blockdev_handle_t handle)\n{\n    if (handle != NULL) {\n        free(handle);\n    }\n    return ESP_OK;\n}\n\nstatic const esp_blockdev_ops_t bdl_simulated_blockdev_ops = {\n    .read = bdl_simulated_read,\n    .write = bdl_simulated_write,\n    .erase = NULL, // Not recommended to leave as NULL; just for test purposes\n    .ioctl = NULL,\n    .sync = NULL,\n    .release = bdl_simulated_release_blockdev,\n};\n\nstatic esp_err_t bdl_simulated_get_blockdev(uint8_t *buffer, size_t buffer_size, esp_blockdev_handle_t *out_handle)\n{\n    if (buffer == NULL || out_handle == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    esp_blockdev_handle_t out = (esp_blockdev_handle_t) calloc(1, sizeof(esp_blockdev_t));\n    if (out == NULL) {\n        return ESP_ERR_NO_MEM;\n    }\n    out->ctx = (void *) buffer;\n\n    out->device_flags.default_val_after_erase = 0;\n\n    out->geometry.disk_size = buffer_size;\n    out->geometry.read_size = 1;\n    out->geometry.write_size = 1;\n    out->geometry.erase_size = 1;\n\n    out->ops = &bdl_simulated_blockdev_ops;\n\n    *out_handle = out;\n    return ESP_OK;\n}\n\nTEST_CASE(\"Test with BDL (simulated in RAM) - basic operations\", \"[esp_ext_part_table]\")\n{\n    size_t buffer_size = 3 * 1024;\n    uint8_t *buffer = (uint8_t *) malloc(buffer_size);\n    TEST_ASSERT_NOT_NULL(buffer);\n    esp_blockdev_handle_t handle = NULL;\n    esp_err_t err = bdl_simulated_get_blockdev(buffer, buffer_size, &handle);\n    TEST_ESP_OK(err);\n    TEST_ASSERT_NOT_NULL(handle);\n\n    size_t sector_size = 512;\n\n    // Write As to the first sector\n    uint8_t buf[] = {[0 ... 511] = 'A'}; // Fill buffer with 'A'\n    err = handle->ops->write(handle, buf, 0, sector_size);\n    TEST_ESP_OK(err);\n\n    uint8_t read_buf[512] = {0};\n    err = handle->ops->read(handle, read_buf, sector_size, 0, sector_size);\n    TEST_ESP_OK(err);\n    TEST_ASSERT_EQUAL_MEMORY(buf, read_buf, sizeof(buf));\n\n    // Write Bs to the emulated \"first sector\" (0 + start sector offset (2) == sector size (512) * 2)\n    {\n        uint8_t buf2[] = {[0 ... 511] = 'B'}; // Fill buffer with 'B'\n        err = handle->ops->write(handle, buf2, sector_size * 2, sector_size);\n        TEST_ESP_OK(err);\n\n        err = handle->ops->read(handle, read_buf, sector_size, sector_size * 2, sector_size);\n        TEST_ESP_OK(err);\n        TEST_ASSERT_EQUAL_MEMORY(buf2, read_buf, sizeof(buf2));\n    }\n\n    // Read the first sector again, it should be 'A's\n    err = handle->ops->read(handle, read_buf, sector_size, 0, sector_size);\n    TEST_ESP_OK(err);\n    TEST_ASSERT_EQUAL_MEMORY(buf, read_buf, sizeof(buf));\n\n    // Visualize the first 5 sectors\n    for (int i = 0; i < 5; i++) {\n        // Read the first sector, it should be 'A's\n        err = handle->ops->read(handle, read_buf, sector_size, sector_size * i, sector_size);\n        TEST_ESP_OK(err);\n        for (int j = 0; j < sizeof(read_buf); j++) {\n            printf(\"%c\", read_buf[j]);\n        }\n        printf(\"\\n\");\n        fflush(stdout);\n    }\n\n    handle->ops->release(handle);\n    handle = NULL;\n    free(buffer);\n    buffer = NULL;\n}\n\nTEST_CASE(\"Test with BDL (simulated in RAM) - MBR related\", \"[esp_ext_part_table]\")\n{\n    size_t buffer_size = 512;\n    uint8_t *buffer = (uint8_t *) malloc(buffer_size);\n    TEST_ASSERT_NOT_NULL(buffer);\n    esp_blockdev_handle_t handle = NULL;\n    esp_err_t err = bdl_simulated_get_blockdev(buffer, buffer_size, &handle);\n    TEST_ESP_OK(err);\n    TEST_ASSERT_NOT_NULL(handle);\n\n    err = handle->ops->write(handle, mbr_bin, 0, mbr_bin_len);\n    TEST_ESP_OK(err);\n\n    esp_mbr_parse_extra_args_t mbr_parse_args = {\n        .sector_size = ESP_EXT_PART_SECTOR_SIZE_512B\n    };\n\n    esp_ext_part_list_t part_list = {0};\n    esp_ext_part_list_item_t *it = NULL;\n    err = esp_ext_part_list_bdl_read(handle, &part_list, ESP_EXT_PART_LIST_SIGNATURE_MBR, (void *) &mbr_parse_args);\n    TEST_ESP_OK(err);\n\n    it = esp_ext_part_list_item_head(&part_list);\n    TEST_ASSERT_NOT_NULL(it);\n    printf(\"Partition list read from BDL simulated MBR:\\n\");\n    print_esp_ext_part_list_items(it);\n    fflush(stdout);\n\n    esp_mbr_generate_extra_args_t mbr_gen_args = {\n        .sector_size = ESP_EXT_PART_SECTOR_SIZE_512B,\n        .alignment = ESP_EXT_PART_ALIGN_1MiB\n    };\n\n    esp_ext_part_list_item_t partition_for_insertion = {\n        .info = {\n            .address = esp_ext_part_sector_count_to_bytes(20480, mbr_gen_args.sector_size), // 10 MiB offset\n            .size = 10 * 1024 * 1024, // 10 MiB\n            .type = ESP_EXT_PART_TYPE_LITTLEFS,\n            .extra = 4096, // LittleFS block size stored in CHS hack\n            .flags = ESP_EXT_PART_FLAG_EXTRA, // Extra flag set to indicate that the extra field is used\n        }\n    };\n    TEST_ESP_OK(esp_ext_part_list_insert(&part_list, &partition_for_insertion));\n\n    err = esp_ext_part_list_bdl_write(handle, &part_list, ESP_EXT_PART_LIST_SIGNATURE_MBR, (void *) &mbr_gen_args);\n    TEST_ESP_OK(err);\n\n    TEST_ESP_OK(esp_ext_part_list_deinit(&part_list));\n\n    err = esp_ext_part_list_bdl_read(handle, &part_list, ESP_EXT_PART_LIST_SIGNATURE_MBR, (void *) &mbr_parse_args);\n    TEST_ESP_OK(err);\n\n    it = esp_ext_part_list_item_head(&part_list);\n    TEST_ASSERT_NOT_NULL(it);\n    printf(\"Partition list after writing new partition to BDL simulated MBR:\\n\");\n    print_esp_ext_part_list_items(it);\n    fflush(stdout);\n\n    TEST_ESP_OK(esp_ext_part_list_deinit(&part_list));\n}\n#endif // (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0))\n\nvoid app_main(void)\n{\n    printf(\"Running esp_ext_part_tables component tests\\n\");\n    unity_run_menu();\n}\n"
  },
  {
    "path": "esp_ext_part_tables/test_apps/pytest_esp_ext_part_tables.py",
    "content": "# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.utils import idf_parametrize\n\n\n@pytest.mark.host_test\n@idf_parametrize('target', ['linux'], indirect=['target'])\ndef test_esp_ext_part_tables(dut: Dut) -> None:\n    dut.run_all_single_board_cases()\n"
  },
  {
    "path": "esp_ext_part_tables/test_apps/sdkconfig.defaults",
    "content": "\n# ignore task watchdog triggered by unity_run_menu\nCONFIG_ESP_TASK_WDT_INIT=n\n"
  },
  {
    "path": "esp_flash_dispatcher/.build-test-rules.yml",
    "content": "esp_flash_dispatcher/test_apps:\n  disable:\n    - if: SOC_SPIRAM_XIP_SUPPORTED != 1\n      reason: \"This feature is only necessary on chips which have PSRAM, and can XIP from PSRAM\"\n    - if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR < 2\n      reason: IDF version below v5.2 is not supported\n"
  },
  {
    "path": "esp_flash_dispatcher/CMakeLists.txt",
    "content": "set(includes \"include\")\n\nidf_component_register(SRCS \"esp_flash_dispatcher.c\"\n                       INCLUDE_DIRS ${includes}\n                       PRIV_REQUIRES \"spi_flash\" \"freertos\" \"esp_system\"\n                       )\n\nset(WRAP_FUNCTIONS\n    esp_flash_write\n    esp_flash_erase_region\n    esp_flash_read\n    esp_flash_erase_chip\n    esp_flash_write_encrypted)\n\nforeach(wrap ${WRAP_FUNCTIONS})\n    target_link_libraries(${COMPONENT_LIB} INTERFACE \"-Wl,--wrap=${wrap}\")\nendforeach()\n"
  },
  {
    "path": "esp_flash_dispatcher/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "esp_flash_dispatcher/README.md",
    "content": "## Overview\n\nWhen a task stack resides in PSRAM, invoking `esp_flash_*` directly in that task can cause crashes during moments when the Flash driver temporarily disables the CPU cache (resulting in the PSRAM stack being inaccessible). Typical failures include Cache errors and Guru Meditation.\n\nThe `esp_flash_dispatcher` component intercepts common Flash APIs and executes the real Flash operations in a dedicated background task whose stack lives in internal RAM. This guarantees that even while cache is disabled, Flash operations run on an always-accessible stack. Therefore, application tasks can keep their stacks in PSRAM without worrying about Flash operations breaking them.\n\n## Usage\n\n1. Add esp_flash_dispatcher component to your project: `idf.py add-dependency espressif/esp_flash_dispatcher`\n2. Initialize esp_flash_dispatcher in app_main:\n\n    ```c\n    #include \"esp_flash_dispatcher.h\"\n    \n    const esp_flash_dispatcher_config_t cfg = {\n        .task_stack_size = 2048,\n        .task_priority = 10,\n        .task_core_id = tskNO_AFFINITY,\n        .queue_size = 5,\n    };\n    ESP_ERROR_CHECK(esp_flash_dispatcher_init(&cfg));\n    ```\n    \n3. Now you can call any API which writes or reads SPI Flash from a task with the stack in PSRAM, no other changes are required.\n"
  },
  {
    "path": "esp_flash_dispatcher/esp_flash_dispatcher.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include <stdbool.h>\n#include <string.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"freertos/queue.h\"\n#include \"freertos/semphr.h\"\n#include \"esp_log.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_flash_spi_init.h\"\n#include \"esp_private/startup_internal.h\"\n#include \"esp_check.h\"\n#include \"esp_flash_dispatcher.h\"\n\nstatic const char *TAG = \"flash_dispatcher\";\n\nextern esp_err_t __real_esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t size);\nextern esp_err_t __real_esp_flash_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t size);\nextern esp_err_t __real_esp_flash_erase_region(esp_flash_t *chip, uint32_t start_address, uint32_t size);\nextern esp_err_t __real_esp_flash_erase_chip(esp_flash_t *chip);\nextern esp_err_t __real_esp_flash_write_encrypted(esp_flash_t *chip, uint32_t address, const void *buffer, uint32_t length);\n\n// Operation type for flash requests\ntypedef enum {\n    FLASH_OP_READ = 0,\n    FLASH_OP_WRITE,\n    FLASH_OP_WRITE_ENCRYPTED,\n    FLASH_OP_ERASE_REGION,\n    FLASH_OP_ERASE_CHIP,\n} flash_operation_t;\n\n// Structure to hold flash operation requests\ntypedef struct {\n    esp_flash_t *chip;\n    flash_operation_t op;            // Operation type to execute\n    union {\n        struct {\n            void *buffer;\n            uint32_t address;\n            size_t size;\n        } read;                 // for FLASH_OP_READ\n        struct {\n            const void *buffer;\n            uint32_t address;\n            size_t size;\n        } write;          // for FLASH_OP_WRITE\n        struct {\n            uint32_t address;\n            const void *buffer;\n            size_t size;\n        } write_encrypted;// for FLASH_OP_WRITE_ENCRYPTED\n        struct {\n            uint32_t start_address;\n            size_t size;\n        } erase_region;                 // for FLASH_OP_ERASE_REGION\n    } args;\n} flash_operation_request_t;\n\ntypedef struct {\n    QueueHandle_t queue;\n    TaskHandle_t task;\n    bool dispatcher_initialized;\n    QueueHandle_t result_queue;\n} flash_dispatcher_context_t;\n\n// Configuration struct is declared in public header\n\nstatic flash_dispatcher_context_t s_flash_dispatcher_ctx;\n\nstatic void flash_dispatcher_task(void *arg)\n{\n    flash_operation_request_t request;\n    esp_err_t result;\n\n    while (true) {\n        if (xQueueReceive(s_flash_dispatcher_ctx.queue, &request, portMAX_DELAY) == pdTRUE) {\n            // Execute the actual flash operation based on the operation type and arguments\n            switch (request.op) {\n            case FLASH_OP_READ:\n                result = __real_esp_flash_read(request.chip,\n                                               request.args.read.buffer,\n                                               request.args.read.address,\n                                               request.args.read.size);\n                break;\n            case FLASH_OP_WRITE:\n                result = __real_esp_flash_write(request.chip,\n                                                request.args.write.buffer,\n                                                request.args.write.address,\n                                                request.args.write.size);\n                break;\n            case FLASH_OP_WRITE_ENCRYPTED:\n                result = __real_esp_flash_write_encrypted(request.chip,\n                         request.args.write_encrypted.address,\n                         request.args.write_encrypted.buffer,\n                         request.args.write_encrypted.size);\n                break;\n            case FLASH_OP_ERASE_REGION:\n                result = __real_esp_flash_erase_region(request.chip,\n                                                       request.args.erase_region.start_address,\n                                                       request.args.erase_region.size);\n                break;\n            case FLASH_OP_ERASE_CHIP:\n                result = __real_esp_flash_erase_chip(request.chip);\n                break;\n            default:\n                ESP_EARLY_LOGE(TAG, \"Unsupported flash operation type: %d\", (int)request.op);\n                result = ESP_FAIL;\n                break;\n            }\n            // Publish result and signal completion to the waiting caller\n            if (xQueueSend(s_flash_dispatcher_ctx.result_queue, &result, portMAX_DELAY) != pdTRUE) {\n                ESP_EARLY_LOGE(TAG, \"Failed to send result to queue\");\n            }\n        }\n    }\n}\n\nesp_err_t esp_flash_dispatcher_init(const esp_flash_dispatcher_config_t *cfg)\n{\n    if (s_flash_dispatcher_ctx.queue != NULL || s_flash_dispatcher_ctx.task != NULL) {\n        ESP_EARLY_LOGE(TAG, \"flash dispatcher already initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    s_flash_dispatcher_ctx.queue = xQueueCreateWithCaps(cfg->queue_size, sizeof(flash_operation_request_t), MALLOC_CAP_INTERNAL);\n    ESP_RETURN_ON_FALSE(s_flash_dispatcher_ctx.queue, ESP_ERR_NO_MEM, TAG, \"create flash operation queue failed\");\n\n    s_flash_dispatcher_ctx.result_queue = xQueueCreateWithCaps(cfg->queue_size, sizeof(esp_err_t), MALLOC_CAP_INTERNAL);\n    if (s_flash_dispatcher_ctx.result_queue == NULL) {\n        vQueueDeleteWithCaps(s_flash_dispatcher_ctx.queue);\n        ESP_EARLY_LOGE(TAG, \"Failed to create completion semaphore\");\n        return ESP_ERR_NO_MEM;\n    }\n\n    BaseType_t rc = xTaskCreatePinnedToCoreWithCaps(flash_dispatcher_task,\n                    \"flash_dispatcher\",\n                    cfg->task_stack_size,\n                    NULL,\n                    cfg->task_priority,\n                    &s_flash_dispatcher_ctx.task,\n                    cfg->task_core_id,\n                    MALLOC_CAP_INTERNAL);\n\n    if (rc != pdPASS) {\n        // Cleanup resources if task creation failed\n        vQueueDeleteWithCaps(s_flash_dispatcher_ctx.queue);\n        s_flash_dispatcher_ctx.queue = NULL;\n        vQueueDeleteWithCaps(s_flash_dispatcher_ctx.result_queue);\n        s_flash_dispatcher_ctx.result_queue = NULL;\n        ESP_EARLY_LOGE(TAG, \"create flash dispatcher task failed\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    s_flash_dispatcher_ctx.dispatcher_initialized = true;\n\n    return ESP_OK;\n}\n\n/**\n * Send a flash operation request to the dispatcher queue and wait for the result.\n * The meaning and order of arg1/arg2/arg3 must match what the dispatcher task expects\n * for the given operation type. This helper centralizes the common send/wait logic.\n */\nstatic esp_err_t flash_dispatcher_execute(flash_operation_t op,\n        esp_flash_t *chip,\n        void *arg1,\n        void *arg2,\n        void *arg3,\n        const char *op_name)\n{\n    ESP_RETURN_ON_FALSE(s_flash_dispatcher_ctx.dispatcher_initialized, ESP_ERR_INVALID_STATE, TAG, \"flash dispatcher is not initialized\");\n\n    esp_err_t operation_result = ESP_FAIL;\n    flash_operation_request_t request = { 0 };\n    request.chip = chip;\n    request.op = op;\n    switch (op) {\n    case FLASH_OP_READ:\n        request.args.read.buffer = arg1;\n        request.args.read.address = (uint32_t)(uintptr_t)arg2;\n        request.args.read.size = (size_t)(uintptr_t)arg3;\n        break;\n    case FLASH_OP_WRITE:\n        request.args.write.buffer = arg1;\n        request.args.write.address = (uint32_t)(uintptr_t)arg2;\n        request.args.write.size = (size_t)(uintptr_t)arg3;\n        break;\n    case FLASH_OP_WRITE_ENCRYPTED:\n        request.args.write_encrypted.address = (uint32_t)(uintptr_t)arg1;\n        request.args.write_encrypted.buffer = arg2;\n        request.args.write_encrypted.size = (size_t)(uintptr_t)arg3;\n        break;\n    case FLASH_OP_ERASE_REGION:\n        request.args.erase_region.start_address = (uint32_t)(uintptr_t)arg1;\n        request.args.erase_region.size = (size_t)(uintptr_t)arg2;\n        break;\n    case FLASH_OP_ERASE_CHIP:\n    default:\n        break;\n    }\n\n    if (xQueueSend(s_flash_dispatcher_ctx.queue, &request, portMAX_DELAY) != pdTRUE) {\n        ESP_EARLY_LOGE(TAG, \"Failed to send %s request to queue\", op_name ? op_name : \"flash\");\n        return ESP_ERR_TIMEOUT;\n    }\n\n    if (xQueueReceive(s_flash_dispatcher_ctx.result_queue, &operation_result, portMAX_DELAY) != pdTRUE) {\n        ESP_EARLY_LOGE(TAG, \"Failed to receive %s result from queue\", op_name ? op_name : \"flash\");\n        return ESP_ERR_TIMEOUT;\n    }\n    return operation_result;\n}\n\nesp_err_t __wrap_esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t size)\n{\n    return flash_dispatcher_execute(FLASH_OP_READ,\n                                    chip,\n                                    (void *)buffer,\n                                    (void *)address,\n                                    (void *)size,\n                                    \"flash read\");\n}\n\nesp_err_t __wrap_esp_flash_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t size)\n{\n    return flash_dispatcher_execute(FLASH_OP_WRITE,\n                                    chip,\n                                    (void *)buffer,\n                                    (void *)address,\n                                    (void *)size,\n                                    \"flash write\");\n}\n\nesp_err_t __wrap_esp_flash_write_encrypted(esp_flash_t *chip, uint32_t address, const void *buffer, uint32_t size)\n{\n    return flash_dispatcher_execute(FLASH_OP_WRITE_ENCRYPTED,\n                                    chip,\n                                    (void *)address,\n                                    (void *)buffer,\n                                    (void *)size,\n                                    \"flash write_encrypted\");\n}\n\nesp_err_t __wrap_esp_flash_erase_region(esp_flash_t *chip, uint32_t start_address, uint32_t size)\n{\n    return flash_dispatcher_execute(FLASH_OP_ERASE_REGION,\n                                    chip,\n                                    (void *)start_address,\n                                    (void *)size,\n                                    NULL,\n                                    \"flash erase_region\");\n}\n\nesp_err_t __wrap_esp_flash_erase_chip(esp_flash_t *chip)\n{\n    return flash_dispatcher_execute(FLASH_OP_ERASE_CHIP,\n                                    chip,\n                                    NULL,\n                                    NULL,\n                                    NULL,\n                                    \"flash erase_chip\");\n}\n"
  },
  {
    "path": "esp_flash_dispatcher/idf_component.yml",
    "content": "version: \"1.0.0\"\ndescription: This component allows flash operations to be performed by tasks with stacks in PSRAM.\nurl: https://github.com/espressif/idf-extra-components/tree/master/esp_flash_dispatcher\nrepository: https://github.com/espressif/idf-extra-components.git\nissues: https://github.com/espressif/idf-extra-components/issues\ndependencies:\n  idf: \">=5.2\"\n"
  },
  {
    "path": "esp_flash_dispatcher/include/esp_flash_dispatcher.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdint.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"esp_err.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* Configuration for the flash dispatcher task.\n * The dispatcher serializes flash operations to a dedicated task.\n */\ntypedef struct {\n    uint32_t task_stack_size;   // Stack size for the dedicated flash task (in bytes)\n    uint32_t task_priority;     // Priority for the dedicated flash task\n    BaseType_t task_core_id;    // Core affinity (PRO_CPU_NUM, APP_CPU_NUM, or tskNO_AFFINITY)\n    uint32_t queue_size;        // Length of the request queue\n} esp_flash_dispatcher_config_t;\n\n/**\n * @brief Default configuration to init flash dispatcher\n */\n#define ESP_FLASH_DISPATCHER_DEFAULT_CONFIG   {   \\\n    .task_stack_size = 2048,                       \\\n    .task_priority = 10,                  \\\n    .task_core_id = tskNO_AFFINITY,                      \\\n    .queue_size = 1,                              \\\n}\n\n/**\n * @brief Initialize flash dispatcher.\n *\n * @param[in]  cfg: Configuration structure\n *\n * @return\n *      - ESP_OK            on success\n *      - ESP_ERR_NO_MEM    if there is no memory for allocating main structure\n *      - ESP_ERR_INVALID_STATE    if the dispatcher is already initialized\n */\nesp_err_t esp_flash_dispatcher_init(const esp_flash_dispatcher_config_t *cfg);\n\n#ifdef __cplusplus\n}\n#endif\n\n\n"
  },
  {
    "path": "esp_flash_dispatcher/test_apps/CMakeLists.txt",
    "content": "# This is the project CMakeLists.txt file for the test subproject\n\ncmake_minimum_required(VERSION 3.16)\n\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(test_esp_flash_dispatcher)\n"
  },
  {
    "path": "esp_flash_dispatcher/test_apps/README.md",
    "content": "| Supported Targets | ESP32-C5 | ESP32-C61 | ESP32-H4 | ESP32-P4 | ESP32-S3 |\n| ----------------- | -------- | --------- | -------- | -------- | -------- |\n"
  },
  {
    "path": "esp_flash_dispatcher/test_apps/main/CMakeLists.txt",
    "content": "set(srcs \"test_app_main.c\"\n         \"test_esp_flash_dispatcher.c\")\n\n# In order for the cases defined by `TEST_CASE` to be linked into the final elf,\n# the component can be registered as WHOLE_ARCHIVE\nidf_component_register(SRCS ${srcs}\n                       PRIV_REQUIRES unity spi_flash esp_psram esp_partition esp_flash_dispatcher\n                       INCLUDE_DIRS \".\"\n                       WHOLE_ARCHIVE)\n"
  },
  {
    "path": "esp_flash_dispatcher/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/esp_flash_dispatcher:\n    version: \"*\"\n    override_path: \"../..\"\n"
  },
  {
    "path": "esp_flash_dispatcher/test_apps/main/test_app_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"unity.h\"\n#include \"unity_test_utils.h\"\n#include \"esp_heap_caps.h\"\n\n// The source allocated in esp_flash_dispatcher test is large, and these memory should never be freed.\n#define TEST_MEMORY_LEAK_THRESHOLD (3300)\n\nvoid setUp(void)\n{\n    unity_utils_record_free_mem();\n}\n\nvoid tearDown(void)\n{\n    unity_utils_evaluate_leaks_direct(TEST_MEMORY_LEAK_THRESHOLD);\n}\n\nvoid app_main(void)\n{\n    unity_run_menu();\n}\n"
  },
  {
    "path": "esp_flash_dispatcher/test_apps/main/test_esp_flash_dispatcher.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n#include <stdio.h>\n#include <string.h>\n#include <inttypes.h>\n#include <freertos/FreeRTOS.h>\n#include <freertos/task.h>\n#include <freertos/semphr.h>\n\n#include <unity.h>\n#include \"esp_flash.h\"\n#include <esp_attr.h>\n#include \"esp_log.h\"\n#include \"unity.h\"\n#include \"sdkconfig.h\"\n#include \"esp_flash_dispatcher.h\"\n#include \"esp_partition.h\"\n\n// Buffer for PSRAM task stack\nstatic StackType_t *s_psram_task_stack = NULL;\n\n#define TEST_FLASH_ADDRESS 0x110000 // default address in flash for testing\n#define TEST_FLASH_SIZE 4096\n#define TEST_PSRAM_TASK_STACK_SIZE 4096\n\nstatic const esp_partition_t *get_test_data_partition(void)\n{\n    /* This finds \"flash_test\" partition defined in partition_table_unit_test_app.csv */\n    const esp_partition_t *result = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,\n                                    ESP_PARTITION_SUBTYPE_ANY, \"flash_test\");\n    TEST_ASSERT_NOT_NULL(result); /* means partition table set wrong */\n    return result;\n}\n\n// The PSRAM task will take the creating task's handle as argument to notify it upon completion\nstatic void psram_flash_test_task(void *arg)\n{\n    const esp_partition_t *test_part = get_test_data_partition();\n    TaskHandle_t creating_task_handle = (TaskHandle_t)arg;\n\n    ESP_LOGI(\"PSRAM_TASK\", \"PSRAM task started on core %d\", xPortGetCoreID());\n    esp_err_t ret;\n\n    uint8_t *write_buf = (uint8_t *)heap_caps_malloc(TEST_FLASH_SIZE, MALLOC_CAP_INTERNAL);\n    uint8_t *read_buf = (uint8_t *)heap_caps_malloc(TEST_FLASH_SIZE, MALLOC_CAP_INTERNAL);\n    TEST_ASSERT_NOT_NULL(write_buf);\n    TEST_ASSERT_NOT_NULL(read_buf);\n\n    // Fill write buffer with some pattern\n    for (int i = 0; i < TEST_FLASH_SIZE; i++) {\n        write_buf[i] = (uint8_t)(i % 256);\n    }\n    ESP_LOGI(\"PSRAM_TASK\", \"Performing flash erase at 0x%lx, size 0x%x\", test_part->address, TEST_FLASH_SIZE);\n    ret = esp_flash_erase_region(NULL, test_part->address, 4096);\n    TEST_ASSERT_EQUAL(ESP_OK, ret);\n    ESP_LOGI(\"PSRAM_TASK\", \"Flash erase successful.\");\n\n    ESP_LOGI(\"PSRAM_TASK\", \"Performing flash write to 0x%lx, size 0x%x\", test_part->address, TEST_FLASH_SIZE);\n    ret = esp_flash_write(NULL, write_buf, test_part->address, TEST_FLASH_SIZE);\n    TEST_ASSERT_EQUAL(ESP_OK, ret);\n    ESP_LOGI(\"PSRAM_TASK\", \"Flash write successful.\");\n\n    ESP_LOGI(\"PSRAM_TASK\", \"Performing flash read from 0x%lx, size 0x%x\", test_part->address, TEST_FLASH_SIZE);\n    ret = esp_flash_read(NULL, read_buf, test_part->address, TEST_FLASH_SIZE);\n    TEST_ASSERT_EQUAL(ESP_OK, ret);\n    ESP_LOGI(\"PSRAM_TASK\", \"Flash read successful.\");\n\n    // Verify data\n    TEST_ASSERT_EQUAL_HEX8_ARRAY(write_buf, read_buf, TEST_FLASH_SIZE);\n    ESP_LOGI(\"PSRAM_TASK\", \"Flash read data verified successfully.\");\n\n    heap_caps_free(write_buf);\n    heap_caps_free(read_buf);\n\n    // Notify the creating task that this task has completed\n    xTaskNotifyGive(creating_task_handle);\n\n    vTaskDelete(NULL);\n}\n\nTEST_CASE(\"Flash operations from PSRAM task\", \"[flash_dispatcher]\")\n{\n    // Use default configuration when cfg is NULL\n    const esp_flash_dispatcher_config_t cfg = ESP_FLASH_DISPATCHER_DEFAULT_CONFIG;\n    esp_flash_dispatcher_init(&cfg);\n\n    ESP_LOGI(\"TEST\", \"Creating PSRAM task\");\n    s_psram_task_stack = (StackType_t *)heap_caps_malloc(TEST_PSRAM_TASK_STACK_SIZE, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);\n    TEST_ASSERT_NOT_NULL(s_psram_task_stack);\n\n    TaskHandle_t psram_task_handle;\n    xTaskCreatePinnedToCore(\n        psram_flash_test_task,\n        \"psram_flash_test\",\n        TEST_PSRAM_TASK_STACK_SIZE, // The size here is in bytes for dynamic allocation\n        (void *)xTaskGetCurrentTaskHandle(), // Pass the current task handle as argument\n        5, // Priority\n        &psram_task_handle,\n        0 // Run on APP_CPU if available, otherwise PRO_CPU\n    );\n    TEST_ASSERT_NOT_NULL(psram_task_handle);\n\n    // Wait for the PSRAM task to complete\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    vTaskDelay(2);\n\n    heap_caps_free(s_psram_task_stack);\n    s_psram_task_stack = NULL;\n}\n"
  },
  {
    "path": "esp_flash_dispatcher/test_apps/partitions.csv",
    "content": "# Name,     Type, SubType, Offset,   Size, Flags\n# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap\nnvs,        data, nvs,      0x9000,  0x6000,\nfactory,    0,    0,        0x10000, 1M\nflash_test, data, fat,      ,        700K\n"
  },
  {
    "path": "esp_flash_dispatcher/test_apps/pytest_flash_dispatcher.py",
    "content": "# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.utils import idf_parametrize\n\n@pytest.mark.quad_psram\n@idf_parametrize('target', ['esp32s3'], indirect=['target'])\ndef test_esp_flash_dispatcher(dut) -> None:\n    dut.run_all_single_board_cases()\n"
  },
  {
    "path": "esp_flash_dispatcher/test_apps/sdkconfig.defaults",
    "content": "CONFIG_ESP_TASK_WDT_INIT=n\nCONFIG_SPIRAM=y\nCONFIG_SPIRAM_XIP_FROM_PSRAM=y\nCONFIG_PARTITION_TABLE_CUSTOM=y\nCONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions.csv\"\n"
  },
  {
    "path": "esp_gcov/.build-test-rules.yml",
    "content": ""
  },
  {
    "path": "esp_gcov/CMakeLists.txt",
    "content": "if(CONFIG_ESP_GCOV_ENABLE)\n    if(NOT CMAKE_C_COMPILER_ID MATCHES \"GNU\")\n        # TODO: LLVM-214\n        message(FATAL_ERROR \"Coverage info is supported only when building with GNU!\")\n    endif()\n\n    # Set a name for Gcov library\n    set(GCOV_LIB libgcov_rtio)\n\n    # Set include directory of Gcov internal headers\n    execute_process(COMMAND ${CMAKE_C_COMPILER} -print-file-name=plugin\n                    OUTPUT_VARIABLE gcc_plugin_dir\n                    OUTPUT_STRIP_TRAILING_WHITESPACE\n                    ERROR_QUIET\n                    RESULT_VARIABLE gcc_plugin_result)\n\n    set_source_files_properties(gcov_rtio.c\n                                PROPERTIES COMPILE_FLAGS \"-I${gcc_plugin_dir}/include\")\n\n    # Copy libgcov.a with symbols redefinition\n    find_library(GCOV_LIBRARY_PATH gcov ${CMAKE_C_IMPLICIT_LINK_DIRECTORIES})\n\n    # Check if libgcov.a was found\n    if(NOT GCOV_LIBRARY_PATH)\n        message(FATAL_ERROR \"GCOV: libgcov.a not found in system directories: ${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}\")\n    endif()\n\n    # Verify libgcov.a file exists and is readable\n    if(NOT EXISTS \"${GCOV_LIBRARY_PATH}\")\n        message(FATAL_ERROR \"GCOV: libgcov.a file does not exist\")\n    endif()\n\n    # Check if symbol map file exists\n    set(SYMBOL_MAP_FILE \"${CMAKE_CURRENT_LIST_DIR}/io_sym.map\")\n\n    # Check if objcopy tool exists\n    find_program(OBJCOPY_TOOL \"${_CMAKE_TOOLCHAIN_PREFIX}objcopy\")\n    if(NOT OBJCOPY_TOOL)\n        message(FATAL_ERROR \"GCOV: objcopy tool not found: ${_CMAKE_TOOLCHAIN_PREFIX}objcopy. \"\n                           \"Make sure your toolchain is properly installed.\")\n    endif()\n\n    add_custom_command(OUTPUT ${GCOV_LIB}.a\n                       COMMAND ${OBJCOPY_TOOL}\n                               --redefine-syms ${SYMBOL_MAP_FILE}\n                               ${GCOV_LIBRARY_PATH} ${GCOV_LIB}.a\n                       COMMAND ${CMAKE_COMMAND} -E echo \"GCOV: Successfully created modified library: ${GCOV_LIB}.a\"\n                       MAIN_DEPENDENCY ${GCOV_LIBRARY_PATH}\n                       DEPENDS ${SYMBOL_MAP_FILE}\n                       VERBATIM\n                       COMMENT \"Creating GCOV library with symbol redefinition\")\n\n    add_custom_target(${GCOV_LIB}_target DEPENDS ${GCOV_LIB}.a)\n    add_library(${GCOV_LIB} STATIC IMPORTED)\n    set_target_properties(${GCOV_LIB}\n                          PROPERTIES\n                          IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/${GCOV_LIB}.a)\n    add_dependencies(${GCOV_LIB} ${GCOV_LIB}_target)\n\n    # Register component with app_trace dependency\n    idf_component_register(SRCS \"gcov_rtio.c\"\n                          REQUIRES \"esp_trace\"\n                          INCLUDE_DIRS \".\")\n\n    # Configure gcov-specific flags\n    target_compile_options(${COMPONENT_LIB} PRIVATE \"-fno-profile-arcs\" \"-fno-test-coverage\")\n    target_link_options(${COMPONENT_LIB} INTERFACE \"-Wl,--wrap=__gcov_init\")\n    target_link_libraries(${COMPONENT_LIB} INTERFACE ${GCOV_LIB} c)\n\n    message(STATUS \"GCOV: Component configured successfully\")\n    message(STATUS \"GCOV: GCC Plugin Dir: ${gcc_plugin_dir}\")\n    message(STATUS \"GCOV: Original Library: ${GCOV_LIBRARY_PATH}\")\n    message(STATUS \"GCOV: Modified Library: ${CMAKE_CURRENT_BINARY_DIR}/${GCOV_LIB}.a\")\n\nelse()\n    # Register empty component when GCOV is disabled\n    idf_component_register(REQUIRES \"esp_trace\")\n    message(STATUS \"GCOV: Component registered but GCOV support is disabled\")\nendif()\n"
  },
  {
    "path": "esp_gcov/Kconfig",
    "content": "menu \"GNU Code Coverage\"\n\n    config ESP_GCOV_ENABLE\n        bool \"GCOV to Host Enable\"\n        depends on ESP_TRACE_TRANSPORT_APPTRACE && ESP_TRACE_LIB_NONE\n        select ESP_DEBUG_STUBS_ENABLE\n        select ESP_IPC_ENABLE\n        default n\n        help\n            Enables support for GCOV data transfer to host.\n\n    config ESP_GCOV_DUMP_TASK_STACK_SIZE\n        int \"Gcov dump task stack size\"\n        depends on ESP_GCOV_ENABLE\n        default 2048\n        help\n            Configures stack size of Gcov dump task\n\nendmenu\n"
  },
  {
    "path": "esp_gcov/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "esp_gcov/README.md",
    "content": "# Gcov (Source Code Coverage)\n\n## Basics of Gcov and Gcovr\n\nSource code coverage is data indicating the count and frequency of every program execution path that has been taken within a program's runtime. [Gcov](https://en.wikipedia.org/wiki/Gcov) is a GCC tool that, when used in concert with the compiler, can generate log files indicating the execution count of each line of a source file. The [Gcovr](https://gcovr.com/) tool is a utility for managing Gcov and generating summarized code coverage results.\n\nGenerally, using Gcov to compile and run programs on the host will undergo these steps:\n\n1. Compile the source code using GCC with the `--coverage` option enabled. This will cause the compiler to generate a `.gcno` notes files during compilation. The notes files contain information to reconstruct execution path block graphs and map each block to source code line numbers. Each source file compiled with the `--coverage` option should have their own `.gcno` file of the same name (e.g., a `main.c` will generate a `main.gcno` when compiled).\n\n2. Execute the program. During execution, the program should generate `.gcda` data files. These data files contain the counts of the number of times an execution path was taken. The program will generate a `.gcda` file for each source file compiled with the `--coverage` option (e.g., `main.c` will generate a `main.gcda`).\n\n3. Gcov or Gcovr can be used to generate a code coverage based on the `.gcno`, `.gcda`, and source files. Gcov will generate a text-based coverage report for each source file in the form of a `.gcov` file, whilst Gcovr will generate a coverage report in HTML format.\n\n## Gcov and Gcovr in ESP-IDF\n\nUsing Gcov in ESP-IDF is complicated due to the fact that the program is running remotely from the host (i.e., on the target). The code coverage data (i.e., the `.gcda` files) is initially stored on the target itself. OpenOCD is then used to dump the code coverage data from the target to the host via JTAG during runtime. Using Gcov in ESP-IDF can be split into the following steps.\n\n1. [Setting Up a Project for Gcov](#setting-up-a-project-for-gcov)\n2. [Dumping Code Coverage Data](#dumping-code-coverage-data)\n3. [Generating Coverage Report](#generating-coverage-report)\n\n## Setting Up a Project for Gcov\n\n### Compiler Option\n\nIn order to obtain code coverage data in a project, one or more source files within the project must be compiled with the `--coverage` option. In ESP-IDF, this can be achieved at the component level or the individual source file level:\n\n- To cause all source files in a component to be compiled with the `--coverage` option, you can add `target_compile_options(${COMPONENT_LIB} PRIVATE --coverage)` to the `CMakeLists.txt` file of the component.\n- To cause a select number of source files (e.g., `source1.c` and `source2.c`) in the same component to be compiled with the `--coverage` option, you can add `set_source_files_properties(source1.c source2.c PROPERTIES COMPILE_FLAGS --coverage)` to the `CMakeLists.txt` file of the component.\n\nWhen a source file is compiled with the `--coverage` option (e.g., `gcov_example.c`), the compiler will generate the `gcov_example.gcno` file in the project's build directory.\n\n### Project Configuration\n\nBefore building a project with source code coverage, make sure that the following project configuration options are enabled by running `idf.py menuconfig`.\n\n- Enable the application tracing module by selecting `Trace Memory` for the `CONFIG_APPTRACE_DESTINATION1` option.\n- Enable Gcov to the host via the `CONFIG_APPTRACE_GCOV_ENABLE`.\n\n## Dumping Code Coverage Data\n\nOnce a project has been complied with the `--coverage` option and flashed onto the target, code coverage data will be stored internally on the target (i.e., in trace memory) whilst the application runs. The process of transferring code coverage data from the target to the host is known as dumping.\n\nThe dumping of coverage data is done via OpenOCD (see JTAG Debugging documentation on how to setup and run OpenOCD). A dump is triggered by issuing commands to OpenOCD, therefore a telnet session to OpenOCD must be opened to issue such commands (run `telnet localhost 4444`). Note that GDB could be used instead of telnet to issue commands to OpenOCD, however all commands issued from GDB will need to be prefixed as `mon <oocd_command>`.\n\nWhen the target dumps code coverage data, the `.gcda` files are stored in the project's build directory. For example, if `gcov_example_main.c` of the `main` component is compiled with the `--coverage` option, then dumping the code coverage data would generate a `gcov_example_main.gcda` in `build/esp-idf/main/CMakeFiles/__idf_main.dir/gcov_example_main.c.gcda`. Note that the `.gcno` files produced during compilation are also placed in the same directory.\n\nThe dumping of code coverage data can be done multiple times throughout an application's lifetime. Each dump will simply update the `.gcda` file with the newest code coverage information. Code coverage data is accumulative, thus the newest data will contain the total execution count of each code path over the application's entire lifetime.\n\nESP-IDF supports two methods of dumping code coverage data form the target to the host:\n\n* Instant Run-Time Dump\n* Hard-coded Dump\n\n### Instant Run-Time Dump\n\nAn Instant Run-Time Dump is triggered by calling the `esp gcov` OpenOCD command (via a telnet session). Once called, OpenOCD will immediately preempt the {IDF_TARGET_NAME}'s current state and execute a built-in ESP-IDF Gcov debug stub function. The debug stub function will handle the dumping of data to the host. Upon completion, the {IDF_TARGET_NAME} will resume its current state.\n\n### Hard-coded Dump\n\nA Hard-coded Dump is triggered by the application itself by calling `esp_gcov_dump()` from somewhere within the application. When called, the application will halt and wait for OpenOCD to connect and retrieve the code coverage data. Once `esp_gcov_dump()` is called, the host must execute the `esp gcov dump` OpenOCD command (via a telnet session). The `esp gcov dump` command will cause OpenOCD to connect to the {IDF_TARGET_NAME}, retrieve the code coverage data, then disconnect from the {IDF_TARGET_NAME}, thus allowing the application to resume. Hard-coded Dumps can also be triggered multiple times throughout an application's lifetime.\n\nHard-coded dumps are useful if code coverage data is required at certain points of an application's lifetime by placing `esp_gcov_dump()` where necessary (e.g., after application initialization, during each iteration of an application's main loop).\n\nGDB can be used to set a breakpoint on `esp_gcov_dump()`, then call `mon esp gcov dump` automatically via the use a `gdbinit` script (see Using GDB from JTAG debugging documentation).\n\nThe following GDB script will add a breakpoint at `esp_gcov_dump()`, then call the `mon esp gcov dump` OpenOCD command.\n\n```\nb esp_gcov_dump\ncommands\nmon esp gcov dump\nend\n```\n\n> **Note:** All OpenOCD commands should be invoked in GDB as: `mon <oocd_command>`.\n\n## Generating Coverage Report\n\nOnce the code coverage data has been dumped, the `.gcno`, `.gcda` and the source files can be used to generate a code coverage report. A code coverage report is simply a report indicating the number of times each line in a source file has been executed.\n\nBoth Gcov and Gcovr can be used to generate code coverage reports. Gcov is provided along with the Xtensa toolchain, whilst Gcovr may need to be installed separately. For details on how to use Gcov or Gcovr, refer to [Gcov documentation](https://gcc.gnu.org/onlinedocs/gcc/Gcov.html) and [Gcovr documentation](https://gcovr.com/).\n\n### Adding Gcovr Build Target to Project\n\nTo make report generation more convenient, users can define additional build targets in their projects such that the report generation can be done with a single build command.\n\nAdd the following lines to the `CMakeLists.txt` file of your project.\n\n```cmake\nidf_create_coverage_report(${CMAKE_CURRENT_BINARY_DIR}/coverage_report)\nidf_clean_coverage_report(${CMAKE_CURRENT_BINARY_DIR}/coverage_report)\n```\n\nThe following commands can now be used:\n\n* `cmake --build build/ --target gcovr-report` will generate an HTML coverage report in `$(BUILD_DIR_BASE)/coverage_report/html` directory.\n* `cmake --build build/ --target cov-data-clean` will remove all coverage data files.\n"
  },
  {
    "path": "esp_gcov/esp_gcov.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n/**\n * @brief Triggers gcov info dump.\n *        This function waits for the host to connect to target before dumping data.\n */\nvoid esp_gcov_dump(void);\n"
  },
  {
    "path": "esp_gcov/gcov_rtio.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// This module implements runtime file I/O API for GCOV.\n\n#include <string.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"esp_app_trace.h\"\n#include \"esp_freertos_hooks.h\"\n#include \"esp_dbg_stubs.h\"\n#include \"esp_private/esp_ipc.h\"\n#include \"esp_log.h\"\n\n#define ESP_GCOV_DOWN_BUF_SIZE  4200\n\nstatic const char *TAG = \"esp_gcov_rtio\";\nstatic volatile bool s_create_gcov_task = false;\nstatic volatile bool s_gcov_task_running = false;\n\nextern void __gcov_dump(void);\nextern void __gcov_reset(void);\n\nvoid gcov_dump_task(void *pvParameter)\n{\n    int dump_result = 0;\n    bool *running = (bool *)pvParameter;\n\n    ESP_EARLY_LOGV(TAG, \"%s stack use in %d\", __FUNCTION__, uxTaskGetStackHighWaterMark(NULL));\n\n    ESP_EARLY_LOGV(TAG, \"Alloc apptrace down buf %d bytes\", ESP_GCOV_DOWN_BUF_SIZE);\n    void *down_buf = malloc(ESP_GCOV_DOWN_BUF_SIZE);\n    if (down_buf == NULL) {\n        ESP_EARLY_LOGE(TAG, \"Could not allocate memory for the buffer\");\n        dump_result = ESP_ERR_NO_MEM;\n        goto gcov_exit;\n    }\n    ESP_EARLY_LOGV(TAG, \"Config apptrace down buf\");\n    esp_err_t res = esp_apptrace_down_buffer_config(down_buf, ESP_GCOV_DOWN_BUF_SIZE);\n    if (res != ESP_OK) {\n        ESP_EARLY_LOGE(TAG, \"Failed to config apptrace down buf (%d)!\", res);\n        dump_result = res;\n        goto gcov_exit;\n    }\n    ESP_EARLY_LOGV(TAG, \"Dump data...\");\n    __gcov_dump();\n    // reset dump status to allow incremental data accumulation\n    __gcov_reset();\n    free(down_buf);\n    ESP_EARLY_LOGV(TAG, \"Finish file transfer session\");\n    dump_result = esp_apptrace_fstop();\n    if (dump_result != ESP_OK) {\n        ESP_EARLY_LOGE(TAG, \"Failed to send files transfer stop cmd (%d)!\", dump_result);\n    }\n\ngcov_exit:\n    ESP_EARLY_LOGV(TAG, \"dump_result %d\", dump_result);\n    if (running) {\n        *running = false;\n    }\n\n    ESP_EARLY_LOGV(TAG, \"%s stack use out %d\", __FUNCTION__, uxTaskGetStackHighWaterMark(NULL));\n\n    vTaskDelete(NULL);\n}\n\nvoid gcov_create_task(void *arg)\n{\n    ESP_EARLY_LOGV(TAG, \"%s\", __FUNCTION__);\n    xTaskCreatePinnedToCore(&gcov_dump_task, \"gcov_dump_task\", CONFIG_ESP_GCOV_DUMP_TASK_STACK_SIZE,\n                            (void *)&s_gcov_task_running, configMAX_PRIORITIES - 1, NULL, 0);\n}\n\nstatic IRAM_ATTR\nvoid gcov_create_task_tick_hook(void)\n{\n    if (s_create_gcov_task) {\n        if (esp_ipc_call_nonblocking(xPortGetCoreID(), &gcov_create_task, NULL) == ESP_OK) {\n            s_create_gcov_task = false;\n        }\n    }\n}\n\n/**\n * @brief Triggers gcov info dump task\n *        This function is to be called by OpenOCD, not by normal user code.\n * TODO: what about interrupted flash access (when cache disabled)\n *\n * @return ESP_OK on success, otherwise see esp_err_t\n */\nstatic int esp_dbg_stub_gcov_entry(void)\n{\n    /* we are in isr context here */\n    s_create_gcov_task = true;\n    return ESP_OK;\n}\n\nvoid gcov_rtio_init(void)\n{\n    uint32_t stub_entry = 0;\n    ESP_EARLY_LOGV(TAG, \"%s\", __FUNCTION__);\n    assert(esp_dbg_stub_entry_get(ESP_DBG_STUB_ENTRY_GCOV, &stub_entry) == ESP_OK);\n    if (stub_entry != 0) {\n        /* \"__gcov_init()\" can be called several times. We must avoid multiple tick hook registration */\n        return;\n    }\n    esp_dbg_stub_entry_set(ESP_DBG_STUB_ENTRY_GCOV, (uint32_t)&esp_dbg_stub_gcov_entry);\n    assert(esp_dbg_stub_entry_get(ESP_DBG_STUB_ENTRY_CAPABILITIES, &stub_entry) == ESP_OK);\n    esp_dbg_stub_entry_set(ESP_DBG_STUB_ENTRY_CAPABILITIES, stub_entry | ESP_DBG_STUB_CAP_GCOV_TASK);\n    esp_register_freertos_tick_hook(gcov_create_task_tick_hook);\n}\n\nvoid esp_gcov_dump(void)\n{\n    ESP_EARLY_LOGV(TAG, \"%s\", __FUNCTION__);\n\n    while (!esp_apptrace_host_is_connected()) {\n        vTaskDelay(pdMS_TO_TICKS(10));\n    }\n\n    /* We are not in isr context here. Waiting for the completion is safe */\n    s_gcov_task_running = true;\n    s_create_gcov_task = true;\n    while (s_gcov_task_running) {\n        vTaskDelay(pdMS_TO_TICKS(10));\n    }\n}\n\nvoid *gcov_rtio_fopen(const char *path, const char *mode)\n{\n    ESP_EARLY_LOGV(TAG, \"%s '%s' '%s'\", __FUNCTION__, path, mode);\n    void *f = esp_apptrace_fopen(path, mode);\n    ESP_EARLY_LOGV(TAG, \"%s ret %p\", __FUNCTION__, f);\n    return f;\n}\n\nint gcov_rtio_fclose(void *stream)\n{\n    ESP_EARLY_LOGV(TAG, \"%s\", __FUNCTION__);\n    return esp_apptrace_fclose(stream);\n}\n\nsize_t gcov_rtio_fread(void *ptr, size_t size, size_t nmemb, void *stream)\n{\n    ESP_EARLY_LOGV(TAG, \"%s read %u\", __FUNCTION__, size * nmemb);\n    size_t sz = esp_apptrace_fread(ptr, size, nmemb, stream);\n    ESP_EARLY_LOGV(TAG, \"%s actually read %u\", __FUNCTION__, sz);\n    return sz;\n}\n\nsize_t gcov_rtio_fwrite(const void *ptr, size_t size, size_t nmemb, void *stream)\n{\n    ESP_EARLY_LOGV(TAG, \"%s\", __FUNCTION__);\n    return esp_apptrace_fwrite(ptr, size, nmemb, stream);\n}\n\nint gcov_rtio_fseek(void *stream, long offset, int whence)\n{\n    int ret = esp_apptrace_fseek(stream, offset, whence);\n    ESP_EARLY_LOGV(TAG, \"%s(%p %ld %d) = %d\", __FUNCTION__, stream, offset, whence, ret);\n    return ret;\n}\n\nlong gcov_rtio_ftell(void *stream)\n{\n    long ret = esp_apptrace_ftell(stream);\n    ESP_EARLY_LOGV(TAG, \"%s(%p) = %ld\", __FUNCTION__, stream, ret);\n    return ret;\n}\n\nint gcov_rtio_feof(void *stream)\n{\n    int ret = esp_apptrace_feof(stream);\n    ESP_EARLY_LOGV(TAG, \"%s(%p) = %d\", __FUNCTION__, stream, ret);\n    return ret;\n}\n\nvoid gcov_rtio_setbuf(void *arg1 __attribute__((unused)), void *arg2 __attribute__((unused)))\n{\n    return;\n}\n\n/* Wrappers for Gcov functions */\n\nextern void __real___gcov_init(void *info);\nvoid __wrap___gcov_init(void *info)\n{\n    __real___gcov_init(info);\n    gcov_rtio_init();\n}\n"
  },
  {
    "path": "esp_gcov/idf_component.yml",
    "content": "version: 1.0.5\ndescription: Gcov (Source Code Coverage) component for ESP-IDF\nurl: https://github.com/espressif/idf-extra-components/tree/master/esp_gcov\nissues: https://github.com/espressif/idf-extra-components/issues\nrepository: https://github.com/espressif/idf-extra-components.git\ndependencies:\n  idf: \">=6.0\"\n"
  },
  {
    "path": "esp_gcov/project_include.cmake",
    "content": "# idf_create_coverage_report\n#\n# Create coverage report.\n#\n# Arguments:\n#   report_dir - Directory where the coverage report will be generated\n#   SOURCE_DIR - (Optional) Source directory to use as root for gcovr.\n#                If not provided, defaults to PROJECT_DIR.\n#   GCOV_OPTIONS - (Optional) Additional options to pass to gcovr.\n#\n# Example:\n#   idf_create_coverage_report(${report_dir})  # Uses PROJECT_DIR\n#   idf_create_coverage_report(${report_dir} SOURCE_DIR ${component_dir})  # Uses custom source dir\n#   idf_create_coverage_report(${report_dir} GCOV_OPTIONS \"--gcov-ignore-parse-errors=negative_hits.warn\")\n#\nfunction(idf_create_coverage_report report_dir)\n    cmake_parse_arguments(ARG \"\" \"SOURCE_DIR\" \"GCOV_OPTIONS\" ${ARGN})\n\n    set(gcov_tool ${_CMAKE_TOOLCHAIN_PREFIX}gcov)\n\n    # Use provided SOURCE_DIR or default to PROJECT_DIR\n    if(ARG_SOURCE_DIR)\n        set(source_root_dir \"${ARG_SOURCE_DIR}\")\n    else()\n        idf_build_get_property(source_root_dir PROJECT_DIR)\n    endif()\n\n    file(TO_NATIVE_PATH \"${report_dir}\" _report_dir)\n    file(TO_NATIVE_PATH \"${source_root_dir}\" _source_root_dir)\n    file(TO_NATIVE_PATH \"${report_dir}/html/index.html\" _index_path)\n\n    add_custom_target(pre-cov-report\n        COMMENT \"Generating coverage report in: ${_report_dir}\"\n        COMMAND ${CMAKE_COMMAND} -E echo \"Using gcov: ${gcov_tool}\"\n        COMMAND ${CMAKE_COMMAND} -E echo \"Source root: ${_source_root_dir}\"\n        COMMAND ${CMAKE_COMMAND} -E make_directory ${_report_dir}/html\n        )\n\n    add_custom_target(gcovr-report\n        COMMAND gcovr -r ${_source_root_dir} --gcov-executable ${gcov_tool} ${ARG_GCOV_OPTIONS} -s --html-details ${_index_path}\n        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}\n        DEPENDS pre-cov-report\n        )\nendfunction()\n\n# idf_clean_coverage_report\n#\n# Clean coverage report.\nfunction(idf_clean_coverage_report report_dir)\n    file(TO_CMAKE_PATH \"${report_dir}\" _report_dir)\n\n    add_custom_target(cov-data-clean\n        COMMENT \"Clean coverage report in: ${_report_dir}\"\n        COMMAND ${CMAKE_COMMAND} -E remove_directory ${_report_dir})\nendfunction()\n"
  },
  {
    "path": "esp_gcov/sdkconfig.rename",
    "content": "# sdkconfig replacement configurations for deprecated options formatted as\n# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION\n\nCONFIG_ESP32_GCOV_ENABLE                                CONFIG_ESP_GCOV_ENABLE\nCONFIG_APPTRACE_GCOV_DUMP_TASK_STACK_SIZE               CONFIG_ESP_GCOV_DUMP_TASK_STACK_SIZE\n"
  },
  {
    "path": "esp_isotp/.build-test-rules.yml",
    "content": ""
  },
  {
    "path": "esp_isotp/CMakeLists.txt",
    "content": "idf_component_register(\n    SRCS \"src/esp_isotp.c\" \"isotp-c/isotp.c\"\n    INCLUDE_DIRS \"inc\"\n    PRIV_INCLUDE_DIRS \"isotp-c\"\n    REQUIRES esp_driver_twai\n    PRIV_REQUIRES esp_timer\n)\n\n# Force include our custom isotp_config.h before any source file compilation\n# This ensures our configuration is loaded first, preventing macro redefinitions\ntarget_compile_options(${COMPONENT_LIB} PRIVATE\n    \"SHELL:-include ${CMAKE_CURRENT_SOURCE_DIR}/src/isotp_config.h\"\n)\n"
  },
  {
    "path": "esp_isotp/Kconfig",
    "content": "menu \"ISO-TP Protocol\"\n\n    config ISO_TP_DEFAULT_BLOCK_SIZE\n        int \"Default Block Size\"\n        default 8\n        range 1 32\n        help\n            Maximum number of consecutive frames the receiver can receive at one time.\n            This value is affected by CAN driver queue length.\n            Higher values improve throughput but require more buffer space.\n\n    config ISO_TP_DEFAULT_ST_MIN_US\n        int \"Default STmin (microseconds)\"\n        default 1000\n        range 0 50000\n        help\n            The STmin parameter specifies the minimum time gap allowed between\n            the transmission of consecutive frame network protocol data units.\n            0 = no delay, 1-50000 microseconds for timing control.\n\n    config ISO_TP_MAX_WFT_NUMBER\n        int \"Maximum Wait Frame Number\"\n        default 1\n        range 1 10\n        help\n            This parameter indicates how many FC N_PDU WTs (Wait frames) can be\n            transmitted by the receiver in a row before giving up.\n\n    config ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US\n        int \"Default Response Timeout (microseconds)\"\n        default 100000\n        range 10000 5000000\n        help\n            The default timeout to use when waiting for a response during a\n            multi-frame send or receive operation.\n            Common values: 100000 (100ms), 1000000 (1s).\n\n    config ISO_TP_FRAME_PADDING\n        bool \"Enable Frame Padding\"\n        default n\n        help\n            Enable padding of ISO-TP message frames to full CAN frame size.\n            When enabled, frames are padded with ISO_TP_FRAME_PADDING_VALUE.\n\n    config ISO_TP_FRAME_PADDING_VALUE\n        hex \"Frame Padding Value\"\n        default 0xAA\n        range 0x00 0xFF\n        depends on ISO_TP_FRAME_PADDING\n        help\n            Value used for padding when ISO_TP_FRAME_PADDING is enabled.\n            Common values: 0x00, 0xAA, 0xCC, 0xFF.\n\nendmenu\n"
  },
  {
    "path": "esp_isotp/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019-2024 Li Shen & Co-Operators\nCopyright (c) 2024 Simon Cahill & Contributors.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "esp_isotp/README.md",
    "content": "# ESP-IDF ISO-TP Component\n\n[![Component Registry](https://components.espressif.com/components/espressif/esp_isotp/badge.svg)](https://components.espressif.com/components/espressif/esp_isotp)\n\nISO 15765-2 (ISO-TP) for ESP-IDF. Sends/receives large payloads (≤4095 B) over TWAI with segmentation and reassembly.\n\n## Key Features\n\n- Segmentation + flow control for >7 B\n- Non-blocking API, ISR-backed\n- Multiple links in parallel\n- UDS/OBD-II friendly\n- Timeouts + sequence checks\n- 11-bit and 29-bit IDs\n\n> [!NOTE]\n> TWAI-FD (Flexible Data-rate)  is not supported in this version.\n\n## Installation\n\nTo add this component to your project, run the following command from your project's root directory:\n\n```bash\nidf.py add-dependency espressif/esp_isotp\n```\n\n## Configuration\n\nYou can configure protocol parameters like timing through the project configuration menu:\n\n```bash\nidf.py menuconfig\n```\n\nNavigate to `Component config` → `ISO-TP Protocol Configuration`.\n\n## Quick Start Guide\n\nHere's a simple example that initializes the TWAI driver and an ISO-TP link, then echoes back any received data.\n\n### Example Code\n\n```c\n#include \"esp_isotp.h\"\n#include \"esp_twai_onchip.h\"\n\nvoid app_main(void) {\n    // 1) Init TWAI\n    twai_onchip_node_config_t twai_cfg = {\n        .io_cfg = {.tx = GPIO_NUM_5, .rx = GPIO_NUM_4},\n        .bit_timing = {.bitrate = 500000},\n        .tx_queue_depth = 16,\n    };\n    twai_node_handle_t twai_node;\n    ESP_ERROR_CHECK(twai_new_node_onchip(&twai_cfg, &twai_node));\n\n    // 2) Create ISO-TP (11-bit IDs, auto-detected)\n    esp_isotp_config_t config = {\n        .tx_id = 0x7E0,                // request ID (11-bit, auto-detected)\n        .rx_id = 0x7E8,                // response ID (11-bit, auto-detected)\n        .tx_buffer_size = 4096,\n        .rx_buffer_size = 4096,\n    };\n    esp_isotp_handle_t isotp_handle;\n    ESP_ERROR_CHECK(esp_isotp_new_transport(twai_node, &config, &isotp_handle));\n\n    // 3) Loop\n    uint8_t buffer[4096];\n    uint32_t received_size;\n\n    while (1) {\n        // This is the engine of the component. Call it frequently!\n        esp_isotp_poll(isotp_handle);\n\n        // Check if a full message has been received\n        if (esp_isotp_receive(isotp_handle, buffer, sizeof(buffer), &received_size) == ESP_OK) {\n            printf(\"Received %lu bytes\\n\", received_size);\n            // Echo the message back\n            esp_isotp_send(isotp_handle, buffer, received_size);\n        }\n\n        vTaskDelay(pdMS_TO_TICKS(5)); // A small delay is good practice\n    }\n}\n```\n\n## Extended (29-bit) IDs\n\n- ID format is auto-detected: IDs > 0x7FF use 29-bit extended format, others use 11-bit standard format.\n- `tx_id` and `rx_id` must differ and match peer's expected format.\n\n```c\nesp_isotp_config_t cfg = {\n    .tx_id = 0x18DAF110,    // 29-bit ID (auto-detected as extended)\n    .rx_id = 0x18DA10F1,    // 29-bit ID (auto-detected as extended)\n    .tx_buffer_size = 4096,\n    .rx_buffer_size = 4096,\n};\n```\n\n## Errors\n\n- Common: ESP_OK, ESP_ERR_INVALID_ARG, ESP_ERR_INVALID_SIZE, ESP_ERR_NO_MEM, ESP_ERR_TIMEOUT\n- Send: ESP_ERR_NOT_FINISHED when previous TX in progress\n- Receive: ESP_ERR_NOT_FOUND when no complete message; ESP_ERR_INVALID_RESPONSE on bad sequence\n- Full list: see `esp_isotp.h`\n\n## Checklist\n\n- IDs valid and different; 11-bit vs 29-bit matches `use_extended_id`\n- Buffers > 0; size gates max single-message length (≤4095 B)\n- Call `esp_isotp_poll()` every 1–10 ms\n- TWAI node created and enabled before use\n\n"
  },
  {
    "path": "esp_isotp/idf_component.yml",
    "content": "version: \"0.1.1\"\ndescription: ISO-TP (ISO 15765-2) protocol implementation for ESP-IDF\nurl: https://github.com/espressif/idf-extra-components/tree/master/esp_isotp\nrepository: https://github.com/espressif/idf-extra-components.git\nissues: https://github.com/espressif/idf-extra-components/issues\ndependencies:\n  idf: \">=5.5.0\"\n"
  },
  {
    "path": "esp_isotp/inc/esp_isotp.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n/**\n * @file esp_isotp.h\n * @brief ISO-TP (ISO 15765-2) Transport Protocol Implementation\n *\n * ISO-TP enables transmission of data larger than 8 bytes over TWAI networks\n * through automatic fragmentation and reassembly.\n *\n * ## How it Works\n *\n * **Small packets (≤7 bytes)**: Sent in a single TWAI frame immediately.\n * **Large packets (>7 bytes)**: Split into multiple frames - first frame sent immediately,\n * remaining frames sent during esp_isotp_poll() calls.\n *\n */\n\n#include \"esp_err.h\"\n#include \"esp_twai.h\"\n#include \"esp_twai_types.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief ISO-TP link handle\n */\ntypedef struct esp_isotp_link_t *esp_isotp_handle_t;\n\n/**\n * @brief ISO-TP receive callback function type\n *\n * Called when a complete message has been received successfully.\n *\n * @warning This callback executes in the same context as isotp_on_can_message(),\n *          which is typically ISR context. Keep callback execution time minimal\n *          and avoid blocking operations.\n * @note The data pointer is only valid during the callback execution.\n *       Copy data immediately if needed beyond the callback scope.\n *\n * @param[in] handle ISO-TP handle that received the message\n * @param[in] data Pointer to received data (valid only during callback)\n * @param[in] size Size of received data in bytes\n * @param[in] user_arg User argument provided during configuration\n */\ntypedef void (*esp_isotp_rx_callback_t)(esp_isotp_handle_t handle, const uint8_t *data, uint32_t size, void *user_arg);\n\n/**\n * @brief ISO-TP transmit callback function type\n *\n * Called when a complete message has been transmitted successfully.\n *\n * @note Execution context depends on message type:\n *       - Single-frame: Called immediately from isotp_send() in caller's context\n *       - Multi-frame: Called from isotp_poll() in task context\n * @note Keep callback execution time minimal to avoid affecting system performance.\n *\n * @param[in] handle ISO-TP handle that transmitted the message\n * @param[in] tx_size Size of transmitted data in bytes\n * @param[in] user_arg User argument provided during configuration\n */\ntypedef void (*esp_isotp_tx_callback_t)(esp_isotp_handle_t handle, uint32_t tx_size, void *user_arg);\n\n/**\n * @brief Configuration structure for creating a new ISO-TP link\n */\ntypedef struct {\n    uint32_t tx_id;                  /*!< TWAI ID for transmitting ISO-TP frames (11-bit or 29-bit, auto-detected from value) */\n    uint32_t rx_id;                  /*!< TWAI ID for receiving ISO-TP frames (11-bit or 29-bit, auto-detected from value) */\n    uint32_t tx_buffer_size;         /*!< Size of the transmit buffer (max message size to send) */\n    uint32_t rx_buffer_size;         /*!< Size of the receive buffer (max message size to receive) */\n    uint32_t tx_frame_pool_size;     /*!< Size of TX frame pool */\n\n    esp_isotp_rx_callback_t rx_callback; /*!< Receive completion callback (NULL for polling mode) */\n    esp_isotp_tx_callback_t tx_callback; /*!< Transmit completion callback (NULL to disable) */\n    void *callback_arg;               /*!< User argument passed to callbacks */\n} esp_isotp_config_t;\n\n/**\n * @brief Create a new ISO-TP transport bound to a TWAI node.\n *\n * Allocates internal buffers, creates TX frame pool, registers TWAI callbacks\n * and enables the provided TWAI node.\n *\n * @param twai_node TWAI node handle to bind.\n * @param config Transport configuration.\n * @param[out] out_handle Returned ISO-TP transport handle.\n * @return esp_err_t\n *  - ESP_OK on success\n *  - ESP_ERR_INVALID_ARG for invalid parameters\n *  - ESP_ERR_INVALID_SIZE for invalid buffer sizes\n *  - ESP_ERR_NO_MEM when allocation fails\n *  - Other error codes from TWAI functions\n */\nesp_err_t esp_isotp_new_transport(twai_node_handle_t twai_node, const esp_isotp_config_t *config, esp_isotp_handle_t *out_handle);\n\n/**\n * @brief Send data over an ISO-TP link (non-blocking, ISR-safe)\n *\n * Immediately sends first/single frame and returns. For multi-frame messages,\n * remaining frames are sent during subsequent esp_isotp_poll() calls.\n *\n * @note This function is ISR-safe and can be called from interrupt context.\n * @note TX completion callback timing:\n *       - Single-frame: Called immediately from isotp_send()\n *       - Multi-frame: Called from isotp_poll() when last frame is sent\n *\n * @param handle ISO-TP handle\n * @param data Data to send\n * @param size Data length in bytes\n * @return\n *     - ESP_OK: Send initiated successfully\n *     - ESP_ERR_NOT_FINISHED: Previous send still in progress\n *     - ESP_ERR_NO_MEM: Data too large for buffer or no space available\n *     - ESP_ERR_INVALID_SIZE: Invalid data size\n *     - ESP_ERR_TIMEOUT: Send operation timed out\n *     - ESP_ERR_INVALID_ARG: Invalid parameters\n *     - ESP_FAIL: Other send errors\n */\nesp_err_t esp_isotp_send(esp_isotp_handle_t handle, const uint8_t *data, uint32_t size);\n\n/**\n * @brief Send data over an ISO-TP link with specified TWAI ID (non-blocking, ISR-safe)\n *\n * Similar to esp_isotp_send(), but allows specifying a different TWAI ID for transmission.\n * This function is primarily used for functional addressing where multiple nodes\n * may respond to the same request.\n *\n * @note This function is ISR-safe and can be called from interrupt context.\n * @note TX completion callback timing:\n *       - Single-frame: Called immediately from isotp_send_with_id()\n *       - Multi-frame: Called from isotp_poll() when last frame is sent\n *\n * @param handle ISO-TP handle\n * @param id TWAI identifier to use for transmission (overrides configured tx_id)\n * @param data Data to send\n * @param size Data length in bytes\n * @return\n *     - ESP_OK: Send initiated successfully\n *     - ESP_ERR_NOT_FINISHED: Previous send still in progress\n *     - ESP_ERR_NO_MEM: Data too large for buffer or no space available\n *     - ESP_ERR_INVALID_SIZE: Invalid data size\n *     - ESP_ERR_TIMEOUT: Send operation timed out\n *     - ESP_ERR_INVALID_ARG: Invalid parameters or ID exceeds maximum value\n *     - ESP_FAIL: Other send errors\n */\nesp_err_t esp_isotp_send_with_id(esp_isotp_handle_t handle, uint32_t id, const uint8_t *data, uint32_t size);\n\n/**\n * @brief Extract a complete received message (non-blocking, task context only)\n *\n * This function only extracts data that has already been assembled by esp_isotp_poll().\n * It does NOT process incoming TWAI frames - that happens in esp_isotp_poll().\n *\n * Process: TWAI frames → esp_isotp_poll() assembles → esp_isotp_receive() extracts\n *\n * @warning This function is NOT ISR-safe and must only be called from task context.\n * @note When using callback mode (rx_callback != NULL), received messages are\n *       automatically delivered via callback. This function should only be used\n *       in polling mode (rx_callback == NULL).\n *\n * @param handle ISO-TP handle\n * @param data Buffer to store received data\n * @param size Buffer size in bytes\n * @param[out] received_size Actual received data length\n * @return\n *     - ESP_OK: Complete message extracted and internal buffer cleared\n *     - ESP_ERR_NOT_FOUND: No complete message ready for extraction\n *     - ESP_ERR_INVALID_SIZE: Receive buffer overflow or invalid size\n *     - ESP_ERR_INVALID_RESPONSE: Invalid sequence number or protocol error\n *     - ESP_ERR_TIMEOUT: Receive operation timed out\n *     - ESP_ERR_INVALID_ARG: Invalid parameters\n *     - ESP_FAIL: Other receive errors\n */\nesp_err_t esp_isotp_receive(esp_isotp_handle_t handle, uint8_t *data, uint32_t size, uint32_t *received_size);\n\n/**\n * @brief Poll the ISO-TP link to process messages (CRITICAL - call regularly, task context only)\n *\n * This function drives the ISO-TP state machine. Call every 1-10ms for proper operation.\n *\n * What it does:\n * - Sends remaining frames for multi-frame messages\n * - Processes incoming TWAI frames and assembles complete messages\n * - Handles flow control and timeouts\n * - Updates internal state machine\n * - Triggers TX completion callbacks for multi-frame messages\n *\n * Without regular polling: multi-frame sends will stall and receives won't complete.\n *\n * @warning This function is NOT ISR-safe and must only be called from task context.\n * @note TX completion callbacks for multi-frame messages are triggered from this function.\n *\n * @param handle ISO-TP handle\n * @return\n *     - ESP_OK: Processing successful\n *     - ESP_ERR_INVALID_ARG: Invalid parameters\n */\nesp_err_t esp_isotp_poll(esp_isotp_handle_t handle);\n\n/**\n * @brief Delete an ISO-TP link\n *\n * @param handle The handle of the ISO-TP link to delete\n * @return\n *     - ESP_OK: Success (or TWAI disable warning logged)\n *     - ESP_ERR_INVALID_ARG: Invalid argument\n *     - Other ESP error codes: TWAI node disable failed\n */\nesp_err_t esp_isotp_delete(esp_isotp_handle_t handle);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_isotp/src/esp_isotp.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include <stdarg.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/queue.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"esp_check.h\"\n#include \"esp_log.h\"\n#include \"esp_timer.h\"\n#include \"esp_twai.h\"\n#include \"esp_isotp.h\"\n// Include isotp-c library from submodule\n#include \"isotp.h\"\n\nstatic const char *TAG = \"esp_isotp\";\n\n/**\n * @brief Determine if the given ID requires extended (29-bit) format\n *\n * @param id TWAI identifier to check\n * @return true if ID requires 29-bit extended format, false for 11-bit standard format\n */\nstatic inline bool is_extended_id(uint32_t id)\n{\n    return (id > TWAI_STD_ID_MASK);\n}\n\n/**\n * @brief TWAI frame container with embedded data buffer.\n *\n * This structure wraps the TWAI frame with an embedded 8-byte data buffer\n * to ensure memory safety during asynchronous operations.\n *\n * Used for:\n * - TX frames: Pre-allocated in SLIST pool, recycled after transmission\n * - RX frames: Pre-allocated in link structure for ISR-safe reception\n */\ntypedef struct esp_isotp_frame_t {\n    twai_frame_t frame;           ///< TWAI driver frame structure\n    uint8_t data_payload[8];      ///< Embedded 8-byte TWAI frame data buffer\n    SLIST_ENTRY(esp_isotp_frame_t) link;  ///< Single-linked list entry for frame pool\n} esp_isotp_frame_t;\n\nSLIST_HEAD(frame_pool_head, esp_isotp_frame_t);\n\n/**\n * @brief ISO-TP link context structure.\n *\n * Contains all state and buffers needed for an ISO-TP transport session.\n * This structure bridges the isotp-c library with ESP-IDF TWAI driver.\n */\ntypedef struct esp_isotp_link_t {\n    IsoTpLink link;                           ///< isotp-c library link state\n    twai_node_handle_t twai_node;             ///< Associated TWAI driver node handle\n    uint8_t *isotp_tx_buffer;                 ///< ISO-TP TX reassembly buffer (for multi-frame messages)\n    uint8_t *isotp_rx_buffer;                 ///< ISO-TP RX reassembly buffer (for multi-frame messages)\n    esp_isotp_frame_t isr_rx_frame_buffer;    ///< Pre-allocated frame buffer for ISR-safe RX operations\n    struct frame_pool_head tx_frame_pool;     ///< Single-linked list of available TX frames\n    esp_isotp_frame_t *tx_frame_array;        ///< Pre-allocated array of TX frames\n    size_t tx_frame_pool_size;                ///< Size of TX frame pool\n    esp_isotp_rx_callback_t rx_callback;      ///< User RX callback function\n    esp_isotp_tx_callback_t tx_callback;      ///< User TX callback function\n    void *callback_arg;                       ///< User argument for callbacks\n} esp_isotp_link_t;\n\n/**\n * @brief Wrapper callback for isotp-c RX completion.\n *\n * This function wraps the user's callback to hide isotp-c internal link parameter.\n *\n * @note Execution context: This callback runs in the same context as isotp_on_can_message(),\n *       which is typically called from ISR context (esp_isotp_rx_callback).\n *       Therefore, user RX callbacks should avoid blocking operations and keep execution minimal.\n *\n * @param link ISO-TP link handle (unused).\n * @param data Pointer to received data.\n * @param size Size of received data in bytes.\n * @param user_arg User context pointer (esp_isotp_handle_t).\n */\n#ifdef ISO_TP_RECEIVE_COMPLETE_CALLBACK\nstatic void esp_isotp_rx_wrapper(void *link, const uint8_t *data, uint32_t size, void *user_arg)\n{\n    esp_isotp_handle_t handle = (esp_isotp_handle_t)user_arg;\n    if (handle && handle->rx_callback) {\n        handle->rx_callback(handle, data, size, handle->callback_arg);\n    }\n}\n#endif\n\n/**\n * @brief Wrapper callback for isotp-c TX completion.\n *\n * This function wraps the user's callback to hide isotp-c internal link parameter.\n *\n * @note Execution context depends on transmission type:\n *       - Single-frame: Called from isotp_send() in the same context as the caller\n *         (may be ISR context if esp_isotp_send() was called from ISR)\n *       - Multi-frame: Called from isotp_poll() in task context when the last frame is sent\n *\n * @param link ISO-TP link handle (unused).\n * @param tx_size Size of transmitted data in bytes.\n * @param user_arg User context pointer (esp_isotp_handle_t).\n */\n#ifdef ISO_TP_TRANSMIT_COMPLETE_CALLBACK\nstatic void esp_isotp_tx_wrapper(void *link, uint32_t tx_size, void *user_arg)\n{\n    esp_isotp_handle_t handle = (esp_isotp_handle_t)user_arg;\n    if (handle && handle->tx_callback) {\n        handle->tx_callback(handle, tx_size, handle->callback_arg);\n    }\n}\n#endif\n\n/**\n * @brief TWAI transmit done callback.\n *\n * Called when a TWAI frame transmission is complete. Returns the used\n * frame back to the SLIST pool for reuse.\n *\n * @note Runs in ISR context.\n * @param handle TWAI node handle invoking the callback.\n * @param edata Transmit event data from TWAI driver.\n * @param user_ctx User context pointer (esp_isotp_handle_t).\n * @return Always returns false (no context switch needed).\n */\nstatic IRAM_ATTR bool esp_isotp_tx_callback(twai_node_handle_t handle, const twai_tx_done_event_data_t *edata, void *user_ctx)\n{\n    esp_isotp_handle_t isotp_handle = (esp_isotp_handle_t) user_ctx;\n    // Return the used frame back to the SLIST pool.\n    if (isotp_handle && edata->done_tx_frame) {\n        esp_isotp_frame_t *tx_frame = (esp_isotp_frame_t *)edata->done_tx_frame;\n        // Return frame to SLIST pool for reuse\n        SLIST_INSERT_HEAD(&isotp_handle->tx_frame_pool, tx_frame, link);\n    }\n\n    return false;\n}\n\n/**\n * @brief TWAI receive done callback.\n *\n * Processes a received TWAI frame and feeds it to the ISO-TP state machine.\n *\n * @note Runs in ISR context.\n * @param handle TWAI node handle invoking the callback.\n * @param edata Receive event data from TWAI driver (unused).\n * @param user_ctx User context pointer (esp_isotp_handle_t).\n * @return true to request a context switch to a higher-priority task, false otherwise.\n */\nstatic IRAM_ATTR bool esp_isotp_rx_callback(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx)\n{\n    esp_isotp_handle_t link_handle = (esp_isotp_handle_t)user_ctx;\n    if (!link_handle) {\n        return false;  // No valid context, nothing to do\n    }\n\n    esp_isotp_frame_t *rx_frame = &link_handle->isr_rx_frame_buffer;\n\n    if (twai_node_receive_from_isr(handle, &rx_frame->frame) != ESP_OK) {\n        return false;\n    }\n\n    // ID match check\n    if (rx_frame->frame.header.id != link_handle->link.receive_arbitration_id) {\n        return false;\n    }\n\n    // Feed received TWAI frame to isotp-c state machine for reassembly.\n    // isotp-c will handle single/multi-frame logic and send flow control frames as needed.\n    isotp_on_can_message(&link_handle->link, rx_frame->frame.buffer, rx_frame->frame.buffer_len);\n\n    return false;\n}\n\n/**\n * @brief Get monotonic timestamp in microseconds.\n *\n * Returns the current time in microseconds as a 32-bit, monotonically\n * increasing value. Wrap-around is expected; the library compares\n * timestamps using IsoTpTimeAfter().\n *\n * @return 32-bit timestamp in microseconds.\n */\nuint32_t isotp_user_get_us(void)\n{\n    return (uint32_t)esp_timer_get_time();\n}\n\n/**\n * @brief isotp-c library stub function: send twai message\n *\n * Queues a TWAI frame for transmission using the configured TWAI node.\n *\n * @param arbitration_id TWAI identifier (11-bit or 29-bit).\n * @param data Pointer to frame payload.\n * @param size Payload length in bytes (0–8).\n * @param user_data Optional ISO-TP link handle.\n * @retval ISOTP_RET_OK Frame queued successfully.\n * @retval ISOTP_RET_ERROR Transmission failed or invalid context.\n */\nint isotp_user_send_can(const uint32_t arbitration_id, const uint8_t *data, const uint8_t size, void *user_data)\n{\n    esp_isotp_handle_t isotp_handle = (esp_isotp_handle_t) user_data;\n    ESP_RETURN_ON_FALSE_ISR(isotp_handle != NULL, ISOTP_RET_ERROR, TAG, \"Invalid ISO-TP handle\");\n\n    twai_node_handle_t twai_node = isotp_handle->twai_node;\n\n    // Get a pre-allocated frame from the SLIST pool.\n    // This avoids dynamic allocation overhead completely.\n    esp_isotp_frame_t *tx_frame = SLIST_FIRST(&isotp_handle->tx_frame_pool);\n    ESP_RETURN_ON_FALSE_ISR(tx_frame != NULL, ISOTP_RET_ERROR, TAG, \"No available frames in pool\");\n\n    // Remove frame from pool\n    SLIST_REMOVE_HEAD(&isotp_handle->tx_frame_pool, link);\n\n    // Initialize TWAI frame header and copy payload data into embedded buffer.\n    memset(&tx_frame->frame, 0, sizeof(twai_frame_t));\n    tx_frame->frame.header.id = arbitration_id;\n    tx_frame->frame.header.ide = is_extended_id(arbitration_id);  // Extended (29-bit) vs Standard (11-bit) ID\n\n    // Size validation - TWAI frames are max 8 bytes by protocol\n    ESP_RETURN_ON_FALSE_ISR(size <= 8, ISOTP_RET_ERROR, TAG, \"Invalid TWAI frame size\");\n\n    // Copy payload into the embedded buffer to ensure data lifetime during async transmission.\n    memcpy(tx_frame->data_payload, data, size);\n\n    tx_frame->frame.buffer = tx_frame->data_payload;\n    tx_frame->frame.buffer_len = size;\n\n    // Send the frame; TX callback will return frame to pool on completion.\n    esp_err_t ret = twai_node_transmit(twai_node, &tx_frame->frame, 0);\n    if (ret != ESP_OK) {\n        // Return frame to SLIST pool if sending failed immediately.\n        SLIST_INSERT_HEAD(&isotp_handle->tx_frame_pool, tx_frame, link);\n        ESP_EARLY_LOGE(TAG, \"Failed to send TWAI frame: %s\", esp_err_to_name(ret));\n        return ISOTP_RET_ERROR;\n    }\n\n    return ISOTP_RET_OK;\n}\n\n/**\n * @brief Print a formatted debug message from isotp-c.\n *\n * @param message Format string.\n * @param ... Variadic arguments for the format string.\n */\nvoid isotp_user_debug(const char *message, ...)\n{\n    va_list args;\n    va_start(args, message);\n    esp_log_writev(ESP_LOG_DEBUG, \"isotp_c\", message, args);\n    va_end(args);\n}\n\nesp_err_t esp_isotp_new_transport(twai_node_handle_t twai_node, const esp_isotp_config_t *config, esp_isotp_handle_t *out_handle)\n{\n    esp_err_t ret = ESP_OK;\n    esp_isotp_handle_t isotp = NULL;\n    ESP_RETURN_ON_FALSE(twai_node && config && out_handle, ESP_ERR_INVALID_ARG, TAG, \"Invalid parameters\");\n    ESP_RETURN_ON_FALSE(config->tx_buffer_size > 0 && config->rx_buffer_size > 0, ESP_ERR_INVALID_SIZE, TAG, \"Buffer sizes must be greater than 0\");\n    ESP_RETURN_ON_FALSE(config->tx_frame_pool_size != 0, ESP_ERR_INVALID_SIZE, TAG, \"TX frame pool size cannot be zero\");\n\n    // Validate ID ranges - each ID is validated against its own required format\n    ESP_RETURN_ON_FALSE((config->tx_id & ~TWAI_EXT_ID_MASK) == 0,\n                        ESP_ERR_INVALID_ARG, TAG, \"TX ID exceeds maximum value\");\n    ESP_RETURN_ON_FALSE((config->rx_id & ~TWAI_EXT_ID_MASK) == 0,\n                        ESP_ERR_INVALID_ARG, TAG, \"RX ID exceeds maximum value\");\n\n    // Allocate memory for handle.\n    isotp = calloc(1, sizeof(esp_isotp_link_t));\n    ESP_RETURN_ON_FALSE(isotp, ESP_ERR_NO_MEM, TAG, \"Failed to allocate memory for ISO-TP link\");\n\n    // Allocate ISO-TP reassembly buffers for multi-frame message handling.\n    // These buffers are used by isotp-c to reassemble/fragment large payloads.\n    isotp->isotp_tx_buffer = calloc(config->tx_buffer_size, sizeof(uint8_t));\n    isotp->isotp_rx_buffer = calloc(config->rx_buffer_size, sizeof(uint8_t));\n    ESP_GOTO_ON_FALSE(isotp->isotp_rx_buffer && isotp->isotp_tx_buffer, ESP_ERR_NO_MEM, err, TAG, \"Failed to allocate ISO-TP reassembly buffers\");\n\n    // Initialize TX frame pool with user-specified size\n    // Using simple single-linked list for maximum efficiency\n    isotp->tx_frame_pool_size = config->tx_frame_pool_size;\n    SLIST_INIT(&isotp->tx_frame_pool);\n\n    // Allocate array of TX frames\n    isotp->tx_frame_array = calloc(isotp->tx_frame_pool_size, sizeof(esp_isotp_frame_t));\n    ESP_GOTO_ON_FALSE(isotp->tx_frame_array, ESP_ERR_NO_MEM, err, TAG, \"Failed to allocate TX frame array\");\n\n    // Initialize each frame and add to SLIST pool\n    for (size_t i = 0; i < isotp->tx_frame_pool_size; i++) {\n        esp_isotp_frame_t *frame = &isotp->tx_frame_array[i];\n        frame->frame.buffer = frame->data_payload;\n        frame->frame.buffer_len = sizeof(frame->data_payload);\n\n        SLIST_INSERT_HEAD(&isotp->tx_frame_pool, frame, link);\n    }\n\n    // Initialize the isotp-c library link with our allocated buffers.\n    isotp_init_link(&isotp->link, config->tx_id, isotp->isotp_tx_buffer,\n                    config->tx_buffer_size, isotp->isotp_rx_buffer, config->rx_buffer_size);\n    isotp->link.receive_arbitration_id = config->rx_id;\n\n    // Pre-allocate ISR-safe receive frame buffer to avoid dynamic allocation in interrupt context.\n    // This buffer is reused for each incoming TWAI frame received in the ISR.\n    memset(&isotp->isr_rx_frame_buffer, 0, sizeof(esp_isotp_frame_t));\n    isotp->isr_rx_frame_buffer.frame.buffer = isotp->isr_rx_frame_buffer.data_payload;\n    isotp->isr_rx_frame_buffer.frame.buffer_len = sizeof(isotp->isr_rx_frame_buffer.data_payload);\n\n    // Set user argument for TWAI operations.\n    isotp->link.user_send_can_arg = isotp;\n\n    // Save user callback functions\n    isotp->rx_callback = config->rx_callback;\n    isotp->tx_callback = config->tx_callback;\n    isotp->callback_arg = config->callback_arg;\n\n    // Set isotp-c wrapper callbacks if user callbacks provided.\n#ifdef ISO_TP_TRANSMIT_COMPLETE_CALLBACK\n    if (config->tx_callback) {\n        isotp_set_tx_done_cb(&isotp->link, esp_isotp_tx_wrapper, isotp);\n    }\n#endif\n\n#ifdef ISO_TP_RECEIVE_COMPLETE_CALLBACK\n    if (config->rx_callback) {\n        isotp_set_rx_done_cb(&isotp->link, esp_isotp_rx_wrapper, isotp);\n    }\n#endif\n\n    // Register TWAI callbacks.\n    twai_event_callbacks_t cbs = {\n        .on_rx_done = esp_isotp_rx_callback,\n        .on_tx_done = esp_isotp_tx_callback,\n    };\n    ret = twai_node_register_event_callbacks(twai_node, &cbs, isotp);\n    ESP_GOTO_ON_ERROR(ret, err, TAG, \"Failed to register event callbacks\");\n\n    // Enable TWAI node.\n    ret = twai_node_enable(twai_node);\n    ESP_GOTO_ON_ERROR(ret, err, TAG, \"Failed to enable TWAI node\");\n\n    isotp->twai_node = twai_node;\n    *out_handle = isotp;\n\n    return ESP_OK;\n\nerr:\n    if (isotp) {\n        if (isotp->isotp_rx_buffer) {\n            free(isotp->isotp_rx_buffer);\n        }\n        if (isotp->isotp_tx_buffer) {\n            free(isotp->isotp_tx_buffer);\n        }\n        if (isotp->tx_frame_array) {\n            free(isotp->tx_frame_array);\n        }\n        free(isotp);\n    }\n    return ret;\n}\n\n/**\n * @brief Delete an ISO-TP transport and free resources.\n *\n * Disables the TWAI node, cleans up TX frame pool and frees allocated\n * memory. Continues cleanup even if disabling TWAI fails.\n *\n * @param handle ISO-TP transport handle.\n * @return ESP_OK on success or the error from TWAI disable.\n */\nesp_err_t esp_isotp_delete(esp_isotp_handle_t handle)\n{\n    ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, \"Invalid parameters\");\n\n    esp_err_t ret = ESP_OK;\n\n    // Disable TWAI node after unregistering callbacks\n    esp_err_t twai_ret = twai_node_disable(handle->twai_node);\n    if (twai_ret != ESP_OK) {\n        ESP_LOGW(TAG, \"Failed to disable TWAI node: %s\", esp_err_to_name(twai_ret));\n        if (ret == ESP_OK) {\n            ret = twai_ret;\n        }\n    }\n\n    // Unregister TWAI callbacks first to prevent use-after-free during disable\n    twai_event_callbacks_t cbs = { 0 };\n    esp_err_t unreg_ret = twai_node_register_event_callbacks(handle->twai_node, &cbs, NULL);\n    if (unreg_ret != ESP_OK) {\n        ESP_LOGW(TAG, \"Failed to unregister TWAI callbacks: %s\", esp_err_to_name(unreg_ret));\n        ret = unreg_ret;\n    }\n\n    // Clean up ISO-TP link.\n    isotp_destroy_link(&handle->link);\n\n    // Clean up TX frame array (SLIST pool is automatically cleaned when frames are freed).\n    if (handle->tx_frame_array) {\n        free(handle->tx_frame_array);\n    }\n\n    // Free ISO-TP reassembly buffers and handle.\n    if (handle->isotp_tx_buffer) {\n        free(handle->isotp_tx_buffer);\n    }\n    if (handle->isotp_rx_buffer) {\n        free(handle->isotp_rx_buffer);\n    }\n    free(handle);\n\n    return ret;\n}\n\n\n/**\n * @brief Poll the ISO-TP link. Call this periodically from a task.\n *\n * @param handle ISO-TP transport handle.\n * @return ESP_OK on success, or an error code on failure.\n */\nesp_err_t esp_isotp_poll(esp_isotp_handle_t handle)\n{\n    ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, \"Invalid parameters\");\n\n    // Run ISO-TP state machine to check timeouts and send consecutive frames.\n    isotp_poll(&handle->link);\n\n    return ESP_OK;\n}\n\n/**\n * @brief Send a payload using ISO-TP.\n *\n * @param handle ISO-TP transport handle.\n * @param data Pointer to payload buffer.\n * @param size Payload size in bytes.\n * @return\n *  - ESP_OK on success\n *  - ESP_ERR_NOT_FINISHED when the send is still in progress\n *  - ESP_ERR_NO_MEM for buffer overflow conditions\n *  - ESP_ERR_INVALID_SIZE for invalid sizes\n *  - ESP_ERR_TIMEOUT on timeout\n *  - ESP_FAIL for other errors\n */\nesp_err_t esp_isotp_send(esp_isotp_handle_t handle, const uint8_t *data, uint32_t size)\n{\n    if (!(handle && data && size)) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    int ret = isotp_send(&handle->link, data, size);\n    switch (ret) {\n    case ISOTP_RET_OK:\n        return ESP_OK;\n    case ISOTP_RET_INPROGRESS:\n        return ESP_ERR_NOT_FINISHED;\n    case ISOTP_RET_OVERFLOW:    // Buffer overflow\n    case ISOTP_RET_NOSPACE:     // Not enough space in internal buffers\n        return ESP_ERR_NO_MEM;\n    case ISOTP_RET_LENGTH:      // Payload size exceeds buffer size\n        return ESP_ERR_INVALID_SIZE;\n    case ISOTP_RET_TIMEOUT:\n        return ESP_ERR_TIMEOUT;\n    case ISOTP_RET_ERROR:\n    default:\n        ESP_EARLY_LOGE(TAG, \"ISO-TP send failed with error code: %d\", ret);\n        return ESP_FAIL;\n    }\n}\n\n/**\n * @brief Send a payload with a specific TWAI ID.\n *\n * Uses the provided TWAI ID for this transmission instead of the default.\n *\n * @param handle ISO-TP transport handle.\n * @param id TWAI identifier (subject to STD/EXT mask based on configuration).\n * @param data Pointer to payload buffer.\n * @param size Payload size in bytes.\n * @return Same as esp_isotp_send().\n */\nesp_err_t esp_isotp_send_with_id(esp_isotp_handle_t handle, uint32_t id, const uint8_t *data, uint32_t size)\n{\n    if (!(handle && data && size)) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    if ((id & ~TWAI_EXT_ID_MASK) != 0) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    int ret = isotp_send_with_id(&handle->link, id, data, size);\n    switch (ret) {\n    case ISOTP_RET_OK:\n        return ESP_OK;\n    case ISOTP_RET_INPROGRESS:\n        return ESP_ERR_NOT_FINISHED;\n    case ISOTP_RET_OVERFLOW:    // Buffer overflow\n    case ISOTP_RET_NOSPACE:     // Not enough space in internal buffers\n        return ESP_ERR_NO_MEM;\n    case ISOTP_RET_LENGTH:      // Payload size exceeds buffer size\n        return ESP_ERR_INVALID_SIZE;\n    case ISOTP_RET_TIMEOUT:\n        return ESP_ERR_TIMEOUT;\n    case ISOTP_RET_ERROR:\n    default:\n        ESP_EARLY_LOGE(TAG, \"ISO-TP send with ID failed with error code: %d\", ret);\n        return ESP_FAIL;\n    }\n}\n\n/**\n * @brief Receive a payload using ISO-TP.\n *\n * @param handle ISO-TP transport handle.\n * @param data Output buffer for received data.\n * @param size Size of the output buffer in bytes.\n * @param received_size Actual number of bytes written to the buffer.\n * @return\n *  - ESP_OK when data is received\n *  - ESP_ERR_NOT_FOUND when no data is available\n *  - ESP_ERR_INVALID_SIZE when the buffer is too small or size invalid\n *  - ESP_ERR_INVALID_RESPONSE on sequence errors\n *  - ESP_ERR_TIMEOUT on timeout\n *  - ESP_FAIL for other errors\n */\nesp_err_t esp_isotp_receive(esp_isotp_handle_t handle, uint8_t *data, uint32_t size, uint32_t *received_size)\n{\n    ESP_RETURN_ON_FALSE(handle && data && size && received_size, ESP_ERR_INVALID_ARG, TAG, \"Invalid parameters\");\n\n    *received_size = 0;\n    int ret = isotp_receive(&handle->link, data, size, received_size);\n    switch (ret) {\n    case ISOTP_RET_OK:\n        return ESP_OK;\n    case ISOTP_RET_NO_DATA:\n        return ESP_ERR_NOT_FOUND;\n    case ISOTP_RET_OVERFLOW:    // Receive buffer too small for the message\n    case ISOTP_RET_LENGTH:      // Invalid length in message\n        return ESP_ERR_INVALID_SIZE;\n    case ISOTP_RET_NOSPACE:     // Not enough space in internal buffers (rare if configured correctly)\n        return ESP_ERR_NO_MEM;\n    case ISOTP_RET_WRONG_SN:    // Sequence number error\n        return ESP_ERR_INVALID_RESPONSE;\n    case ISOTP_RET_INPROGRESS:  // Should not happen in receive, but handle for robustness\n        return ESP_ERR_INVALID_STATE;\n    case ISOTP_RET_TIMEOUT:\n        return ESP_ERR_TIMEOUT;\n    case ISOTP_RET_ERROR:\n    default:\n        ESP_LOGE(TAG, \"ISO-TP receive failed with error code: %d\", ret);\n        return ESP_FAIL;\n    }\n}\n"
  },
  {
    "path": "esp_isotp/src/isotp_config.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#ifndef ISOTPC_CONFIG_H\n#define ISOTPC_CONFIG_H\n\n// This file overrides the default isotp_config.h from isotp-c submodule\n// Values are taken from ESP-IDF Kconfig system\n\n#include \"sdkconfig.h\"\n\n/* Max number of messages the receiver can receive at one time, this value\n * is affected by can driver queue length\n */\n#define ISO_TP_DEFAULT_BLOCK_SIZE CONFIG_ISO_TP_DEFAULT_BLOCK_SIZE\n\n/* The STmin parameter value specifies the minimum time gap allowed between\n * the transmission of consecutive frame network protocol data units\n */\n#define ISO_TP_DEFAULT_ST_MIN_US CONFIG_ISO_TP_DEFAULT_ST_MIN_US\n\n/* This parameter indicate how many FC N_PDU WTs can be transmitted by the\n * receiver in a row.\n */\n#define ISO_TP_MAX_WFT_NUMBER CONFIG_ISO_TP_MAX_WFT_NUMBER\n\n/* The default timeout to use when waiting for a response during a multi-frame send or receive. */\n#define ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US CONFIG_ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US\n\n/* Determines if by default, padding is added to ISO-TP message frames */\n#ifdef CONFIG_ISO_TP_FRAME_PADDING\n#define ISO_TP_FRAME_PADDING\n#endif\n\n/* The value to use when padding frames if enabled by ISO_TP_FRAME_PADDING */\n#define ISO_TP_FRAME_PADDING_VALUE CONFIG_ISO_TP_FRAME_PADDING_VALUE\n\n/* Always enable the additional user_data argument in isotp_user_send_can function */\n#define ISO_TP_USER_SEND_CAN_ARG\n\n/* Always enable the transmission complete callback */\n#define ISO_TP_TRANSMIT_COMPLETE_CALLBACK\n\n/* Always enable the receive complete callback */\n#define ISO_TP_RECEIVE_COMPLETE_CALLBACK\n\n#endif // ISOTPC_CONFIG_H\n"
  },
  {
    "path": "esp_jpeg/.build-test-rules.yml",
    "content": ""
  },
  {
    "path": "esp_jpeg/CHANGELOG.md",
    "content": "## 1.3.1\n\n- Fixed the format of Kconfig file\n\n## 1.3.0\n\n- Added option to get image size without decoding it\n\n## 1.2.1\n\n- Fixed decoding of non-conforming 0xFFFF marker\n\n## 1.2.0\n\n- Added option to for passing user defined working buffer\n\n## 1.1.0\n\n- Added support for decoding images without Huffman tables\n- Fixed undefined configuration options from Kconfig\n\n## 1.0.5~3\n\n- Added option to swap output color bytes regardless of JD_FORMAT\n\n## 1.0.4\n\n- Added ROM implementation support for ESP32-C6\n\n## 1.0.2\n\n- Fixed compiler warnings\n\n## 1.0.1\n\n- Fixed: exclude ESP32-C2 from list of ROM implementations\n\n## 1.0.0\n\n- Initial version\n"
  },
  {
    "path": "esp_jpeg/CMakeLists.txt",
    "content": "set(sources \"jpeg_decoder.c\")\nset(includes \"include\")\n\n# Compile only when cannot use ROM code\nif(NOT CONFIG_JD_USE_ROM)\n    list(APPEND sources \"tjpgd/tjpgd.c\")\n    list(APPEND includes \"tjpgd\")\nendif()\n\nif(CONFIG_JD_DEFAULT_HUFFMAN)\n    list(APPEND sources \"jpeg_default_huffman_table.c\")\nendif()\n\nidf_component_register(SRCS ${sources} INCLUDE_DIRS ${includes})\n"
  },
  {
    "path": "esp_jpeg/Kconfig",
    "content": "menu \"JPEG Decoder\"\n\n    config JD_USE_ROM\n        bool \"Use TinyJPG Decoder from ROM\"\n        depends on ESP_ROM_HAS_JPEG_DECODE\n        default y\n        help\n            By default, Espressif SoCs use TJpg decoder implemented in ROM code.\n            If this feature is disabled, new configuration of TJpg decoder can be used.\n            Refer to README.md for more details.\n\n    config JD_SZBUF\n        int \"Size of stream input buffer\"\n        depends on !JD_USE_ROM\n        default 512\n\n    config JD_FORMAT\n        int\n        depends on !JD_USE_ROM\n        default 0 if JD_FORMAT_RGB888\n        default 1 if JD_FORMAT_RGB565\n\n    choice\n        prompt \"Output pixel format\"\n        depends on !JD_USE_ROM\n        default JD_FORMAT_RGB888\n        help\n                Output format is selected at runtime.\n\n        config JD_FORMAT_RGB888\n            bool \"Support RGB565 and RGB888 output (16-bit/pix and 24-bit/pix)\"\n        config JD_FORMAT_RGB565\n            bool \"Support RGB565 output (16-bit/pix)\"\n    endchoice\n\n    config JD_USE_SCALE\n        bool \"Enable descaling\"\n        depends on !JD_USE_ROM\n        default y\n        help\n            If scaling is enabled, size of output image can be lowered during decoding.\n\n    config JD_TBLCLIP\n        bool \"Use table conversion for saturation arithmetic\"\n        depends on !JD_USE_ROM\n        default y\n        help\n            Use table conversion for saturation arithmetic. A bit faster, but increases 1 KB of code size.\n\n    config JD_FASTDECODE\n        int\n        depends on !JD_USE_ROM\n        default 0 if JD_FASTDECODE_BASIC\n        default 1 if JD_FASTDECODE_32BIT\n        default 2 if JD_FASTDECODE_TABLE\n\n    choice\n        prompt \"Optimization level\"\n        depends on !JD_USE_ROM\n        default JD_FASTDECODE_32BIT\n\n        config JD_FASTDECODE_BASIC\n            bool \"Basic optimization. Suitable for 8/16-bit MCUs\"\n        config JD_FASTDECODE_32BIT\n            bool \"+ 32-bit barrel shifter. Suitable for 32-bit MCUs\"\n        config JD_FASTDECODE_TABLE\n            bool \"+ Table conversion for huffman decoding (wants 6 << HUFF_BIT bytes of RAM)\"\n    endchoice\n\n    config JD_DEFAULT_HUFFMAN\n        bool \"Support images without Huffman table\"\n        depends on !JD_USE_ROM\n        default n\n        help\n            Enable this option to support decoding JPEG images that lack an embedded Huffman table.\n            When enabled, a default Huffman table is used during decoding, allowing the JPEG decoder to handle\n            images without explicitly provided Huffman tables.\n\n            Note: Enabling this option increases ROM usage due to the inclusion of default Huffman tables.\nendmenu\n"
  },
  {
    "path": "esp_jpeg/README.md",
    "content": "# JPEG Decoder: TJpgDec - Tiny JPEG Decompressor\n\n[![Component Registry](https://components.espressif.com/components/espressif/esp_jpeg/badge.svg)](https://components.espressif.com/components/espressif/esp_jpeg)\n![maintenance-status](https://img.shields.io/badge/maintenance-actively--developed-brightgreen.svg)\n\nTJpgDec is a lightweight JPEG image decompressor optimized for embedded systems with minimal memory consumption.\n\nOn some microcontrollers, TJpgDec is available in ROM and will be used by default, though this can be disabled in menuconfig if desired[^1].\n\n[^1]: **_NOTE:_** When the ROM decoder is used, the configuration can't be changed. The configuration is fixed.\n\n## Features\n\n**Compilation configuration:**\n- Stream input buffer size (default: 512 bytes)\n- Output pixel format (default: RGB888; options: RGB888/RGB565)\n- Enable/disable output descaling (default: enabled)\n- Use table-based saturation for arithmetic operations (default: enabled)\n- Use default Huffman tables: Useful from decoding frames from cameras, that do not provide Huffman tables (default: disabled to save ROM)\n- Three optimization levels (default: 32-bit MCUs) for different CPU types:\n  - 8/16-bit MCUs\n  - 32-bit MCUs\n  - Table-based Huffman decoding\n\n**Runtime configuration:**\n- Pixel format options: RGB888, RGB565\n- Selectable scaling ratios: 1/1, 1/2, 1/4, or 1/8 (chosen at decompression)\n- Option to swap the first and last bytes of color values\n\n## TJpgDec in ROM\n\nOn certain microcontrollers, TJpgDec is available in ROM and used by default. This can be disabled in menuconfig if you prefer to use the library code provided in this component.\n\n### List of MCUs, which have TJpgDec in ROM\n- ESP32\n- ESP32-S3\n- ESP32-C3\n- ESP32-C6\n- ESP32-C5\n- ESP32-C61\n\n### Fixed compilation configuration of the ROM code\nThe ROM version uses the following fixed settings:\n- Stream input buffer: 512 bytes\n- Output pixel format: RGB888\n- Output descaling: enabled\n- Saturation table: enabled\n- Optimization level: Basic (JD_FASTDECODE = 0)\n\n### Pros and cons using ROM code\n\n**Advantages:**\n- Saves approximately 5 KB of flash memory with the same configuration\n\n**Disadvantages:**\n- Compilation configuration cannot be changed\n- Certain configurations may provide faster performance\n\n## Speed comparison\n\nThe table below shows example decoding times for a JPEG image using various configurations:\n* Image size: 320 x 180 px\n* Output format: RGB565\n* CPU: ESP32-S3\n* CPU frequency: 240 MHz\n* SPI mode: DIO\n* Internal RAM used\n* Measured in 1000 retries\n\n| ROM used | JD_SZBUF | JD_FORMAT | JD_USE_SCALE | JD_TBLCLIP | JD_FASTDECODE | RAM buffer | Flash size | Approx. time |\n| :------: | :------: | :-------: | :----------: | :--------: | :-----------: | :--------: | :--------: | :----------: |\n|   YES    |    512   |   RGB888  |      1       |      1     |       0       |    3.1 kB  |    0 kB    |     52 ms    |    \n|   NO     |    512   |   RGB888  |      1       |      1     |       0       |    3.1 kB  |    5 kB    |     50 ms    |    \n|   NO     |    512   |   RGB888  |      1       |      0     |       0       |    3.1 kB  |    4 kB    |     68 ms    |     \n|   NO     |    512   |   RGB888  |      1       |      1     |       1       |    3.1 kB  |    5 kB    |     50 ms    |      \n|   NO     |    512   |   RGB888  |      1       |      0     |       1       |    3.1 kB  |    4 kB    |     62 ms    |   \n|   NO     |    512   |   RGB888  |      1       |      1     |       2       |   65.5 kB  |   5.5 kB   |     46 ms    |  \n|   NO     |    512   |   RGB888  |      1       |      0     |       2       |   65.5 kB  |   4.5 kB   |     59 ms    |  \n|   NO     |    512   |   RGB565  |      1       |      1     |       0       |    5 kB    |    5 kB    |     60 ms    |     \n|   NO     |    512   |   RGB565  |      1       |      1     |       1       |    5 kB    |    5 kB    |     59 ms    |     \n|   NO     |    512   |   RGB565  |      1       |      1     |       2       |   65.5 kB  |   5.5 kB   |     56 ms    |     \n\n## Add to project\n\nPackages from this repository are uploaded to [Espressif's component service](https://components.espressif.com/).\nYou can add them to your project via `idf.py add-dependancy`, e.g. \n```\n    idf.py add-dependency esp_jpeg==1.0.0\n```\n\nAlternatively, you can create `idf_component.yml`. More is in [Espressif's documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html).\n\n## Example use\n\nHere is example of usage. This calling is **blocking**.\n\n```\nesp_jpeg_image_cfg_t jpeg_cfg = {\n    .indata = (uint8_t *)jpeg_img_buf,\n    .indata_size = jpeg_img_buf_size,\n    .outbuf = out_img_buf,\n    .outbuf_size = out_img_buf_size,\n    .out_format = JPEG_IMAGE_OUT_FORMAT_RGB565,\n    .out_scale = JPEG_IMAGE_SCALE_0,\n    .flags = {\n        .swap_color_bytes = 1,\n    }\n};\nesp_jpeg_image_output_t outimg;\n\nesp_jpeg_decode(&jpeg_cfg, &outimg);\n```\n"
  },
  {
    "path": "esp_jpeg/examples/get_started/CMakeLists.txt",
    "content": "# The following lines of boilerplate have to be in your project's CMakeLists\n# in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(lcd_tjpgd)\n"
  },
  {
    "path": "esp_jpeg/examples/get_started/README.md",
    "content": "# LCD tjpgd example\n\n## Overview\n\nThis example shows how to decode a jpeg image and display it on an SPI-interfaced LCD, and rotates the image periodically.\n\nIf you want to adapt this example to another type of display or pinout, check [lcd_tjpgd_example_main.c](main/lcd_tjpgd_example_main.c) for comments with some implementation details.\n\n## How to Use Example\n\n### Hardware Required\n\n* An ESP development board\n* An SPI-interfaced LCD\n* An USB cable for power supply and programming\n\n### Hardware Connection\n\nThe connection between ESP Board and the LCD is as follows:\n\n```text\n      ESP Board                            LCD Screen\n      +---------+              +---------------------------------+\n      |         |              |                                 |\n      |     3V3 +--------------+ VCC   +----------------------+  |\n      |         |              |       |                      |  |\n      |     GND +--------------+ GND   |                      |  |\n      |         |              |       |                      |  |\n      |   DATA0 +--------------+ MOSI  |                      |  |\n      |         |              |       |                      |  |\n      |    PCLK +--------------+ SCK   |                      |  |\n      |         |              |       |                      |  |\n      |      CS +--------------+ CS    |                      |  |\n      |         |              |       |                      |  |\n      |     D/C +--------------+ D/C   |                      |  |\n      |         |              |       |                      |  |\n      |     RST +--------------+ RST   |                      |  |\n      |         |              |       |                      |  |\n      |BK_LIGHT +--------------+ BCKL  +----------------------+  |\n      |         |              |                                 |\n      +---------+              +---------------------------------+\n```\n\nThe GPIO number used by this example can be changed in [lcd_tjpgd_example_main.c](main/lcd_tjpgd_example_main.c), where:\n\n| GPIO number              | LCD pin |\n| ------------------------ | ------- |\n| EXAMPLE_PIN_NUM_PCLK     | SCK     |\n| EXAMPLE_PIN_NUM_CS       | CS      |\n| EXAMPLE_PIN_NUM_DC       | DC      |\n| EXAMPLE_PIN_NUM_RST      | RST     |\n| EXAMPLE_PIN_NUM_DATA0    | MOSI    |\n| EXAMPLE_PIN_NUM_BK_LIGHT | BCKL    |\n\nEspecially, please pay attention to the level used to turn on the LCD backlight, some LCD module needs a low level to turn it on, while others take a high level. You can change the backlight level macro `EXAMPLE_LCD_BK_LIGHT_ON_LEVEL` in [lcd_tjpgd_example_main.c](main/lcd_tjpgd_example_main.c).\n\n### Build and Flash\n\nRun `idf.py -p PORT flash monitor` to build, flash and monitor the project. A flowing picture will be shown on the LCD screen.\n\n(To exit the serial monitor, type ``Ctrl-]``.)\n\nSee the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.\n\n## Troubleshooting\n\nFor any technical queries, please open an [issue] (https://github.com/espressif/idf-extra-components/issues) on GitHub. We will get back to you soon.\n"
  },
  {
    "path": "esp_jpeg/examples/get_started/main/CMakeLists.txt",
    "content": "set(srcs \"pretty_effect.c\"\n         \"lcd_tjpgd_example_main.c\"\n         \"decode_image.c\"\n    )\n\nidf_component_register(SRCS ${srcs}\n                       INCLUDE_DIRS \".\"\n                       EMBED_FILES image.jpg\n                       PRIV_REQUIRES esp_lcd driver)\n"
  },
  {
    "path": "esp_jpeg/examples/get_started/main/Kconfig.projbuild",
    "content": "menu \"Example Configuration\"\n\n    config EXAMPLE_LCD_FLUSH_PARALLEL_LINES\n        int \"LCD flush parallel lines\"\n        default 12 if IDF_TARGET_ESP32C2\n        default 16\n        help\n            To speed up transfers, every SPI transfer sends a bunch of lines.\n\nendmenu\n"
  },
  {
    "path": "esp_jpeg/examples/get_started/main/decode_image.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n\n/*\nThe image used for the effect on the LCD in the SPI master example is stored in flash\nas a jpeg file. This file contains the decode_image routine, which uses the tiny JPEG\ndecoder library to decode this JPEG into a format that can be sent to the display.\n\nKeep in mind that the decoder library cannot handle progressive files (will give\n``Image decoder: jd_prepare failed (8)`` as an error) so make sure to save in the correct\nformat if you want to use a different image file.\n*/\n\n#include <string.h>\n#include \"decode_image.h\"\n#include \"jpeg_decoder.h\"\n#include \"esp_log.h\"\n#include \"esp_check.h\"\n#include \"freertos/FreeRTOS.h\"\n\n//Reference the binary-included jpeg file\nextern const uint8_t image_jpg_start[] asm(\"_binary_image_jpg_start\");\nextern const uint8_t image_jpg_end[] asm(\"_binary_image_jpg_end\");\n//Define the height and width of the jpeg file. Make sure this matches the actual jpeg\n//dimensions.\n\nconst char *TAG = \"ImageDec\";\n\n//Decode the embedded image into pixel lines that can be used with the rest of the logic.\nesp_err_t decode_image(uint16_t **pixels)\n{\n    *pixels = NULL;\n    esp_err_t ret = ESP_OK;\n\n    //Allocate pixel memory. Each line is an array of IMAGE_W 16-bit pixels; the `*pixels` array itself contains pointers to these lines.\n    *pixels = calloc(IMAGE_H * IMAGE_W, sizeof(uint16_t));\n    ESP_GOTO_ON_FALSE((*pixels), ESP_ERR_NO_MEM, err, TAG, \"Error allocating memory for lines\");\n\n    //JPEG decode config\n    esp_jpeg_image_cfg_t jpeg_cfg = {\n        .indata = (uint8_t *)image_jpg_start,\n        .indata_size = image_jpg_end - image_jpg_start,\n        .outbuf = (uint8_t *)(*pixels),\n        .outbuf_size = IMAGE_W * IMAGE_H * sizeof(uint16_t),\n        .out_format = JPEG_IMAGE_FORMAT_RGB565,\n        .out_scale = JPEG_IMAGE_SCALE_0,\n        .flags = {\n            .swap_color_bytes = 1,\n        }\n    };\n\n    //JPEG decode\n    esp_jpeg_image_output_t outimg;\n    esp_jpeg_decode(&jpeg_cfg, &outimg);\n\n    ESP_LOGI(TAG, \"JPEG image decoded! Size of the decoded image is: %dpx x %dpx\", outimg.width, outimg.height);\n\n    return ret;\nerr:\n    //Something went wrong! Exit cleanly, de-allocating everything we allocated.\n    if (*pixels != NULL) {\n        free(*pixels);\n    }\n    return ret;\n}\n"
  },
  {
    "path": "esp_jpeg/examples/get_started/main/decode_image.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n\n#pragma once\n\n#include <stdint.h>\n#include \"esp_err.h\"\n\n#define IMAGE_W 320\n#define IMAGE_H 240\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief Decode the jpeg ``image.jpg`` embedded into the program file into pixel data.\n *\n * @param pixels A pointer to a pointer for an array of rows, which themselves are an array of pixels.\n *        Effectively, you can get the pixel data by doing ``decode_image(&myPixels); pixelval=myPixels[ypos][xpos];``\n * @return - ESP_ERR_NOT_SUPPORTED if image is malformed or a progressive jpeg file\n *         - ESP_ERR_NO_MEM if out of memory\n *         - ESP_OK on successful decode\n */\nesp_err_t decode_image(uint16_t **pixels);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_jpeg/examples/get_started/main/idf_component.yml",
    "content": "dependencies:\n  idf: \">=5.0\"\n  esp_jpeg:\n    version: \"*\"\n    override_path: \"../../../\"\n"
  },
  {
    "path": "esp_jpeg/examples/get_started/main/lcd_tjpgd_example_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n\n#include <stdio.h>\n#include \"sdkconfig.h\"\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"esp_lcd_panel_io.h\"\n#include \"esp_lcd_panel_vendor.h\"\n#include \"esp_lcd_panel_ops.h\"\n#include \"esp_heap_caps.h\"\n#include \"driver/spi_master.h\"\n#include \"driver/gpio.h\"\n#include \"pretty_effect.h\"\n\n// Using SPI2 in the example, as it also supports octal modes on some targets\n#define LCD_HOST       SPI2_HOST\n// To speed up transfers, every SPI transfer sends a bunch of lines. This define specifies how many.\n// More means more memory use, but less overhead for setting up / finishing transfers. Make sure 240\n// is dividable by this.\n#define PARALLEL_LINES CONFIG_EXAMPLE_LCD_FLUSH_PARALLEL_LINES\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////// Please update the following configuration according to your LCD spec //////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#define EXAMPLE_LCD_PIXEL_CLOCK_HZ (20 * 1000 * 1000)\n#define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL  0\n#define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL\n#define EXAMPLE_PIN_NUM_DATA0          23  /*!< for 1-line SPI, this also refereed as MOSI */\n#define EXAMPLE_PIN_NUM_PCLK           19\n#define EXAMPLE_PIN_NUM_CS             22\n#define EXAMPLE_PIN_NUM_DC             21\n#define EXAMPLE_PIN_NUM_RST            18\n#define EXAMPLE_PIN_NUM_BK_LIGHT       5\n\n// The pixel number in horizontal and vertical\n#define EXAMPLE_LCD_H_RES              320\n#define EXAMPLE_LCD_V_RES              240\n// Bit number used to represent command and parameter\n#define EXAMPLE_LCD_CMD_BITS           8\n#define EXAMPLE_LCD_PARAM_BITS         8\n\n// Simple routine to generate some patterns and send them to the LCD. Because the\n// SPI driver handles transactions in the background, we can calculate the next line\n// while the previous one is being sent.\nstatic uint16_t *s_lines[2];\nstatic void display_pretty_colors(esp_lcd_panel_handle_t panel_handle)\n{\n    int frame = 0;\n    // Indexes of the line currently being sent to the LCD and the line we're calculating\n    int sending_line = 0;\n    int calc_line = 0;\n\n    while (1) {\n        frame++;\n        for (int y = 0; y < EXAMPLE_LCD_V_RES; y += PARALLEL_LINES) {\n            // Calculate a line\n            pretty_effect_calc_lines(s_lines[calc_line], y, frame, PARALLEL_LINES);\n            sending_line = calc_line;\n            calc_line = !calc_line;\n            // Send the calculated data\n            esp_lcd_panel_draw_bitmap(panel_handle, 0, y, 0 + EXAMPLE_LCD_H_RES, y + PARALLEL_LINES, s_lines[sending_line]);\n        }\n    }\n}\n\nvoid app_main(void)\n{\n    gpio_config_t bk_gpio_config = {\n        .mode = GPIO_MODE_OUTPUT,\n        .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT\n    };\n    // Initialize the GPIO of backlight\n    ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));\n\n    spi_bus_config_t buscfg = {\n        .sclk_io_num = EXAMPLE_PIN_NUM_PCLK,\n        .mosi_io_num = EXAMPLE_PIN_NUM_DATA0,\n        .miso_io_num = -1,\n        .quadwp_io_num = -1,\n        .quadhd_io_num = -1,\n        .max_transfer_sz = PARALLEL_LINES * EXAMPLE_LCD_H_RES * 2 + 8\n    };\n    // Initialize the SPI bus\n    ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));\n\n    esp_lcd_panel_io_handle_t io_handle = NULL;\n    esp_lcd_panel_io_spi_config_t io_config = {\n        .dc_gpio_num = EXAMPLE_PIN_NUM_DC,\n        .cs_gpio_num = EXAMPLE_PIN_NUM_CS,\n        .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,\n        .lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,\n        .lcd_param_bits = EXAMPLE_LCD_PARAM_BITS,\n        .spi_mode = 0,\n        .trans_queue_depth = 10,\n    };\n    // Attach the LCD to the SPI bus\n    ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &io_handle));\n\n    esp_lcd_panel_handle_t panel_handle = NULL;\n    esp_lcd_panel_dev_config_t panel_config = {\n        .reset_gpio_num = EXAMPLE_PIN_NUM_RST,\n        .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR,\n        .bits_per_pixel = 16,\n    };\n    // Initialize the LCD configuration\n    ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));\n\n    // Turn off backlight to avoid unpredictable display on the LCD screen while initializing\n    // the LCD panel driver. (Different LCD screens may need different levels)\n    ESP_ERROR_CHECK(gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL));\n\n    // Reset the display\n    ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));\n    // Initialize LCD panel\n    ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));\n    // Swap x and y axis (Different LCD screens may need different options)\n    ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel_handle, true));\n    // Turn on the screen\n    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));\n\n    // Turn on backlight (Different LCD screens may need different levels)\n    ESP_ERROR_CHECK(gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL));\n\n    // Initialize the effect displayed\n    ESP_ERROR_CHECK(pretty_effect_init());\n\n    // Allocate memory for the pixel buffers\n    for (int i = 0; i < 2; i++) {\n        s_lines[i] = heap_caps_malloc(EXAMPLE_LCD_H_RES * PARALLEL_LINES * sizeof(uint16_t), MALLOC_CAP_DMA);\n        assert(s_lines[i] != NULL);\n    }\n\n    //Go do nice stuff.\n    display_pretty_colors(panel_handle);\n}\n"
  },
  {
    "path": "esp_jpeg/examples/get_started/main/pretty_effect.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n\n#include <math.h>\n#include \"pretty_effect.h\"\n#include \"decode_image.h\"\n\nuint16_t *pixels;\n\n//Grab a rgb16 pixel from the esp32_tiles image\nstatic inline uint16_t get_bgnd_pixel(int x, int y)\n{\n    //Get color of the pixel on x,y coords\n    return (uint16_t) * (pixels + (y * IMAGE_W) + x);\n}\n\n//This variable is used to detect the next frame.\nstatic int prev_frame = -1;\n\n//Instead of calculating the offsets for each pixel we grab, we pre-calculate the valueswhenever a frame changes, then reuse\n//these as we go through all the pixels in the frame. This is much, much faster.\nstatic int8_t xofs[320], yofs[240];\nstatic int8_t xcomp[320], ycomp[240];\n\n//Calculate the pixel data for a set of lines (with implied line size of 320). Pixels go in dest, line is the Y-coordinate of the\n//first line to be calculated, linect is the amount of lines to calculate. Frame increases by one every time the entire image\n//is displayed; this is used to go to the next frame of animation.\nvoid pretty_effect_calc_lines(uint16_t *dest, int line, int frame, int linect)\n{\n    if (frame != prev_frame) {\n        //We need to calculate a new set of offset coefficients. Take some random sines as offsets to make everything\n        //look pretty and fluid-y.\n        for (int x = 0; x < 320; x++) {\n            xofs[x] = sin(frame * 0.15 + x * 0.06) * 4;\n        }\n        for (int y = 0; y < 240; y++) {\n            yofs[y] = sin(frame * 0.1 + y * 0.05) * 4;\n        }\n        for (int x = 0; x < 320; x++) {\n            xcomp[x] = sin(frame * 0.11 + x * 0.12) * 4;\n        }\n        for (int y = 0; y < 240; y++) {\n            ycomp[y] = sin(frame * 0.07 + y * 0.15) * 4;\n        }\n        prev_frame = frame;\n    }\n    for (int y = line; y < line + linect; y++) {\n        for (int x = 0; x < 320; x++) {\n            *dest++ = get_bgnd_pixel(x + yofs[y] + xcomp[x], y + xofs[x] + ycomp[y]);\n        }\n    }\n}\n\nesp_err_t pretty_effect_init(void)\n{\n    return decode_image(&pixels);\n}\n"
  },
  {
    "path": "esp_jpeg/examples/get_started/main/pretty_effect.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n\n#pragma once\n#include <stdint.h>\n#include \"esp_err.h\"\n\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief Calculate the effect for a bunch of lines.\n *\n * @param dest Destination for the pixels. Assumed to be LINECT * 320 16-bit pixel values.\n * @param line Starting line of the chunk of lines.\n * @param frame Current frame, used for animation\n * @param linect Amount of lines to calculate\n */\nvoid pretty_effect_calc_lines(uint16_t *dest, int line, int frame, int linect);\n\n\n/**\n * @brief Initialize the effect\n *\n * @return ESP_OK on success, an error from the jpeg decoder otherwise.\n */\nesp_err_t pretty_effect_init(void);\n\n#ifdef __cplusplus\n}\n#endif"
  },
  {
    "path": "esp_jpeg/idf_component.yml",
    "content": "version: \"1.3.1\"\ndescription: \"JPEG Decoder: TJpgDec\"\nurl: https://github.com/espressif/idf-extra-components/tree/master/esp_jpeg/\ndependencies:\n  idf: \">=5.0\"\n"
  },
  {
    "path": "esp_jpeg/include/jpeg_decoder.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include \"esp_err.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief Scale of output image\n *\n */\ntypedef enum {\n    JPEG_IMAGE_SCALE_0 = 0, /*!< No scale */\n    JPEG_IMAGE_SCALE_1_2,   /*!< Scale 1:2 */\n    JPEG_IMAGE_SCALE_1_4,   /*!< Scale 1:4 */\n    JPEG_IMAGE_SCALE_1_8,   /*!< Scale 1:8 */\n} esp_jpeg_image_scale_t;\n\n/**\n * @brief Format of output image\n *\n */\ntypedef enum {\n    JPEG_IMAGE_FORMAT_RGB888 = 0,   /*!< Format RGB888 */\n    JPEG_IMAGE_FORMAT_RGB565,       /*!< Format RGB565 */\n} esp_jpeg_image_format_t;\n\n/**\n * @brief JPEG Configuration Type\n *\n */\ntypedef struct esp_jpeg_image_cfg_s {\n    uint8_t *indata;        /*!< Input JPEG image */\n    uint32_t indata_size;   /*!< Size of input image  */\n    uint8_t *outbuf;        /*!< Output buffer */\n    uint32_t outbuf_size;   /*!< Output buffer size */\n    esp_jpeg_image_format_t out_format; /*!< Output image format */\n    esp_jpeg_image_scale_t  out_scale; /*!< Output scale */\n\n    struct {\n        uint8_t swap_color_bytes: 1; /*!< Swap first and last color bytes */\n    } flags;\n\n    struct {\n        void *working_buffer;       /*!< If set to NULL, a working buffer will be allocated in esp_jpeg_decode().\n                                         Tjpgd does not use dynamic allocation, se we pass this buffer to Tjpgd that uses it as scratchpad */\n        size_t working_buffer_size; /*!< Size of the working buffer. Must be set it working_buffer != NULL.\n                                         Default size is 3.1kB or 65kB if JD_FASTDECODE == 2 */\n    } advanced;\n\n    struct {\n        uint32_t read;  /*!< Internal count of read bytes */\n    } priv;\n} esp_jpeg_image_cfg_t;\n\n/**\n * @brief JPEG output info\n */\ntypedef struct esp_jpeg_image_output_s {\n    uint16_t width;    /*!< Width of the output image */\n    uint16_t height;   /*!< Height of the output image */\n    size_t output_len; /*!< Length of the output image in bytes */\n} esp_jpeg_image_output_t;\n\n/**\n * @brief Decode JPEG image\n *\n * @note This function is blocking.\n *\n * @param[in]  cfg: Configuration structure\n * @param[out] img: Output image info\n *\n * @return\n *      - ESP_OK            on success\n *      - ESP_ERR_NO_MEM    if there is no memory for allocating main structure\n *      - ESP_FAIL          if there is an error in decoding JPEG\n */\nesp_err_t esp_jpeg_decode(esp_jpeg_image_cfg_t *cfg, esp_jpeg_image_output_t *img);\n\n/**\n * @brief Get information about the JPEG image\n *\n * Use this function to get the size of the JPEG image without decoding it.\n * Allocate a buffer of size img->output_len to store the decoded image.\n *\n * @note cfg->outbuf and cfg->outbuf_size are not used in this function.\n * @param[in]  cfg: Configuration structure\n * @param[out] img: Output image info\n *\n * @return\n *      - ESP_OK              on success\n *      - ESP_ERR_INVALID_ARG if cfg or img is NULL\n *      - ESP_FAIL            if there is an error in decoding JPEG\n */\nesp_err_t esp_jpeg_get_image_info(esp_jpeg_image_cfg_t *cfg, esp_jpeg_image_output_t *img);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_jpeg/jpeg_decoder.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"esp_system.h\"\n#include \"esp_rom_caps.h\"\n#include \"esp_log.h\"\n#include \"esp_err.h\"\n#include \"esp_check.h\"\n#include \"jpeg_decoder.h\"\n\n#if CONFIG_JD_USE_ROM\n/* When supported in ROM, use ROM functions */\n#if defined(ESP_ROM_HAS_JPEG_DECODE)\n#include \"rom/tjpgd.h\"\n#else\n#error Using JPEG decoder from ROM is not supported for selected target. Please select external code in menuconfig.\n#endif\n\n/* The ROM code of TJPGD is older and has different return type in decode callback */\ntypedef unsigned int jpeg_decode_out_t;\n#else\n/* When Tiny JPG Decoder is not in ROM or selected external code */\n#include \"tjpgd.h\"\n\n/* The TJPGD outside the ROM code is newer and has different return type in decode callback */\ntypedef int jpeg_decode_out_t;\n#endif\n\nstatic const char *TAG = \"JPEG\";\n\n#define LOBYTE(u16)     ((uint8_t)(((uint16_t)(u16)) & 0xff))\n#define HIBYTE(u16)     ((uint8_t)((((uint16_t)(u16))>>8) & 0xff))\n\n#if defined(JD_FASTDECODE) && (JD_FASTDECODE == 2)\n#define JPEG_WORK_BUF_SIZE  65472\n#else\n#define JPEG_WORK_BUF_SIZE  3100    /* Recommended buffer size; Independent on the size of the image */\n#endif\n\n/* If not set JD_FORMAT, it is set in ROM to RGB888, otherwise, it can be set in config */\n#ifndef JD_FORMAT\n#define JD_FORMAT 0\n#endif\n\n/* Output color bytes from tjpgd (depends on JD_FORMAT) */\n#if (JD_FORMAT==0)\n#define ESP_JPEG_COLOR_BYTES    3\n#elif  (JD_FORMAT==1)\n#define ESP_JPEG_COLOR_BYTES    2\n#elif  (JD_FORMAT==2)\n#error Grayscale image output format is not supported\n#define ESP_JPEG_COLOR_BYTES    1\n#endif\n\n/*******************************************************************************\n* Function definitions\n*******************************************************************************/\nstatic uint8_t jpeg_get_div_by_scale(esp_jpeg_image_scale_t scale);\nstatic uint8_t jpeg_get_color_bytes(esp_jpeg_image_format_t format);\n\nstatic unsigned int jpeg_decode_in_cb(JDEC *jd, uint8_t *buff, unsigned int nbyte);\nstatic jpeg_decode_out_t jpeg_decode_out_cb(JDEC *jd, void *bitmap, JRECT *rect);\nstatic inline uint16_t ldb_word(const void *ptr);\n/*******************************************************************************\n* Public API functions\n*******************************************************************************/\n\nesp_err_t esp_jpeg_decode(esp_jpeg_image_cfg_t *cfg, esp_jpeg_image_output_t *img)\n{\n    esp_err_t ret = ESP_OK;\n    uint8_t *workbuf = NULL;\n    JRESULT res;\n    JDEC JDEC;\n\n    assert(cfg != NULL);\n    assert(img != NULL);\n\n    const bool allocate_buffer = (cfg->advanced.working_buffer == NULL);\n    const size_t workbuf_size = allocate_buffer ? JPEG_WORK_BUF_SIZE : cfg->advanced.working_buffer_size;\n    if (allocate_buffer) {\n        workbuf = heap_caps_malloc(JPEG_WORK_BUF_SIZE, MALLOC_CAP_DEFAULT);\n        ESP_GOTO_ON_FALSE(workbuf, ESP_ERR_NO_MEM, err, TAG, \"no mem for JPEG work buffer\");\n    } else {\n        workbuf = cfg->advanced.working_buffer;\n        ESP_RETURN_ON_FALSE(workbuf_size != 0, ESP_ERR_INVALID_ARG, TAG, \"Working buffer size not defined!\");\n    }\n\n\n    cfg->priv.read = 0;\n\n    /* Prepare image */\n    res = jd_prepare(&JDEC, jpeg_decode_in_cb, workbuf, workbuf_size, cfg);\n    ESP_GOTO_ON_FALSE((res == JDR_OK), ESP_FAIL, err, TAG, \"Error in preparing JPEG image! %d\", res);\n\n    const uint8_t scale_div       = jpeg_get_div_by_scale(cfg->out_scale);\n    const uint8_t out_color_bytes = jpeg_get_color_bytes(cfg->out_format);\n\n    /* Size of output image */\n    const uint32_t outsize = (JDEC.height / scale_div) * (JDEC.width / scale_div) * out_color_bytes;\n    ESP_GOTO_ON_FALSE((outsize <= cfg->outbuf_size), ESP_ERR_NO_MEM, err, TAG, \"Not enough size in output buffer!\");\n\n    /* Size of output image */\n    img->height = JDEC.height / scale_div;\n    img->width = JDEC.width / scale_div;\n    img->output_len = outsize;\n\n    /* Decode JPEG */\n    res = jd_decomp(&JDEC, jpeg_decode_out_cb, cfg->out_scale);\n    ESP_GOTO_ON_FALSE((res == JDR_OK), ESP_FAIL, err, TAG, \"Error in decoding JPEG image! %d\", res);\n\nerr:\n    if (workbuf && allocate_buffer) {\n        free(workbuf);\n    }\n\n    return ret;\n}\n\nesp_err_t esp_jpeg_get_image_info(esp_jpeg_image_cfg_t *cfg, esp_jpeg_image_output_t *img)\n{\n    if (cfg == NULL || img == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    } else if (cfg->indata == NULL || cfg->indata_size < 5) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    esp_err_t ret = ESP_FAIL;\n\n    if (ldb_word(cfg->indata) != 0xFFD8) {\n        return ESP_FAIL;    /* Err: SOI is not detected */\n    }\n    unsigned ofs = 2; // Start after SOI marker\n\n    while (true) {\n        /* Get a JPEG marker */\n        uint8_t *seg = cfg->indata + ofs;       /* Segment pointer */\n        unsigned short marker = ldb_word(seg);  /* Marker */\n        unsigned int len = ldb_word(seg + 2);   /* Length field */\n        if (len <= 2 || (marker >> 8) != 0xFF) {\n            return ESP_FAIL;\n        }\n        ofs += 2 + len; /* Number of bytes loaded */\n        if (ofs > cfg->indata_size) {\n            return ESP_FAIL; // No more data\n        }\n\n        if ((marker & 0xFF) == 0xC0) {  /* SOF0 (baseline JPEG) */\n            seg += 4; /* Skip marker and length field */\n\n            /* Size of output image */\n            img->height = ldb_word(seg + 1);\n            img->width = ldb_word(seg + 3);\n            const uint8_t scale_div       = jpeg_get_div_by_scale(cfg->out_scale);\n            const uint8_t out_color_bytes = jpeg_get_color_bytes(cfg->out_format);\n            img->output_len = (img->height / scale_div) * (img->width / scale_div) * out_color_bytes;\n            ret = ESP_OK;\n            break;\n        }\n    }\n    return ret;\n}\n\n/*******************************************************************************\n* Private API functions\n*******************************************************************************/\n\nstatic unsigned int jpeg_decode_in_cb(JDEC *dec, uint8_t *buff, unsigned int nbyte)\n{\n    assert(dec != NULL);\n\n    uint32_t to_read = nbyte;\n    esp_jpeg_image_cfg_t *cfg = (esp_jpeg_image_cfg_t *)dec->device;\n    assert(cfg != NULL);\n\n    if (buff) {\n        if (cfg->priv.read + to_read > cfg->indata_size) {\n            to_read = cfg->indata_size - cfg->priv.read;\n        }\n\n        /* Copy data from JPEG image */\n        memcpy(buff, &cfg->indata[cfg->priv.read], to_read);\n        cfg->priv.read += to_read;\n    } else if (buff == NULL) {\n        /* Skip data */\n        cfg->priv.read += to_read;\n    }\n\n    return to_read;\n}\n\nstatic jpeg_decode_out_t jpeg_decode_out_cb(JDEC *dec, void *bitmap, JRECT *rect)\n{\n    uint16_t color = 0;\n    assert(dec != NULL);\n\n    esp_jpeg_image_cfg_t *cfg = (esp_jpeg_image_cfg_t *)dec->device;\n    assert(cfg != NULL);\n    assert(bitmap != NULL);\n    assert(rect != NULL);\n\n    uint8_t scale_div = jpeg_get_div_by_scale(cfg->out_scale);\n    uint8_t out_color_bytes = jpeg_get_color_bytes(cfg->out_format);\n\n    /* Copy decoded image data to output buffer */\n    uint8_t *in = (uint8_t *)bitmap;\n    uint32_t line = dec->width / scale_div;\n    uint8_t *dst = (uint8_t *)cfg->outbuf;\n    for (int y = rect->top; y <= rect->bottom; y++) {\n        for (int x = rect->left; x <= rect->right; x++) {\n            if ( (JD_FORMAT == 0 && cfg->out_format == JPEG_IMAGE_FORMAT_RGB888) ||\n                    (JD_FORMAT == 1 && cfg->out_format == JPEG_IMAGE_FORMAT_RGB565) ) {\n                /* Output image format is same as set in TJPGD */\n                for (int b = 0; b < ESP_JPEG_COLOR_BYTES; b++) {\n                    if (cfg->flags.swap_color_bytes) {\n                        dst[(y * line * out_color_bytes) + x * out_color_bytes + b] = in[out_color_bytes - b - 1];\n                    } else {\n                        dst[(y * line * out_color_bytes) + x * out_color_bytes + b] = in[b];\n                    }\n                }\n            } else if (JD_FORMAT == 0 && cfg->out_format == JPEG_IMAGE_FORMAT_RGB565) {\n                /* Output image format is not same as set in TJPGD */\n                /* We need to convert the 3 bytes in `in` to a rgb565 value */\n                color = ((in[0] & 0xF8) << 8);\n                color |= ((in[1] & 0xFC) << 3);\n                color |= (in[2] >> 3);\n\n                if (cfg->flags.swap_color_bytes) {\n                    dst[(y * line * out_color_bytes) + (x * out_color_bytes)] = HIBYTE(color);\n                    dst[(y * line * out_color_bytes) + (x * out_color_bytes) + 1] = LOBYTE(color);\n                } else {\n                    dst[(y * line * out_color_bytes) + (x * out_color_bytes) + 1] = HIBYTE(color);\n                    dst[(y * line * out_color_bytes) + (x * out_color_bytes)] = LOBYTE(color);\n                }\n            } else {\n                ESP_LOGE(TAG, \"Selected output format is not supported!\");\n                assert(0);\n            }\n            in += ESP_JPEG_COLOR_BYTES;\n        }\n    }\n\n    return 1;\n}\n\nstatic uint8_t jpeg_get_div_by_scale(esp_jpeg_image_scale_t scale)\n{\n    switch (scale) {\n    /* Not scaled */\n    case JPEG_IMAGE_SCALE_0:\n        return 1;\n    /* Scaled 1:2 */\n    case JPEG_IMAGE_SCALE_1_2:\n        return 2;\n    /* Scaled 1:4 */\n    case JPEG_IMAGE_SCALE_1_4:\n        return 4;\n    /* Scaled 1:8 */\n    case JPEG_IMAGE_SCALE_1_8:\n        return 8;\n    }\n\n    return 1;\n}\n\nstatic uint8_t jpeg_get_color_bytes(esp_jpeg_image_format_t format)\n{\n    switch (format) {\n    /* RGB888 (24-bit/pix) */\n    case JPEG_IMAGE_FORMAT_RGB888:\n        return 3;\n    /* RGB565 (16-bit/pix) */\n    case JPEG_IMAGE_FORMAT_RGB565:\n        return 2;\n    }\n\n    return 1;\n}\n\nstatic inline uint16_t ldb_word(const void *ptr)\n{\n    const uint8_t *p = (const uint8_t *)ptr;\n    return ((uint16_t)p[0] << 8) | p[1];\n}\n"
  },
  {
    "path": "esp_jpeg/jpeg_default_huffman_table.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// Default Huffman tables for baseline JPEG\n\n// These values are taken directly from CCITT Rec. T.81 (1992 E) Appendix K.3.3\n// The *_num_bits array always contains exactly 16 elements.\n// Each element represents the number of Huffman codes of a specific length:\n// - The first element corresponds to codes of length 1 bit,\n// - The second element to codes of length 2 bits, and so forth up to 16 bits.\n//\n// The *_values array has a length equal to the sum of all elements in the *_num_bits array,\n// representing the actual values associated with each Huffman code in order.\n\n// Luminance DC Table\nconst unsigned char esp_jpeg_lum_dc_num_bits[16] = {0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0};\nconst unsigned esp_jpeg_lum_dc_codes_total = 12;\nconst unsigned char esp_jpeg_lum_dc_values[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};\n\n// Chrominance DC Table\nconst unsigned char esp_jpeg_chrom_dc_num_bits[16] = {0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};\nconst unsigned esp_jpeg_chrom_dc_codes_total = 12;\nconst unsigned char esp_jpeg_chrom_dc_values[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};\n\n// Luminance AC Table\nconst unsigned char esp_jpeg_lum_ac_num_bits[16] = {0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 125};\nconst unsigned esp_jpeg_lum_ac_codes_total = 162;\nconst unsigned char esp_jpeg_lum_ac_values[162] = {\n    0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,\n    0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0,\n    0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28,\n    0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,\n    0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,\n    0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,\n    0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,\n    0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5,\n    0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2,\n    0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,\n    0xF9, 0xFA\n};\n\n// Chrominance AC Table\nconst unsigned char esp_jpeg_chrom_ac_num_bits[16] = {0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 119};\nconst unsigned esp_jpeg_chrom_ac_codes_total = 162;\nconst unsigned char esp_jpeg_chrom_ac_values[162] = {\n    0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,\n    0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0,\n    0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26,\n    0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,\n    0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,\n    0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,\n    0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5,\n    0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3,\n    0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA,\n    0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,\n    0xF9, 0xFA\n};\n"
  },
  {
    "path": "esp_jpeg/license.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "esp_jpeg/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(esp_jpeg_test)\n"
  },
  {
    "path": "esp_jpeg/test_apps/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"tjpgd_test.c\" \"test_tjpgd_main.c\"\n                       INCLUDE_DIRS \".\"\n                       PRIV_REQUIRES \"unity\"\n                       WHOLE_ARCHIVE\n                       EMBED_FILES \"logo.jpg\" \"usb_camera.jpg\" \"usb_camera_2.jpg\")\n"
  },
  {
    "path": "esp_jpeg/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/esp_jpeg:\n    version: \"*\"\n    override_path: \"../../\"\n"
  },
  {
    "path": "esp_jpeg/test_apps/main/jpg_to_rgb888_hex.py",
    "content": "from PIL import Image\n\n\ndef jpg_to_rgb888_hex_c_array(input_filename: str, output_filename: str) -> str:\n    \"\"\"\n    Convert a .jpg file to RGB888 hex data and format it as a C-style array.\n\n    Parameters:\n    input_filename (str): The path to the JPEG file.\n\n    Returns:\n    str: A string representing the RGB888 hex data formatted as a C array.\n    \"\"\"\n    # Open the image file\n    with Image.open(input_filename) as img:\n        # Ensure the image is in RGB mode\n        rgb_img = img.convert(\"RGB\")\n\n        # Get image dimensions\n        width, height = rgb_img.size\n\n        # List to store hex values as C-style entries\n        hex_data = []\n\n        # Iterate over each pixel to get RGB values\n        for y in range(height):\n            for x in range(width):\n                r, g, b = rgb_img.getpixel((x, y))\n                # Format each RGB value as C-style hex (e.g., 0xRRGGBB)\n                hex_data.append(f\"0x{r:02X}{g:02X}{b:02X}\")\n\n    # Format as a C-style array with line breaks for readability\n    hex_array = \",\\n    \".join(hex_data)\n    c_array = f\"unsigned int image_data[{width * height}] = {{\\n    {hex_array}\\n}};\"\n\n    # Write the C array to the output file\n    with open(output_filename, \"w\") as file:\n        file.write(c_array)\n\n    print(f\"C-style RGB888 hex array saved to {output_filename}\")\n\n    return c_array\n\n\ndef main():\n    \"\"\"\n    Main function to convert a JPEG file to an RGB888 C-style hex array.\n\n    Instructions:\n    1. Replace 'input.jpg' with the path to your JPEG file.\n    2. Run the script to get the C-style array output.\n    \"\"\"\n    # Input JPEG file path\n    input_filename = \"usb_camera.jpg\"  # Replace with your JPEG file path\n\n    # Output file path for the C array\n    output_filename = \"output_array.c\"  # Specify your desired output filename\n\n    # Convert JPEG to C-style RGB888 hex array\n    jpg_to_rgb888_hex_c_array(input_filename, output_filename)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "esp_jpeg/test_apps/main/test_logo_jpg.h",
    "content": "// JPEG encoded image 46x46, 7561 bytes\nextern const unsigned char logo_jpg[] asm(\"_binary_logo_jpg_start\");\n\nextern char _binary_logo_jpg_start;\nextern char _binary_logo_jpg_end;\n// Must be defined as macro because extern variables are not known at compile time (but at link time)\n#define logo_jpg_len (&_binary_logo_jpg_end - &_binary_logo_jpg_start)\n"
  },
  {
    "path": "esp_jpeg/test_apps/main/test_logo_rgb888.h",
    "content": "unsigned char logo_rgb888[] = {\n    0xe1, 0x3b, 0x1f, 0xdf, 0x33, 0x16, 0xe1, 0x2f, 0x14, 0xe2, 0x30, 0x16, 0xdf, 0x2e, 0x14, 0xe1, 0x32, 0x16, 0xdf, 0x30, 0x14, 0xe1, 0x30, 0x16, 0xe3, 0x2e, 0x17, 0xdd, 0x33, 0x15, 0xe1, 0x30, 0x16, 0xe1, 0x2f, 0x12, 0xdf, 0x30, 0x14, 0xdc, 0x32, 0x14, 0xdf, 0x30, 0x15, 0xe2, 0x30, 0x15, 0xe0, 0x2f, 0x15, 0xe1, 0x31, 0x15, 0xe0, 0x2f, 0x15, 0xe2, 0x32, 0x16, 0xde, 0x32, 0x13, 0xdf, 0x30, 0x14, 0xe0, 0x31, 0x18, 0xe1, 0x31, 0x15, 0xe2, 0x30, 0x13, 0xdd, 0x30, 0x17, 0xdf, 0x30, 0x17, 0xe2, 0x30, 0x13, 0xe2, 0x30, 0x15, 0xdf, 0x30, 0x14, 0xe1, 0x33, 0x14, 0xe0, 0x30, 0x14, 0xdd, 0x31, 0x15, 0xdf, 0x30, 0x15, 0xe0, 0x30, 0x14, 0xe2, 0x30, 0x15, 0xdf, 0x30, 0x15, 0xdd, 0x31, 0x12, 0xdf, 0x2f, 0x13, 0xe1, 0x30, 0x18, 0xe2, 0x30, 0x16, 0xe1, 0x2f, 0x14, 0xe0, 0x31, 0x16, 0xe1, 0x30, 0x16, 0xe0, 0x30, 0x12, 0xe3, 0x3e, 0x26, 0xe3, 0x24, 0x0d, 0xdf, 0x29, 0x0d, 0xdd, 0x29, 0x0a, 0xdf, 0x26, 0x0b, 0xdf, 0x29, 0x0d, 0xdd, 0x27, 0x0b, 0xdd, 0x24, 0x07, 0xdd, 0x29, 0x0c, 0xdc, 0x28, 0x09, 0xdf, 0x27, 0x07, 0xdc, 0x26, 0x08, 0xdf, 0x29, 0x0b, 0xde, 0x28, 0x0c, 0xdf, 0x24, 0x0d, 0xdf, 0x29, 0x0b, 0xde, 0x25, 0x08, 0xdd, 0x28, 0x07, 0xde, 0x28, 0x0c, 0xdc, 0x27, 0x0d, 0xdb, 0x25, 0x0b, 0xe0, 0x27, 0x0e, 0xe0, 0x27, 0x0a, 0xe1, 0x25, 0x09, 0xdd, 0x27, 0x0b, 0xdf, 0x26, 0x0d, 0xe0, 0x28, 0x08, 0xdd, 0x29, 0x0a, 0xde, 0x28, 0x0e, 0xdf, 0x26, 0x0b, 0xde, 0x28, 0x0a, 0xdf, 0x26, 0x0b, 0xde, 0x28, 0x0c, 0xe0, 0x28, 0x08, 0xe0, 0x25, 0x0b, 0xe0, 0x28, 0x08, 0xdd, 0x28, 0x0e, 0xdf, 0x26, 0x0d, 0xe0, 0x27, 0x0e, 0xda, 0x28, 0x0b, 0xdf, 0x26, 0x09, 0xdd, 0x29, 0x08, 0xdc, 0x28, 0x07, 0xdc, 0x28, 0x09, 0xe0, 0x27, 0x0a, 0xdf, 0x24, 0x03, 0xe0, 0x2e, 0x13, 0xe1, 0x31, 0x15, 0xde, 0x28, 0x0a, 0xdf, 0x27, 0x07, 0xdd, 0x27, 0x09, 0xdc, 0x28, 0x09, 0xdf, 0x26, 0x09, 0xe3, 0x27, 0x09, 0xdf, 0x26, 0x09, 0xdf, 0x26, 0x09, 0xdd, 0x27, 0x0d, 0xe0, 0x27, 0x0e, 0xde, 0x25, 0x0a, 0xde, 0x28, 0x0c, 0xdf, 0x28, 0x04, 0xe0, 0x25, 0x0b, 0xe1, 0x28, 0x0d, 0xdd, 0x27, 0x09, 0xe0, 0x26, 0x09, 0xe3, 0x27, 0x0d, 0xe0, 0x27, 0x0c, 0xe0, 0x27, 0x0e, 0xe0, 0x27, 0x0c, 0xdd, 0x28, 0x07, 0xdd, 0x28, 0x0f, 0xdd, 0x27, 0x09, 0xe0, 0x28, 0x08, 0xdd, 0x27, 0x0b, 0xdd, 0x27, 0x0b, 0xe0, 0x27, 0x0c, 0xe0, 0x27, 0x0e, 0xdc, 0x28, 0x09, 0xe0, 0x26, 0x09, 0xe0, 0x26, 0x0f, 0xdd, 0x28, 0x07, 0xde, 0x28, 0x0e, 0xdc, 0x26, 0x0c, 0xe0, 0x28, 0x08, 0xe0, 0x27, 0x0a, 0xdf, 0x26, 0x09, 0xdd, 0x29, 0x0c, 0xde, 0x28, 0x0c, 0xdf, 0x26, 0x09, 0xdd, 0x27, 0x0b, 0xdd, 0x27, 0x0b, 0xde, 0x26, 0x06, 0xe0, 0x35, 0x1b, 0xdc, 0x31, 0x15, 0xe0, 0x25, 0x0b, 0xe2, 0x26, 0x0a, 0xdd, 0x29, 0x0c, 0xde, 0x28, 0x0c, 0xe1, 0x27, 0x0a, 0xdf, 0x26, 0x09, 0xdd, 0x27, 0x0b, 0xe0, 0x27, 0x0c, 0xdd, 0x27, 0x0b, 0xe1, 0x27, 0x08, 0xe0, 0x25, 0x0d, 0xdd, 0x29, 0x0a, 0xe0, 0x27, 0x0c, 0xdc, 0x26, 0x08, 0xdd, 0x27, 0x09, 0xdf, 0x26, 0x0d, 0xdd, 0x27, 0x09, 0xda, 0x29, 0x09, 0xdc, 0x28, 0x07, 0xdf, 0x2a, 0x09, 0xdc, 0x27, 0x0d, 0xdc, 0x09, 0x00, 0xd8, 0x05, 0x00, 0xd9, 0x06, 0x00, 0xd9, 0x09, 0x00, 0xdb, 0x14, 0x00, 0xde, 0x20, 0x00, 0xdd, 0x29, 0x08, 0xdb, 0x25, 0x09, 0xdd, 0x27, 0x09, 0xe0, 0x28, 0x08, 0xde, 0x26, 0x06, 0xe1, 0x26, 0x0c, 0xde, 0x28, 0x0a, 0xdd, 0x29, 0x0a, 0xdf, 0x27, 0x07, 0xdf, 0x26, 0x0b, 0xde, 0x28, 0x0a, 0xdd, 0x28, 0x07, 0xe1, 0x26, 0x0c, 0xe1, 0x26, 0x0c, 0xe0, 0x27, 0x0c, 0xdf, 0x26, 0x0b, 0xdf, 0x25, 0x06, 0xe2, 0x35, 0x1c, 0xdf, 0x30, 0x15, 0xe1, 0x26, 0x0c, 0xe1, 0x27, 0x0a, 0xdc, 0x26, 0x0a, 0xde, 0x25, 0x0a, 0xde, 0x28, 0x0a, 0xdc, 0x28, 0x09, 0xe2, 0x27, 0x0d, 0xe0, 0x25, 0x0e, 0xdd, 0x27, 0x0b, 0xe0, 0x28, 0x06, 0xdb, 0x27, 0x0a, 0xe1, 0x28, 0x0d, 0xda, 0x29, 0x09, 0xdf, 0x26, 0x0b, 0xdf, 0x29, 0x0d, 0xdf, 0x27, 0x07, 0xde, 0x2a, 0x0d, 0xe0, 0x28, 0x06, 0xe1, 0x26, 0x0c, 0xdf, 0x25, 0x06, 0xdf, 0x20, 0x09, 0xe6, 0x59, 0x3f, 0xe6, 0x6a, 0x57, 0xe8, 0x64, 0x4f, 0xe5, 0x53, 0x3e, 0xe2, 0x39, 0x24, 0xdd, 0x19, 0x00, 0xd8, 0x02, 0x00, 0xde, 0x03, 0x03, 0xdd, 0x1d, 0x00, 0xdb, 0x29, 0x0f, 0xde, 0x28, 0x0e, 0xdc, 0x27, 0x06, 0xdc, 0x26, 0x0a, 0xe2, 0x28, 0x09, 0xe0, 0x25, 0x0b, 0xdf, 0x26, 0x0d, 0xe3, 0x28, 0x10, 0xdf, 0x26, 0x09, 0xdd, 0x27, 0x09, 0xdc, 0x26, 0x08, 0xdb, 0x27, 0x0a, 0xde, 0x28, 0x0a, 0xde, 0x26, 0x04, 0xe0, 0x35, 0x19, 0xde, 0x32, 0x15, 0xdc, 0x26, 0x0a, 0xe0, 0x26, 0x09, 0xe1, 0x28, 0x0b, 0xde, 0x28, 0x0a, 0xdd, 0x27, 0x09, 0xdc, 0x28, 0x09, 0xdf, 0x29, 0x0d, 0xe0, 0x28, 0x08, 0xda, 0x29, 0x07, 0xdf, 0x27, 0x07, 0xdd, 0x29, 0x0c, 0xdd, 0x25, 0x05, 0xe2, 0x29, 0x0c, 0xdb, 0x1f, 0x03, 0xda, 0x09, 0x00, 0xda, 0x0d, 0x01, 0xd9, 0x18, 0x00, 0xe1, 0x21, 0x0c, 0xdc, 0x28, 0x07, 0xdc, 0x10, 0x01, 0xe0, 0x3b, 0x21, 0xfd, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xfe, 0xff, 0xfe, 0xfe, 0xfb, 0xfb, 0xfa, 0xfa, 0xf9, 0xd2, 0xce, 0xed, 0xa2, 0x99, 0xe5, 0x5f, 0x4f, 0xda, 0x1c, 0x00, 0xda, 0x00, 0x00, 0xde, 0x1c, 0x00, 0xdd, 0x2d, 0x0f, 0xde, 0x28, 0x0c, 0xe0, 0x27, 0x0a, 0xdd, 0x27, 0x0b, 0xde, 0x28, 0x0c, 0xd9, 0x27, 0x0c, 0xe0, 0x27, 0x0a, 0xe0, 0x27, 0x0c, 0xe0, 0x27, 0x0a, 0xdd, 0x27, 0x0b, 0xe0, 0x27, 0x0c, 0xdd, 0x25, 0x05, 0xe0, 0x35, 0x1b, 0xe1, 0x2f, 0x14, 0xe2, 0x28, 0x0b, 0xe0, 0x26, 0x07, 0xdc, 0x26, 0x08, 0xe2, 0x28, 0x0b, 0xe0, 0x26, 0x09, 0xde, 0x28, 0x0a, 0xde, 0x2a, 0x0d, 0xda, 0x12, 0x02, 0xdd, 0x16, 0x00, 0xdf, 0x2b, 0x0e, 0xe0, 0x25, 0x0e, 0xdd, 0x2a, 0x06, 0xdb, 0x08, 0x00, 0xdb, 0x17, 0x02, 0xe6, 0x56, 0x43, 0xe3, 0x4b, 0x30, 0xe3, 0x28, 0x0e, 0xd9, 0x09, 0x00, 0xd8, 0x02, 0x00, 0xd6, 0x05, 0x00, 0xdb, 0x26, 0x0d, 0xe6, 0x64, 0x53, 0xf2, 0xae, 0xa7, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xff, 0xfc, 0xfe, 0xfc, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xf6, 0xd9, 0xd9, 0xea, 0x77, 0x6a, 0xdd, 0x17, 0x00, 0xd7, 0x00, 0x04, 0xe0, 0x26, 0x05, 0xda, 0x2a, 0x0a, 0xe0, 0x27, 0x0a, 0xde, 0x28, 0x0e, 0xe1, 0x27, 0x0a, 0xde, 0x29, 0x08, 0xdb, 0x25, 0x07, 0xde, 0x28, 0x0a, 0xdd, 0x27, 0x09, 0xdd, 0x27, 0x09, 0xdd, 0x25, 0x03, 0xe3, 0x37, 0x1b, 0xdd, 0x31, 0x15, 0xdd, 0x27, 0x0b, 0xde, 0x28, 0x0a, 0xdd, 0x29, 0x0c, 0xdf, 0x26, 0x0b, 0xdd, 0x29, 0x0c, 0xe2, 0x29, 0x0e, 0xda, 0x0e, 0x00, 0xe0, 0x3e, 0x23, 0xe1, 0x3b, 0x1f, 0xdd, 0x1c, 0x06, 0xdf, 0x27, 0x07, 0xd9, 0x01, 0x00, 0xe0, 0x34, 0x20, 0xf3, 0xbf, 0xb9, 0xff, 0xff, 0xfc, 0xfe, 0xff, 0xfe, 0xf6, 0xe3, 0xe1, 0xf4, 0xbe, 0xb5, 0xec, 0x87, 0x7c, 0xe4, 0x4c, 0x39, 0xdc, 0x10, 0x00, 0xd3, 0x02, 0x02, 0xd8, 0x01, 0x00, 0xdf, 0x3b, 0x29, 0xee, 0xa0, 0x98, 0xfd, 0xff, 0xfb, 0xfd, 0xfe, 0xff, 0xfc, 0xff, 0xfd, 0xfc, 0xfe, 0xfc, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xfe, 0xf8, 0xd8, 0xd5, 0xe1, 0x55, 0x43, 0xd9, 0x00, 0x00, 0xe0, 0x1b, 0x02, 0xde, 0x2a, 0x0b, 0xe0, 0x27, 0x0a, 0xdd, 0x27, 0x09, 0xdf, 0x26, 0x0d, 0xe0, 0x27, 0x0c, 0xe1, 0x27, 0x0a, 0xdf, 0x26, 0x0b, 0xe0, 0x27, 0x0c, 0xde, 0x24, 0x05, 0xe0, 0x35, 0x1b, 0xe0, 0x31, 0x18, 0xe0, 0x27, 0x0c, 0xe0, 0x24, 0x08, 0xe1, 0x26, 0x0e, 0xe0, 0x27, 0x0c, 0xde, 0x28, 0x0e, 0xd9, 0x0d, 0x00, 0xde, 0x1e, 0x09, 0xfd, 0xf7, 0xfa, 0xfb, 0xeb, 0xe7, 0xd9, 0x13, 0x00, 0xda, 0x0d, 0x03, 0xe8, 0x67, 0x59, 0xfe, 0xf9, 0xf7, 0xff, 0xff, 0xfe, 0xfd, 0xfe, 0xff, 0xfc, 0xff, 0xfd, 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xff, 0xf7, 0xcf, 0xc7, 0xec, 0x7f, 0x7a, 0xdd, 0x2e, 0x13, 0xd4, 0x00, 0x00, 0xd3, 0x01, 0x00, 0xe1, 0x3d, 0x2b, 0xf6, 0xb8, 0xb3, 0xfd, 0xfe, 0xff, 0xff, 0xfe, 0xfd, 0xfc, 0xfd, 0xfd, 0xfc, 0xfe, 0xfc, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xfc, 0xec, 0x8e, 0x84, 0xda, 0x04, 0x00, 0xdc, 0x15, 0x01, 0xde, 0x2a, 0x0b, 0xdd, 0x27, 0x09, 0xdd, 0x29, 0x0a, 0xe1, 0x26, 0x0c, 0xdf, 0x26, 0x0b, 0xde, 0x28, 0x0c, 0xdc, 0x28, 0x0b, 0xe0, 0x26, 0x05, 0xe1, 0x35, 0x19, 0xdd, 0x31, 0x14, 0xdf, 0x27, 0x07, 0xdd, 0x27, 0x09, 0xdf, 0x29, 0x0b, 0xda, 0x2a, 0x0e, 0xdb, 0x1a, 0x04, 0xdc, 0x04, 0x00, 0xf4, 0xd2, 0xcc, 0xfb, 0xfe, 0xfc, 0xe9, 0x83, 0x71, 0xdc, 0x0a, 0x05, 0xdf, 0x36, 0x21, 0xfe, 0xfd, 0xf8, 0xfe, 0xff, 0xfe, 0xfb, 0xfd, 0xfb, 0xfd, 0xfc, 0xfb, 0xfc, 0xfe, 0xfc, 0xfb, 0xfd, 0xfb, 0xfe, 0xfd, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xff, 0xfe, 0xfd, 0xff, 0xf9, 0xfd, 0xff, 0xfd, 0xfd, 0xf0, 0xf3, 0xef, 0x94, 0x8b, 0xdc, 0x2c, 0x16, 0xd3, 0x01, 0x00, 0xd6, 0x00, 0x00, 0xe8, 0x6d, 0x61, 0xf8, 0xf8, 0xef, 0xfe, 0xff, 0xff, 0xfb, 0xfe, 0xfd, 0xfa, 0xfa, 0xf9, 0xfc, 0xff, 0xfd, 0xfe, 0xff, 0xff, 0xf0, 0xb0, 0xa6, 0xdc, 0x04, 0x00, 0xdd, 0x14, 0x00, 0xe0, 0x2a, 0x10, 0xe0, 0x25, 0x0b, 0xdc, 0x28, 0x07, 0xdf, 0x27, 0x07, 0xe1, 0x26, 0x0c, 0xde, 0x28, 0x0c, 0xdc, 0x24, 0x04, 0xdf, 0x37, 0x1c, 0xdf, 0x33, 0x16, 0xdc, 0x26, 0x0a, 0xdf, 0x2a, 0x07, 0xdd, 0x27, 0x0b, 0xe0, 0x27, 0x04, 0xd5, 0x02, 0x00, 0xf2, 0x9a, 0x8a, 0xff, 0xfe, 0xfd, 0xeb, 0x97, 0x86, 0xd9, 0x01, 0x00, 0xda, 0x0b, 0x00, 0xe2, 0x41, 0x28, 0xfe, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0xf9, 0xff, 0xfd, 0xfa, 0xff, 0xfd, 0xfb, 0xfc, 0xfc, 0xfb, 0xfe, 0xfc, 0xfd, 0xfc, 0xfb, 0xfb, 0xfc, 0xfc, 0xfb, 0xfd, 0xfb, 0xfb, 0xfc, 0xfd, 0xfb, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xfd, 0xf9, 0xf2, 0xf1, 0xeb, 0x7c, 0x74, 0xda, 0x04, 0x00, 0xd4, 0x02, 0x00, 0xe3, 0x31, 0x1e, 0xf6, 0xd0, 0xc7, 0xfd, 0xfe, 0xff, 0xfa, 0xff, 0xff, 0xfd, 0xfc, 0xfb, 0xfe, 0xfe, 0xfb, 0xff, 0xff, 0xff, 0xf1, 0xb6, 0xac, 0xd9, 0x00, 0x02, 0xdc, 0x1d, 0x04, 0xdd, 0x27, 0x0b, 0xe0, 0x27, 0x0a, 0xdf, 0x2b, 0x0c, 0xdb, 0x25, 0x09, 0xe0, 0x27, 0x0c, 0xe1, 0x25, 0x07, 0xdd, 0x35, 0x1a, 0xe0, 0x2f, 0x17, 0xe0, 0x26, 0x0f, 0xe0, 0x25, 0x0b, 0xdd, 0x29, 0x08, 0xd9, 0x06, 0x00, 0xe2, 0x44, 0x28, 0xff, 0xff, 0xff, 0xf5, 0xd9, 0xd1, 0xdd, 0x00, 0x01, 0xdb, 0x1a, 0x02, 0xda, 0x14, 0x01, 0xe3, 0x3d, 0x21, 0xfb, 0xfc, 0xfc, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfd, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0xfb, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xf9, 0xfc, 0xfc, 0xfb, 0xfd, 0xfe, 0xfe, 0xfd, 0xfc, 0xf9, 0xfa, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfe, 0xff, 0xfe, 0xfd, 0xff, 0xfd, 0xf8, 0xc4, 0xc0, 0xdd, 0x34, 0x1f, 0xd2, 0x01, 0x01, 0xda, 0x0b, 0x00, 0xf6, 0xb1, 0xa6, 0xfe, 0xfe, 0xff, 0xfd, 0xff, 0xfe, 0xfa, 0xfc, 0xfa, 0xfa, 0xfe, 0xf9, 0xfd, 0xfd, 0xfe, 0xef, 0x97, 0x83, 0xd7, 0x00, 0x00, 0xdb, 0x27, 0x06, 0xde, 0x25, 0x0a, 0xdd, 0x29, 0x0a, 0xdd, 0x27, 0x0b, 0xdf, 0x26, 0x0b, 0xe0, 0x24, 0x06, 0xe0, 0x35, 0x1b, 0xe1, 0x2f, 0x14, 0xdd, 0x28, 0x07, 0xdd, 0x27, 0x09, 0xdc, 0x24, 0x04, 0xdb, 0x04, 0x03, 0xfb, 0xd7, 0xd3, 0xfc, 0xfe, 0xfa, 0xe1, 0x3b, 0x1d, 0xd7, 0x05, 0x00, 0xdf, 0x29, 0x0b, 0xdf, 0x23, 0x05, 0xdc, 0x26, 0x0a, 0xe3, 0x46, 0x2d, 0xe3, 0x4f, 0x3b, 0xe6, 0x60, 0x50, 0xea, 0x79, 0x6d, 0xed, 0x9e, 0x93, 0xf4, 0xcb, 0xc9, 0xfa, 0xfa, 0xfa, 0xfd, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfd, 0xfd, 0xfc, 0xfb, 0xfd, 0xfd, 0xfc, 0xfc, 0xfe, 0xff, 0xfb, 0xfc, 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xfd, 0xfb, 0xfa, 0xf7, 0xe9, 0x61, 0x4f, 0xd2, 0x01, 0x00, 0xda, 0x00, 0x01, 0xee, 0x9d, 0x91, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xfe, 0xfb, 0xfb, 0xfb, 0xfd, 0xff, 0xfe, 0xfe, 0xfe, 0xfd, 0xe7, 0x52, 0x3d, 0xd7, 0x00, 0x01, 0xe2, 0x29, 0x0c, 0xde, 0x26, 0x06, 0xe2, 0x28, 0x0b, 0xe0, 0x27, 0x0a, 0xdc, 0x24, 0x04, 0xe0, 0x37, 0x1f, 0xe1, 0x31, 0x15, 0xdb, 0x26, 0x0c, 0xe3, 0x29, 0x0a, 0xdb, 0x05, 0x00, 0xe6, 0x55, 0x3c, 0xfd, 0xfd, 0xfe, 0xf3, 0xac, 0xa1, 0xd7, 0x03, 0x01, 0xe0, 0x2d, 0x08, 0xe0, 0x16, 0x03, 0xd8, 0x06, 0x00, 0xd9, 0x07, 0x00, 0xd9, 0x01, 0x00, 0xdb, 0x00, 0x00, 0xd5, 0x00, 0x01, 0xd4, 0x01, 0x01, 0xd7, 0x00, 0x01, 0xd7, 0x03, 0x01, 0xe0, 0x37, 0x1f, 0xe9, 0x78, 0x6a, 0xf7, 0xc9, 0xc5, 0xfb, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xfc, 0xff, 0xfe, 0xfa, 0xfc, 0xfa, 0xfd, 0xfd, 0xfa, 0xff, 0xfc, 0xfd, 0xfa, 0xfd, 0xfc, 0xfb, 0xff, 0xfe, 0xfc, 0xfe, 0xfc, 0xea, 0x80, 0x6e, 0xd6, 0x02, 0x00, 0xd8, 0x01, 0x00, 0xf3, 0xa1, 0x8f, 0xfc, 0xff, 0xfd, 0xfe, 0xff, 0xff, 0xfa, 0xfb, 0xfb, 0xfe, 0xff, 0xff, 0xf6, 0xe6, 0xe2, 0xdc, 0x12, 0x00, 0xde, 0x1a, 0x05, 0xdf, 0x29, 0x0b, 0xdd, 0x27, 0x09, 0xe1, 0x27, 0x0a, 0xde, 0x24, 0x05, 0xdf, 0x37, 0x1c, 0xe0, 0x30, 0x12, 0xde, 0x28, 0x0c, 0xdf, 0x25, 0x08, 0xd9, 0x02, 0x00, 0xf3, 0xcc, 0xbf, 0xfe, 0xfe, 0xfb, 0xe3, 0x36, 0x1d, 0xd6, 0x0b, 0x00, 0xda, 0x04, 0x00, 0xdd, 0x23, 0x0c, 0xe7, 0x75, 0x62, 0xf2, 0xae, 0xa5, 0xf0, 0xc7, 0xbf, 0xf3, 0xbd, 0xb5, 0xf1, 0xa0, 0x96, 0xeb, 0x86, 0x7b, 0xe7, 0x5d, 0x4c, 0xde, 0x2a, 0x0b, 0xd8, 0x02, 0x00, 0xd3, 0x02, 0x00, 0xdc, 0x01, 0x01, 0xe5, 0x52, 0x42, 0xf3, 0xbf, 0xb9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfb, 0xfc, 0xfc, 0xf8, 0xfe, 0xf9, 0xff, 0xfe, 0xfd, 0xf9, 0xfc, 0xfc, 0xff, 0xfe, 0xfd, 0xff, 0xff, 0xfc, 0xea, 0x88, 0x77, 0xd7, 0x00, 0x00, 0xd9, 0x00, 0x00, 0xf3, 0xb4, 0xa6, 0xff, 0xfd, 0xfa, 0xfc, 0xff, 0xff, 0xfb, 0xff, 0xfe, 0xff, 0xff, 0xfa, 0xeb, 0x7b, 0x65, 0xd4, 0x03, 0x00, 0xdd, 0x27, 0x0d, 0xd9, 0x29, 0x0b, 0xe1, 0x27, 0x0a, 0xe1, 0x23, 0x05, 0xe0, 0x35, 0x1b, 0xe1, 0x31, 0x15, 0xdc, 0x28, 0x0b, 0xdd, 0x13, 0x01, 0xe5, 0x36, 0x1a, 0xfe, 0xfe, 0xff, 0xf3, 0xcb, 0xc3, 0xd8, 0x01, 0x00, 0xda, 0x02, 0x00, 0xe7, 0x5c, 0x4e, 0xfa, 0xe4, 0xe2, 0xfe, 0xfe, 0xfb, 0xfe, 0xfe, 0xfe, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xfd, 0xff, 0xfe, 0xfd, 0xfd, 0xff, 0xff, 0xfd, 0xff, 0xfd, 0xfa, 0xef, 0xef, 0xf2, 0xb6, 0xb0, 0xe9, 0x68, 0x5e, 0xde, 0x14, 0x01, 0xd3, 0x02, 0x00, 0xd8, 0x02, 0x00, 0xe5, 0x62, 0x57, 0xf8, 0xec, 0xe7, 0xfd, 0xff, 0xfd, 0xfd, 0xff, 0xfd, 0xfd, 0xfc, 0xfc, 0xfd, 0xfc, 0xfb, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xfc, 0xfe, 0xff, 0xff, 0xe9, 0x81, 0x6f, 0xd2, 0x01, 0x00, 0xdb, 0x0b, 0x02, 0xf7, 0xd8, 0xcd, 0xfd, 0xfe, 0xfe, 0xfb, 0xfe, 0xfc, 0xfe, 0xfd, 0xfd, 0xf7, 0xe3, 0xde, 0xe0, 0x11, 0x03, 0xdc, 0x20, 0x06, 0xdd, 0x27, 0x09, 0xde, 0x28, 0x0a, 0xdd, 0x25, 0x05, 0xe2, 0x35, 0x1e, 0xe1, 0x30, 0x16, 0xda, 0x2b, 0x08, 0xd8, 0x00, 0x00, 0xeb, 0x79, 0x68, 0xff, 0xfe, 0xff, 0xe7, 0x6e, 0x55, 0xd5, 0x01, 0x00, 0xe6, 0x65, 0x57, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xfe, 0xfc, 0xfd, 0xfe, 0xfe, 0xfb, 0xfc, 0xfd, 0xfc, 0xfc, 0xfc, 0xfb, 0xfe, 0xfc, 0xfb, 0xfc, 0xfc, 0xfd, 0xff, 0xfd, 0xfa, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xfe, 0xf5, 0xd9, 0xd2, 0xea, 0x73, 0x67, 0xd7, 0x0a, 0x00, 0xd5, 0x00, 0x01, 0xde, 0x21, 0x0d, 0xf3, 0xb9, 0xb1, 0xfe, 0xff, 0xfe, 0xfd, 0xff, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfc, 0xfc, 0xfc, 0xfd, 0xff, 0xf9, 0xfe, 0xfe, 0xfe, 0xe6, 0x5f, 0x46, 0xd2, 0x01, 0x00, 0xdf, 0x32, 0x19, 0xfb, 0xfa, 0xf9, 0xfd, 0xff, 0xff, 0xfc, 0xff, 0xfd, 0xfd, 0xff, 0xfd, 0xe5, 0x58, 0x40, 0xdc, 0x06, 0x00, 0xdf, 0x26, 0x09, 0xdf, 0x26, 0x0b, 0xe0, 0x24, 0x08, 0xe1, 0x36, 0x1c, 0xe1, 0x31, 0x15, 0xe0, 0x24, 0x0a, 0xda, 0x08, 0x01, 0xf0, 0xbf, 0xb4, 0xff, 0xfe, 0xfe, 0xde, 0x1a, 0x05, 0xde, 0x26, 0x15, 0xfe, 0xff, 0xfe, 0xfc, 0xff, 0xfd, 0xfc, 0xfc, 0xfb, 0xfc, 0xfd, 0xfd, 0xfa, 0xfc, 0xfa, 0xfe, 0xfe, 0xfd, 0xfc, 0xfe, 0xfc, 0xfc, 0xf9, 0xf9, 0xfc, 0xfd, 0xfd, 0xff, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfa, 0xfd, 0xfd, 0xfc, 0xfd, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xca, 0xca, 0xe1, 0x45, 0x32, 0xd3, 0x02, 0x00, 0xd7, 0x01, 0x00, 0xee, 0x95, 0x89, 0xfe, 0xff, 0xfe, 0xfd, 0xff, 0xfb, 0xf9, 0xfc, 0xfb, 0xfc, 0xff, 0xfd, 0xfb, 0xfc, 0xfd, 0xfe, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xe2, 0x2f, 0x1c, 0xd3, 0x01, 0x00, 0xea, 0x75, 0x5f, 0xfe, 0xff, 0xfe, 0xfb, 0xfc, 0xfc, 0xff, 0xff, 0xfc, 0xed, 0xa0, 0x92, 0xd8, 0x02, 0x00, 0xde, 0x28, 0x0e, 0xe0, 0x27, 0x0c, 0xde, 0x24, 0x05, 0xdf, 0x37, 0x1a, 0xdf, 0x30, 0x15, 0xe2, 0x1c, 0x00, 0xdb, 0x1b, 0x00, 0xf9, 0xf6, 0xf7, 0xf7, 0xe8, 0xe7, 0xd8, 0x01, 0x00, 0xec, 0x9a, 0x84, 0xff, 0xff, 0xfe, 0xf9, 0xff, 0xfc, 0xfd, 0xfd, 0xfd, 0xfc, 0xfe, 0xfc, 0xfb, 0xff, 0xf8, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfc, 0xfe, 0xff, 0xfb, 0xfc, 0xfd, 0xfc, 0xfe, 0xfa, 0xfd, 0xfd, 0xfe, 0xfb, 0xfd, 0xfb, 0xfa, 0xfd, 0xfb, 0xfd, 0xfd, 0xfa, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfe, 0xeb, 0x75, 0x65, 0xd8, 0x00, 0x03, 0xd4, 0x00, 0x00, 0xec, 0x90, 0x7d, 0xff, 0xff, 0xfe, 0xfd, 0xfe, 0xfe, 0xfa, 0xfd, 0xfc, 0xfc, 0xfe, 0xfc, 0xfb, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xf7, 0xd0, 0xc5, 0xd6, 0x06, 0x00, 0xd6, 0x00, 0x00, 0xf5, 0xc7, 0xbf, 0xff, 0xff, 0xfe, 0xfc, 0xff, 0xfd, 0xf6, 0xd0, 0xc9, 0xdc, 0x12, 0x00, 0xdd, 0x1f, 0x01, 0xdd, 0x29, 0x08, 0xe0, 0x26, 0x05, 0xe1, 0x35, 0x19, 0xe0, 0x31, 0x16, 0xde, 0x14, 0x01, 0xe0, 0x35, 0x19, 0xfd, 0xff, 0xfe, 0xf6, 0xb1, 0xa5, 0xd7, 0x00, 0x01, 0xf3, 0xc9, 0xc4, 0xfc, 0xff, 0xfd, 0xfc, 0xfc, 0xfc, 0xfe, 0xfd, 0xfd, 0xfb, 0xfc, 0xfc, 0xfe, 0xff, 0xff, 0xf7, 0xe2, 0xe0, 0xf5, 0xdb, 0xd6, 0xfe, 0xf8, 0xfd, 0xfd, 0xff, 0xff, 0xfb, 0xfe, 0xfe, 0xfd, 0xff, 0xfe, 0xfb, 0xfd, 0xfb, 0xfd, 0xff, 0xfd, 0xfc, 0xfe, 0xfa, 0xfb, 0xfc, 0xff, 0xfc, 0xfc, 0xf9, 0xfc, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xee, 0x91, 0x83, 0xd8, 0x01, 0x00, 0xd6, 0x02, 0x00, 0xf0, 0x9d, 0x8e, 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xfb, 0xfe, 0xfd, 0xfc, 0xfc, 0xf9, 0xfb, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xed, 0x7c, 0x66, 0xd6, 0x02, 0x00, 0xe3, 0x41, 0x26, 0xfd, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0xf6, 0xf2, 0xdf, 0x30, 0x15, 0xdf, 0x18, 0x02, 0xdc, 0x28, 0x09, 0xdc, 0x22, 0x05, 0xe3, 0x37, 0x1b, 0xe3, 0x31, 0x17, 0xd8, 0x0f, 0x00, 0xe3, 0x4a, 0x34, 0xfc, 0xfd, 0xfd, 0xed, 0x8a, 0x7e, 0xdc, 0x03, 0x03, 0xf7, 0xe1, 0xdd, 0xff, 0xff, 0xfe, 0xfd, 0xfd, 0xfd, 0xfc, 0xfe, 0xfc, 0xff, 0xff, 0xff, 0xf5, 0xb4, 0xaa, 0xd6, 0x02, 0x00, 0xda, 0x15, 0x00, 0xde, 0x33, 0x17, 0xe9, 0x5b, 0x45, 0xf0, 0x95, 0x8c, 0xfb, 0xde, 0xdc, 0xfd, 0xfd, 0xfa, 0xff, 0xff, 0xff, 0xfd, 0xfe, 0xfe, 0xfb, 0xfd, 0xfb, 0xfb, 0xfd, 0xf9, 0xff, 0xfc, 0xfe, 0xfb, 0xfe, 0xfd, 0xfe, 0xff, 0xff, 0xea, 0x96, 0x87, 0xd5, 0x01, 0x00, 0xdb, 0x00, 0x00, 0xf6, 0xc6, 0xbe, 0xff, 0xff, 0xff, 0xfd, 0xfd, 0xfa, 0xfe, 0xfd, 0xfd, 0xfb, 0xfb, 0xf8, 0xff, 0xfd, 0xff, 0xf8, 0xf5, 0xf5, 0xdc, 0x25, 0x0f, 0xd3, 0x00, 0x01, 0xf1, 0xb0, 0xa3, 0xff, 0xff, 0xfe, 0xfc, 0xff, 0xfd, 0xe7, 0x48, 0x30, 0xd8, 0x10, 0x00, 0xde, 0x25, 0x0a, 0xe0, 0x25, 0x0b, 0xe1, 0x35, 0x19, 0xe0, 0x31, 0x18, 0xda, 0x10, 0x00, 0xe5, 0x53, 0x40, 0xfe, 0xff, 0xff, 0xeb, 0x7b, 0x67, 0xd9, 0x0a, 0x00, 0xfa, 0xed, 0xf1, 0xff, 0xfe, 0xff, 0xfa, 0xfd, 0xfc, 0xfe, 0xfd, 0xfc, 0xfb, 0xfe, 0xfd, 0xf4, 0xc4, 0xba, 0xe0, 0x1d, 0x13, 0xdf, 0x14, 0x00, 0xd9, 0x02, 0x01, 0xd4, 0x01, 0x04, 0xd4, 0x00, 0x00, 0xda, 0x15, 0x00, 0xec, 0x6f, 0x64, 0xf9, 0xe5, 0xde, 0xfd, 0xfe, 0xff, 0xfd, 0xff, 0xff, 0xfe, 0xfd, 0xfc, 0xfc, 0xfc, 0xff, 0xfe, 0xfd, 0xfd, 0xfc, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xee, 0x75, 0x5e, 0xd3, 0x00, 0x00, 0xe0, 0x25, 0x0d, 0xf9, 0xf3, 0xed, 0xff, 0xff, 0xff, 0xfb, 0xfc, 0xfd, 0xfc, 0xfe, 0xfa, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xeb, 0x98, 0x82, 0xd3, 0x01, 0x00, 0xe4, 0x3f, 0x25, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xfd, 0xe6, 0x54, 0x3f, 0xd9, 0x08, 0x00, 0xdf, 0x29, 0x0b, 0xdd, 0x24, 0x09, 0xe2, 0x36, 0x1a, 0xe2, 0x31, 0x17, 0xdc, 0x09, 0x01, 0xe2, 0x57, 0x3f, 0xff, 0xff, 0xfc, 0xe9, 0x7c, 0x6d, 0xd9, 0x03, 0x00, 0xf9, 0xdd, 0xd6, 0xfc, 0xff, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfa, 0xfe, 0xfd, 0xf8, 0xfb, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xf7, 0xe0, 0xe0, 0xf3, 0xc8, 0xbc, 0xee, 0x96, 0x86, 0xe3, 0x50, 0x36, 0xd9, 0x02, 0x03, 0xd2, 0x01, 0x00, 0xdb, 0x19, 0x0b, 0xf0, 0xa2, 0x99, 0xff, 0xff, 0xfe, 0xfc, 0xfe, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfc, 0xf9, 0xfd, 0xfe, 0xfe, 0xfd, 0xff, 0xfe, 0xe2, 0x3a, 0x27, 0xd4, 0x04, 0x00, 0xe6, 0x6f, 0x58, 0xfc, 0xff, 0xfd, 0xfb, 0xfe, 0xfd, 0xfc, 0xfe, 0xfc, 0xfa, 0xfd, 0xfc, 0xff, 0xfe, 0xfd, 0xfb, 0xf5, 0xf7, 0xdf, 0x24, 0x0a, 0xd6, 0x02, 0x00, 0xf2, 0xc4, 0xc0, 0xfd, 0xff, 0xff, 0xe8, 0x5e, 0x4d, 0xdb, 0x05, 0x00, 0xdf, 0x26, 0x0b, 0xdb, 0x25, 0x09, 0xde, 0x36, 0x1b, 0xe2, 0x32, 0x16, 0xd9, 0x0d, 0x00, 0xe5, 0x51, 0x3d, 0xff, 0xfe, 0xff, 0xec, 0x8e, 0x84, 0xd3, 0x02, 0x00, 0xec, 0x92, 0x81, 0xff, 0xff, 0xfe, 0xfb, 0xfe, 0xfc, 0xfb, 0xfd, 0xfb, 0xfb, 0xfe, 0xfd, 0xfb, 0xfe, 0xfd, 0xfe, 0xfe, 0xfd, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfd, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xf5, 0xbd, 0xb6, 0xe4, 0x4c, 0x39, 0xd3, 0x01, 0x00, 0xda, 0x00, 0x00, 0xe9, 0x83, 0x71, 0xff, 0xff, 0xfc, 0xfb, 0xff, 0xff, 0xfc, 0xfc, 0xfb, 0xf8, 0xfe, 0xfc, 0xfd, 0xfc, 0xfb, 0xff, 0xff, 0xff, 0xf6, 0xd4, 0xca, 0xd7, 0x06, 0x00, 0xdb, 0x04, 0x01, 0xf9, 0xd1, 0xcd, 0xff, 0xff, 0xfe, 0xfc, 0xfc, 0xfb, 0xfc, 0xfe, 0xfc, 0xfb, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xee, 0x82, 0x6d, 0xd6, 0x00, 0x00, 0xe7, 0x70, 0x5b, 0xf9, 0xef, 0xe9, 0xe5, 0x43, 0x2e, 0xdb, 0x11, 0x00, 0xe1, 0x29, 0x09, 0xdd, 0x25, 0x05, 0xe1, 0x36, 0x1e, 0xe3, 0x31, 0x16, 0xd8, 0x11, 0x00, 0xe3, 0x40, 0x2b, 0xfd, 0xff, 0xfc, 0xee, 0xa3, 0x99, 0xd5, 0x01, 0x00, 0xdd, 0x22, 0x13, 0xfd, 0xf3, 0xed, 0xfd, 0xfe, 0xfe, 0xfb, 0xfd, 0xfb, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfb, 0xfd, 0xfd, 0xfd, 0xfa, 0xfe, 0xf7, 0xfb, 0xfe, 0xfd, 0xfd, 0xfc, 0xfc, 0xfa, 0xff, 0xfd, 0xfc, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xec, 0x85, 0x7a, 0xda, 0x00, 0x00, 0xd4, 0x02, 0x00, 0xe9, 0x85, 0x73, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xfd, 0xfb, 0xfd, 0xfb, 0xfb, 0xfe, 0xfc, 0xfd, 0xfe, 0xff, 0xfe, 0xfe, 0xfd, 0xe6, 0x70, 0x56, 0xd4, 0x02, 0x00, 0xe3, 0x5e, 0x45, 0xfd, 0xff, 0xfd, 0xfe, 0xff, 0xff, 0xfb, 0xfd, 0xfb, 0xfb, 0xff, 0xfa, 0xff, 0xff, 0xfe, 0xf6, 0xd3, 0xcf, 0xdd, 0x0e, 0x00, 0xdd, 0x23, 0x04, 0xe2, 0x2e, 0x0f, 0xde, 0x20, 0x02, 0xde, 0x28, 0x0a, 0xdd, 0x29, 0x0a, 0xdf, 0x25, 0x06, 0xdd, 0x37, 0x1b, 0xdd, 0x31, 0x14, 0xde, 0x1a, 0x00, 0xdf, 0x2d, 0x10, 0xfe, 0xfe, 0xfd, 0xf3, 0xcb, 0xc7, 0xdc, 0x0b, 0x00, 0xd7, 0x00, 0x00, 0xe4, 0x47, 0x38, 0xfe, 0xfd, 0xfc, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xf8, 0xfb, 0xfc, 0xfc, 0xfd, 0xfb, 0xfd, 0xfc, 0xfc, 0xfc, 0xfe, 0xfe, 0xfe, 0xfb, 0xfe, 0xfe, 0xff, 0xfe, 0xfd, 0xfb, 0xfb, 0xfa, 0xff, 0xff, 0xfc, 0xfe, 0xfe, 0xfe, 0xf1, 0x9e, 0x8f, 0xd4, 0x01, 0x00, 0xd5, 0x00, 0x01, 0xef, 0xb0, 0xa2, 0xfe, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0xfe, 0xf8, 0xfb, 0xfb, 0xfc, 0xff, 0xff, 0xfe, 0xf9, 0xe0, 0xdf, 0xdf, 0x0e, 0x01, 0xda, 0x09, 0x00, 0xf6, 0xdc, 0xd9, 0xfe, 0xfc, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xfd, 0xf9, 0xff, 0xfe, 0xff, 0xff, 0xfe, 0xe2, 0x47, 0x2a, 0xdb, 0x05, 0x00, 0xda, 0x1b, 0x04, 0xdf, 0x26, 0x09, 0xdf, 0x29, 0x0d, 0xdf, 0x26, 0x0b, 0xde, 0x24, 0x05, 0xe2, 0x37, 0x1b, 0xe2, 0x31, 0x17, 0xdf, 0x20, 0x07, 0xdb, 0x11, 0x00, 0xf7, 0xe4, 0xdf, 0xfc, 0xfc, 0xfb, 0xdf, 0x1f, 0x02, 0xdd, 0x1f, 0x01, 0xd8, 0x01, 0x00, 0xe1, 0x3d, 0x2b, 0xf5, 0xc4, 0xbf, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xfe, 0xfd, 0xff, 0xfe, 0xfe, 0xff, 0xfe, 0xfc, 0xfe, 0xf8, 0xfc, 0xfe, 0xfa, 0xfa, 0xfb, 0xfb, 0xfe, 0xfe, 0xfe, 0xfb, 0xfb, 0xfb, 0xfa, 0xff, 0xfd, 0xfd, 0xff, 0xff, 0xed, 0x87, 0x72, 0xd3, 0x02, 0x00, 0xdf, 0x1a, 0x01, 0xfa, 0xea, 0xec, 0xfc, 0xfe, 0xfc, 0xfe, 0xfd, 0xfd, 0xfa, 0xfd, 0xfb, 0xfe, 0xfe, 0xfd, 0xfd, 0xff, 0xff, 0xe5, 0x62, 0x48, 0xd3, 0x03, 0x00, 0xe9, 0x85, 0x73, 0xff, 0xff, 0xff, 0xfa, 0xfd, 0xfc, 0xfb, 0xfc, 0xfd, 0xfb, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xeb, 0x82, 0x76, 0xd8, 0x00, 0x00, 0xe2, 0x23, 0x0c, 0xde, 0x28, 0x0a, 0xdc, 0x26, 0x0a, 0xe1, 0x28, 0x0d, 0xdf, 0x23, 0x05, 0xe0, 0x35, 0x1b, 0xdf, 0x2f, 0x13, 0xe0, 0x28, 0x06, 0xd8, 0x01, 0x00, 0xee, 0xa4, 0x93, 0xff, 0xfe, 0xfb, 0xe2, 0x47, 0x2d, 0xde, 0x10, 0x00, 0xde, 0x2a, 0x0d, 0xde, 0x08, 0x00, 0xd7, 0x0c, 0x00, 0xe7, 0x54, 0x44, 0xed, 0x85, 0x7d, 0xef, 0xa5, 0x9c, 0xf4, 0xbc, 0xb9, 0xfe, 0xf8, 0xfb, 0xfd, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xf9, 0xfc, 0xfb, 0xfe, 0xfe, 0xfe, 0xfb, 0xfc, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xe2, 0x41, 0x28, 0xd2, 0x01, 0x01, 0xef, 0x7b, 0x66, 0xfd, 0xfe, 0xfe, 0xfa, 0xfd, 0xfc, 0xfc, 0xfe, 0xfc, 0xfe, 0xfd, 0xfc, 0xfd, 0xff, 0xfd, 0xf2, 0xb2, 0xa8, 0xd5, 0x01, 0x00, 0xe4, 0x42, 0x23, 0xfb, 0xfe, 0xfd, 0xfe, 0xff, 0xff, 0xfe, 0xfd, 0xf6, 0xfd, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xf3, 0xb9, 0xaf, 0xda, 0x08, 0x00, 0xdc, 0x28, 0x09, 0xe0, 0x28, 0x08, 0xdd, 0x27, 0x09, 0xdd, 0x27, 0x09, 0xe0, 0x24, 0x06, 0xde, 0x36, 0x1b, 0xdd, 0x30, 0x19, 0xe0, 0x27, 0x0a, 0xdd, 0x07, 0x01, 0xe1, 0x5e, 0x46, 0xff, 0xfe, 0xff, 0xeb, 0x8c, 0x7f, 0xd6, 0x00, 0x00, 0xdd, 0x2a, 0x06, 0xde, 0x28, 0x0e, 0xde, 0x22, 0x06, 0xd8, 0x09, 0x00, 0xd8, 0x02, 0x00, 0xdb, 0x00, 0x00, 0xd9, 0x08, 0x00, 0xde, 0x2a, 0x1d, 0xf0, 0x98, 0x8e, 0xfd, 0xff, 0xfd, 0xfe, 0xff, 0xfe, 0xfa, 0xfd, 0xfb, 0xfc, 0xfc, 0xf9, 0xfd, 0xfd, 0xfd, 0xfb, 0xfe, 0xfc, 0xf6, 0xc4, 0xbd, 0xd5, 0x01, 0x00, 0xdc, 0x19, 0x00, 0xf8, 0xee, 0xe8, 0xfe, 0xff, 0xfe, 0xff, 0xfc, 0xfd, 0xfc, 0xfc, 0xfc, 0xfd, 0xff, 0xfd, 0xfb, 0xee, 0xef, 0xdd, 0x1b, 0x09, 0xdd, 0x0a, 0x00, 0xf7, 0xda, 0xd6, 0xfd, 0xff, 0xf9, 0xfe, 0xfd, 0xfd, 0xfb, 0xfd, 0xfb, 0xfc, 0xfe, 0xf8, 0xf6, 0xe1, 0xe0, 0xdc, 0x22, 0x05, 0xd8, 0x1c, 0x00, 0xe0, 0x26, 0x07, 0xde, 0x28, 0x0a, 0xdd, 0x27, 0x09, 0xde, 0x24, 0x05, 0xdf, 0x37, 0x1c, 0xe1, 0x31, 0x15, 0xe0, 0x25, 0x0d, 0xdc, 0x1c, 0x00, 0xde, 0x1f, 0x04, 0xfc, 0xfd, 0xf7, 0xfc, 0xeb, 0xe9, 0xdf, 0x10, 0x00, 0xdd, 0x1f, 0x01, 0xe1, 0x28, 0x0b, 0xe1, 0x28, 0x0d, 0xda, 0x1a, 0x00, 0xdb, 0x02, 0x02, 0xd6, 0x02, 0x00, 0xd9, 0x0a, 0x00, 0xdb, 0x0c, 0x00, 0xd7, 0x00, 0x00, 0xe9, 0x78, 0x62, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfb, 0xfc, 0xfe, 0xfc, 0xfe, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xe3, 0x45, 0x2b, 0xd6, 0x01, 0x02, 0xf2, 0x9f, 0x93, 0xfe, 0xff, 0xff, 0xfa, 0xfb, 0xfb, 0xfd, 0xfe, 0xff, 0xfd, 0xff, 0xfb, 0xff, 0xff, 0xfe, 0xe4, 0x53, 0x36, 0xd5, 0x00, 0x01, 0xef, 0xac, 0x9f, 0xfd, 0xfe, 0xfe, 0xf9, 0xfc, 0xfb, 0xfb, 0xfe, 0xfd, 0xff, 0xfe, 0xfe, 0xfc, 0xff, 0xfe, 0xe6, 0x47, 0x2f, 0xdf, 0x0f, 0x00, 0xdf, 0x26, 0x0b, 0xdf, 0x26, 0x0b, 0xe1, 0x28, 0x0d, 0xdd, 0x25, 0x05, 0xe0, 0x35, 0x1b, 0xe1, 0x31, 0x13, 0xe1, 0x27, 0x0a, 0xe0, 0x27, 0x0a, 0xd7, 0x01, 0x00, 0xef, 0x9a, 0x8f, 0xfb, 0xff, 0xff, 0xe4, 0x5b, 0x42, 0xd6, 0x02, 0x00, 0xde, 0x2d, 0x0b, 0xd6, 0x0e, 0x00, 0xdc, 0x26, 0x0a, 0xeb, 0x81, 0x6d, 0xef, 0x92, 0x86, 0xe4, 0x5b, 0x43, 0xdc, 0x0d, 0x01, 0xdd, 0x18, 0x01, 0xd8, 0x01, 0x02, 0xf3, 0xa7, 0xa1, 0xfe, 0xff, 0xfe, 0xf8, 0xfe, 0xfc, 0xfb, 0xfb, 0xfa, 0xfc, 0xff, 0xfd, 0xfd, 0xfe, 0xfe, 0xef, 0x8e, 0x7f, 0xd3, 0x00, 0x00, 0xe8, 0x67, 0x51, 0xfe, 0xfe, 0xfe, 0xfa, 0xff, 0xfd, 0xfc, 0xfc, 0xfd, 0xfa, 0xff, 0xff, 0xfd, 0xff, 0xf9, 0xec, 0x7b, 0x6c, 0xd5, 0x01, 0x00, 0xea, 0x86, 0x74, 0xfe, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfe, 0xfb, 0xfb, 0xfc, 0xff, 0xfb, 0xfd, 0xfd, 0xfd, 0xe4, 0x4b, 0x33, 0xdc, 0x0c, 0x00, 0xde, 0x2a, 0x0d, 0xe0, 0x27, 0x0c, 0xdf, 0x26, 0x0b, 0xde, 0x26, 0x06, 0xe1, 0x36, 0x1c, 0xe1, 0x30, 0x16, 0xdd, 0x27, 0x0d, 0xdd, 0x29, 0x0a, 0xdb, 0x0f, 0x00, 0xde, 0x2e, 0x12, 0xff, 0xff, 0xfe, 0xfb, 0xdf, 0xd8, 0xd9, 0x09, 0x01, 0xdb, 0x0f, 0x00, 0xe1, 0x30, 0x1a, 0xfd, 0xdf, 0xe1, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfc, 0xfd, 0xfd, 0xfc, 0xec, 0x88, 0x7a, 0xd8, 0x08, 0x00, 0xd9, 0x08, 0x00, 0xe0, 0x38, 0x1d, 0xfb, 0xfc, 0xfc, 0xfe, 0xff, 0xfc, 0xfd, 0xfb, 0xff, 0xfc, 0xfe, 0xfc, 0xfe, 0xfe, 0xff, 0xf1, 0xc0, 0xb3, 0xd6, 0x01, 0x02, 0xe4, 0x3f, 0x25, 0xfd, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfa, 0xfb, 0xfc, 0xfc, 0xfd, 0xfe, 0xfe, 0xee, 0x96, 0x8c, 0xd4, 0x00, 0x00, 0xe9, 0x6a, 0x5b, 0xff, 0xff, 0xfe, 0xf8, 0xff, 0xfc, 0xfd, 0xfd, 0xfa, 0xfe, 0xff, 0xff, 0xef, 0xb2, 0xa9, 0xda, 0x08, 0x00, 0xdf, 0x23, 0x09, 0xdc, 0x28, 0x09, 0xdd, 0x27, 0x0b, 0xdf, 0x26, 0x0b, 0xdf, 0x25, 0x06, 0xe1, 0x36, 0x1c, 0xdd, 0x30, 0x19, 0xde, 0x29, 0x08, 0xdf, 0x26, 0x09, 0xdf, 0x25, 0x08, 0xd8, 0x01, 0x00, 0xed, 0x9d, 0x8e, 0xfe, 0xfe, 0xfe, 0xe8, 0x77, 0x60, 0xd4, 0x00, 0x00, 0xf0, 0xb5, 0xa9, 0xfd, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xfe, 0xfe, 0xfb, 0xff, 0xff, 0xff, 0xe3, 0x42, 0x29, 0xd8, 0x0b, 0x02, 0xdf, 0x11, 0x00, 0xf6, 0xcc, 0xc9, 0xfa, 0xff, 0xfd, 0xfc, 0xfd, 0xfe, 0xfc, 0xfc, 0xfb, 0xfe, 0xff, 0xfc, 0xf5, 0xd6, 0xd3, 0xdc, 0x0b, 0x00, 0xe1, 0x26, 0x0e, 0xfe, 0xed, 0xeb, 0xfe, 0xff, 0xff, 0xfb, 0xfc, 0xfd, 0xfa, 0xfe, 0xf9, 0xff, 0xff, 0xff, 0xf1, 0xa6, 0x9d, 0xd4, 0x02, 0x00, 0xe7, 0x65, 0x54, 0xfc, 0xff, 0xfd, 0xff, 0xff, 0xfc, 0xfd, 0xff, 0xfd, 0xfd, 0xed, 0xef, 0xdb, 0x1b, 0x06, 0xdb, 0x11, 0x00, 0xe0, 0x27, 0x0c, 0xdf, 0x26, 0x09, 0xde, 0x28, 0x0c, 0xdf, 0x26, 0x0b, 0xde, 0x24, 0x05, 0xe2, 0x35, 0x1c, 0xe1, 0x31, 0x13, 0xdf, 0x26, 0x0b, 0xdd, 0x2a, 0x06, 0xde, 0x28, 0x0e, 0xdc, 0x18, 0x04, 0xdb, 0x16, 0x00, 0xfa, 0xf1, 0xee, 0xff, 0xff, 0xff, 0xe1, 0x20, 0x0b, 0xf4, 0xbd, 0xb0, 0xff, 0xff, 0xff, 0xfb, 0xfb, 0xf8, 0xfa, 0xfd, 0xfb, 0xfd, 0xfe, 0xff, 0xfa, 0xff, 0xfe, 0xea, 0x73, 0x66, 0xd7, 0x01, 0x00, 0xd8, 0x09, 0x00, 0xf2, 0xb5, 0xac, 0xfd, 0xff, 0xfb, 0xfd, 0xfa, 0xfa, 0xfc, 0xff, 0xfd, 0xff, 0xff, 0xfc, 0xf8, 0xe4, 0xdf, 0xd9, 0x1b, 0x00, 0xdd, 0x1b, 0x00, 0xf7, 0xe7, 0xdf, 0xfe, 0xfe, 0xfe, 0xfd, 0xfe, 0xfe, 0xff, 0xfe, 0xfb, 0xff, 0xfe, 0xfe, 0xef, 0xae, 0xa1, 0xd6, 0x02, 0x00, 0xe5, 0x54, 0x3b, 0xfe, 0xe9, 0xe8, 0xfb, 0xef, 0xed, 0xfa, 0xe6, 0xe7, 0xe2, 0x4e, 0x32, 0xd6, 0x00, 0x00, 0xdf, 0x2b, 0x0a, 0xe0, 0x27, 0x0c, 0xdf, 0x26, 0x09, 0xde, 0x28, 0x0c, 0xdf, 0x26, 0x0b, 0xde, 0x24, 0x05, 0xe2, 0x35, 0x1c, 0xe0, 0x31, 0x15, 0xe1, 0x26, 0x0c, 0xdc, 0x27, 0x0d, 0xde, 0x25, 0x0a, 0xdd, 0x2c, 0x0c, 0xd7, 0x01, 0x00, 0xe4, 0x52, 0x3d, 0xfe, 0xfe, 0xff, 0xf5, 0xc7, 0xc1, 0xef, 0xa2, 0x94, 0xfe, 0xff, 0xfe, 0xfb, 0xfc, 0xfd, 0xfa, 0xfd, 0xfb, 0xff, 0xfe, 0xff, 0xfb, 0xfe, 0xfd, 0xe5, 0x4d, 0x31, 0xdb, 0x0a, 0x00, 0xdd, 0x0e, 0x00, 0xf5, 0xc3, 0xbc, 0xff, 0xfe, 0xfe, 0xfe, 0xfc, 0xfe, 0xfc, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xdb, 0xd1, 0xde, 0x0f, 0x01, 0xdd, 0x24, 0x09, 0xfa, 0xeb, 0xea, 0xfd, 0xff, 0xff, 0xfb, 0xfc, 0xfc, 0xfa, 0xfd, 0xfc, 0xfd, 0xff, 0xfd, 0xf1, 0xa7, 0xa0, 0xdd, 0x05, 0x00, 0xde, 0x24, 0x03, 0xe0, 0x2b, 0x11, 0xde, 0x33, 0x17, 0xdc, 0x21, 0x07, 0xd9, 0x0a, 0x00, 0xe2, 0x2d, 0x0a, 0xdd, 0x27, 0x0b, 0xe0, 0x27, 0x0c, 0xdf, 0x26, 0x09, 0xde, 0x28, 0x0c, 0xdf, 0x26, 0x0b, 0xde, 0x24, 0x05, 0xe2, 0x35, 0x1c, 0xe2, 0x30, 0x16, 0xdd, 0x27, 0x0b, 0xde, 0x28, 0x0a, 0xe0, 0x27, 0x0c, 0xdd, 0x27, 0x0d, 0xdf, 0x27, 0x07, 0xdb, 0x00, 0x00, 0xed, 0x87, 0x74, 0xff, 0xff, 0xff, 0xf7, 0xe1, 0xdf, 0xf6, 0xdc, 0xd7, 0xfe, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0xfd, 0xfd, 0xf0, 0x9a, 0x94, 0xdb, 0x0a, 0x01, 0xd7, 0x0f, 0x01, 0xe0, 0x2b, 0x11, 0xfb, 0xf4, 0xf5, 0xfe, 0xff, 0xfc, 0xfb, 0xfc, 0xfc, 0xfb, 0xfd, 0xf9, 0xfd, 0xff, 0xfd, 0xf6, 0xc6, 0xbe, 0xd6, 0x00, 0x00, 0xe5, 0x3a, 0x20, 0xfb, 0xfa, 0xf7, 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xfb, 0xfd, 0xfb, 0xff, 0xff, 0xfc, 0xed, 0x9d, 0x8e, 0xda, 0x02, 0x00, 0xdd, 0x22, 0x0a, 0xda, 0x1a, 0x00, 0xdb, 0x0c, 0x00, 0xda, 0x09, 0x00, 0xde, 0x1f, 0x00, 0xde, 0x1b, 0x00, 0xde, 0x2a, 0x0d, 0xe0, 0x27, 0x0c, 0xdf, 0x26, 0x09, 0xde, 0x28, 0x0c, 0xdf, 0x26, 0x0b, 0xde, 0x24, 0x05, 0xe2, 0x35, 0x1c, 0xe0, 0x30, 0x14, 0xde, 0x2a, 0x0d, 0xdc, 0x26, 0x0a, 0xde, 0x29, 0x08, 0xe1, 0x27, 0x08, 0xe0, 0x27, 0x0a, 0xdf, 0x1f, 0x04, 0xd9, 0x02, 0x03, 0xef, 0xa1, 0x96, 0xfe, 0xff, 0xff, 0xf7, 0xd1, 0xc8, 0xec, 0x8a, 0x80, 0xed, 0x87, 0x82, 0xea, 0x73, 0x5f, 0xdb, 0x11, 0x00, 0xda, 0x19, 0x03, 0xdb, 0x0c, 0x00, 0xec, 0x99, 0x8d, 0xfd, 0xff, 0xff, 0xf8, 0xff, 0xfa, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xfd, 0xfd, 0xf0, 0x98, 0x8e, 0xd6, 0x01, 0x05, 0xe2, 0x5e, 0x43, 0xfe, 0xff, 0xfc, 0xfb, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfe, 0xfc, 0xff, 0xfe, 0xff, 0xe9, 0x81, 0x72, 0xd3, 0x01, 0x00, 0xe0, 0x2c, 0x0f, 0xdb, 0x11, 0x00, 0xd8, 0x01, 0x00, 0xf0, 0xa5, 0x9c, 0xf6, 0xed, 0xe8, 0xe1, 0x34, 0x1d, 0xdb, 0x18, 0x00, 0xe0, 0x27, 0x0c, 0xdf, 0x26, 0x09, 0xde, 0x28, 0x0c, 0xdf, 0x26, 0x0b, 0xde, 0x24, 0x05, 0xe2, 0x35, 0x1c, 0xe0, 0x31, 0x16, 0xdd, 0x29, 0x0c, 0xda, 0x28, 0x0b, 0xe0, 0x27, 0x0c, 0xe0, 0x25, 0x0e, 0xd9, 0x28, 0x08, 0xde, 0x2d, 0x0d, 0xde, 0x17, 0x01, 0xd8, 0x00, 0x01, 0xf0, 0x98, 0x90, 0xfd, 0xff, 0xfc, 0xf1, 0xba, 0xaf, 0xdd, 0x16, 0x02, 0xd4, 0x00, 0x00, 0xdd, 0x16, 0x02, 0xda, 0x1e, 0x02, 0xe1, 0x27, 0x14, 0xff, 0xff, 0xff, 0xfe, 0xfd, 0xfc, 0xfc, 0xff, 0xfd, 0xfa, 0xfd, 0xfd, 0xfe, 0xff, 0xfa, 0xfd, 0xfd, 0xfe, 0xe4, 0x57, 0x3b, 0xd3, 0x00, 0x00, 0xf4, 0xb9, 0xaf, 0xfd, 0xfe, 0xff, 0xfc, 0xff, 0xf9, 0xff, 0xfe, 0xfe, 0xfc, 0xfe, 0xfc, 0xfe, 0xff, 0xff, 0xe3, 0x5c, 0x43, 0xdc, 0x04, 0x01, 0xd3, 0x00, 0x00, 0xdc, 0x17, 0x02, 0xf4, 0xb0, 0xa7, 0xff, 0xff, 0xfe, 0xf7, 0xe3, 0xdc, 0xe1, 0x2a, 0x1e, 0xdd, 0x17, 0x06, 0xe0, 0x27, 0x0c, 0xdf, 0x26, 0x09, 0xde, 0x28, 0x0c, 0xdf, 0x26, 0x0b, 0xde, 0x24, 0x05, 0xe2, 0x35, 0x1c, 0xe2, 0x30, 0x13, 0xdd, 0x24, 0x07, 0xe1, 0x28, 0x0f, 0xe1, 0x27, 0x0a, 0xde, 0x28, 0x0e, 0xdd, 0x27, 0x09, 0xdf, 0x26, 0x0b, 0xdf, 0x2b, 0x0e, 0xdd, 0x1a, 0x00, 0xda, 0x00, 0x00, 0xeb, 0x78, 0x6d, 0xfd, 0xff, 0xff, 0xfe, 0xfd, 0xfa, 0xe7, 0x79, 0x71, 0xda, 0x0e, 0x00, 0xda, 0x00, 0x00, 0xd7, 0x0d, 0x00, 0xe8, 0x58, 0x49, 0xf9, 0xf0, 0xef, 0xfd, 0xfe, 0xfe, 0xff, 0xfe, 0xfb, 0xfe, 0xff, 0xff, 0xfa, 0xd7, 0xd3, 0xda, 0x0a, 0x01, 0xdd, 0x0e, 0x02, 0xeb, 0x8a, 0x7d, 0xf7, 0xe7, 0xe3, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xf9, 0xd8, 0xd8, 0xe8, 0x7d, 0x6f, 0xd6, 0x02, 0x00, 0xd9, 0x00, 0x00, 0xe6, 0x59, 0x4f, 0xfd, 0xf4, 0xf1, 0xff, 0xff, 0xff, 0xef, 0xa3, 0x9d, 0xd9, 0x09, 0x00, 0xd9, 0x14, 0x00, 0xdf, 0x29, 0x0b, 0xe0, 0x27, 0x0c, 0xdf, 0x26, 0x09, 0xde, 0x28, 0x0c, 0xdf, 0x26, 0x0b, 0xde, 0x24, 0x05, 0xe2, 0x35, 0x1c, 0xdf, 0x30, 0x15, 0xdf, 0x29, 0x0d, 0xdd, 0x27, 0x09, 0xdc, 0x26, 0x0a, 0xde, 0x29, 0x08, 0xe0, 0x27, 0x0a, 0xde, 0x28, 0x0a, 0xe0, 0x27, 0x0a, 0xde, 0x2a, 0x0d, 0xdd, 0x1f, 0x01, 0xd9, 0x00, 0x02, 0xe4, 0x47, 0x38, 0xfb, 0xe5, 0xe1, 0xff, 0xff, 0xfc, 0xf8, 0xe5, 0xe2, 0xe7, 0x61, 0x59, 0xda, 0x1b, 0x00, 0xd4, 0x00, 0x00, 0xdc, 0x12, 0x00, 0xea, 0x6b, 0x5c, 0xf0, 0xa5, 0x99, 0xf3, 0xc7, 0xc0, 0xe6, 0x57, 0x40, 0xda, 0x08, 0x01, 0xdd, 0x2a, 0x06, 0xdb, 0x0a, 0x00, 0xdf, 0x29, 0x0d, 0xe7, 0x66, 0x52, 0xdf, 0x40, 0x28, 0xd4, 0x01, 0x00, 0xdb, 0x00, 0x03, 0xe2, 0x49, 0x3b, 0xf6, 0xc5, 0xc0, 0xfc, 0xff, 0xfd, 0xfe, 0xff, 0xfe, 0xe7, 0x6a, 0x5f, 0xda, 0x00, 0x00, 0xde, 0x15, 0x00, 0xdc, 0x2b, 0x0b, 0xe0, 0x27, 0x0a, 0xe0, 0x27, 0x0c, 0xdf, 0x26, 0x09, 0xde, 0x28, 0x0c, 0xdf, 0x26, 0x0b, 0xde, 0x24, 0x05, 0xe2, 0x35, 0x1c, 0xdf, 0x30, 0x14, 0xdd, 0x28, 0x0e, 0xdd, 0x27, 0x0b, 0xde, 0x28, 0x0c, 0xe0, 0x27, 0x0c, 0xe0, 0x27, 0x0c, 0xde, 0x28, 0x0c, 0xdd, 0x27, 0x09, 0xe0, 0x26, 0x09, 0xe1, 0x26, 0x0e, 0xde, 0x29, 0x08, 0xd7, 0x04, 0x00, 0xdf, 0x14, 0x00, 0xeb, 0x80, 0x72, 0xfe, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfb, 0xfb, 0xfc, 0xf2, 0x99, 0x8d, 0xe4, 0x42, 0x2d, 0xd4, 0x07, 0x00, 0xda, 0x01, 0x01, 0xd4, 0x02, 0x00, 0xd9, 0x01, 0x00, 0xd9, 0x06, 0x00, 0xd8, 0x05, 0x00, 0xd8, 0x08, 0x00, 0xda, 0x00, 0x00, 0xd8, 0x02, 0x00, 0xdf, 0x2a, 0x11, 0xeb, 0x7e, 0x73, 0xfa, 0xe4, 0xe2, 0xff, 0xff, 0xfe, 0xfd, 0xfe, 0xfe, 0xf0, 0xa1, 0x96, 0xde, 0x27, 0x11, 0xd8, 0x00, 0x01, 0xe0, 0x21, 0x08, 0xdf, 0x29, 0x0d, 0xdd, 0x28, 0x04, 0xdd, 0x28, 0x0e, 0xdd, 0x27, 0x09, 0xe0, 0x28, 0x08, 0xdd, 0x27, 0x09, 0xe0, 0x27, 0x0a, 0xde, 0x24, 0x05, 0xe2, 0x36, 0x1a, 0xe1, 0x31, 0x15, 0xe0, 0x27, 0x0c, 0xdf, 0x26, 0x09, 0xdf, 0x26, 0x09, 0xdf, 0x26, 0x09, 0xdf, 0x24, 0x0a, 0xdf, 0x26, 0x09, 0xdf, 0x26, 0x09, 0xdf, 0x25, 0x0e, 0xda, 0x29, 0x09, 0xdc, 0x28, 0x0b, 0xdf, 0x29, 0x0b, 0xde, 0x1b, 0x00, 0xd8, 0x02, 0x00, 0xdd, 0x25, 0x14, 0xea, 0x83, 0x78, 0xf7, 0xe6, 0xe4, 0xff, 0xff, 0xff, 0xfc, 0xfd, 0xff, 0xfe, 0xfe, 0xfd, 0xf6, 0xe0, 0xdc, 0xf4, 0xb8, 0xb2, 0xf0, 0xa5, 0x99, 0xef, 0x9f, 0x90, 0xf2, 0xa2, 0x9a, 0xf0, 0xb9, 0xae, 0xf3, 0xd9, 0xd6, 0xfc, 0xff, 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xfe, 0xfa, 0xf7, 0xf8, 0xee, 0x95, 0x89, 0xdf, 0x38, 0x22, 0xd7, 0x00, 0x01, 0xda, 0x0f, 0x00, 0xe0, 0x2a, 0x0c, 0xdd, 0x27, 0x09, 0xdd, 0x29, 0x0a, 0xdf, 0x27, 0x07, 0xdf, 0x26, 0x0d, 0xe0, 0x27, 0x0c, 0xe0, 0x27, 0x0a, 0xdd, 0x27, 0x0b, 0xdf, 0x26, 0x0b, 0xde, 0x24, 0x05, 0xe1, 0x34, 0x1b, 0xe0, 0x30, 0x12, 0xdd, 0x27, 0x0b, 0xdf, 0x26, 0x09, 0xde, 0x28, 0x0a, 0xdf, 0x29, 0x0b, 0xde, 0x28, 0x0c, 0xde, 0x28, 0x0a, 0xdf, 0x26, 0x09, 0xdd, 0x28, 0x07, 0xe0, 0x28, 0x08, 0xde, 0x28, 0x0a, 0xdc, 0x27, 0x0e, 0xe0, 0x24, 0x0a, 0xdd, 0x2b, 0x10, 0xdd, 0x13, 0x00, 0xd7, 0x00, 0x00, 0xde, 0x12, 0x00, 0xe0, 0x49, 0x32, 0xef, 0x88, 0x79, 0xf5, 0xc5, 0xbd, 0xfb, 0xf5, 0xf1, 0xfe, 0xff, 0xfe, 0xfa, 0xff, 0xfb, 0xfc, 0xff, 0xfd, 0xfe, 0xfe, 0xfe, 0xfd, 0xff, 0xfe, 0xfa, 0xfd, 0xfb, 0xf7, 0xd1, 0xca, 0xef, 0x94, 0x89, 0xe3, 0x5a, 0x44, 0xdb, 0x1f, 0x05, 0xda, 0x01, 0x01, 0xdf, 0x0f, 0x00, 0xdd, 0x28, 0x05, 0xdf, 0x26, 0x0b, 0xdf, 0x27, 0x05, 0xdd, 0x29, 0x0a, 0xe0, 0x26, 0x07, 0xde, 0x28, 0x0e, 0xe0, 0x27, 0x0a, 0xdd, 0x27, 0x0b, 0xdd, 0x27, 0x0b, 0xdc, 0x28, 0x0b, 0xde, 0x28, 0x0c, 0xdf, 0x27, 0x07, 0xe0, 0x35, 0x1b, 0xe1, 0x31, 0x15, 0xdf, 0x29, 0x0d, 0xe0, 0x27, 0x0a, 0xdc, 0x28, 0x09, 0xdd, 0x27, 0x0b, 0xdd, 0x27, 0x0b, 0xdd, 0x27, 0x0b, 0xdd, 0x27, 0x0b, 0xdd, 0x28, 0x07, 0xe0, 0x27, 0x0c, 0xe0, 0x26, 0x09, 0xe0, 0x26, 0x09, 0xe1, 0x28, 0x0b, 0xdd, 0x27, 0x09, 0xdf, 0x29, 0x0d, 0xe2, 0x2a, 0x0a, 0xe0, 0x21, 0x00, 0xdd, 0x0e, 0x02, 0xd6, 0x02, 0x00, 0xda, 0x07, 0x00, 0xde, 0x19, 0x00, 0xdf, 0x2e, 0x14, 0xe1, 0x38, 0x23, 0xe5, 0x42, 0x2a, 0xe5, 0x40, 0x28, 0xe4, 0x2f, 0x16, 0xdd, 0x1d, 0x02, 0xdb, 0x0c, 0x00, 0xd8, 0x00, 0x00, 0xda, 0x07, 0x00, 0xde, 0x1f, 0x00, 0xde, 0x28, 0x0e, 0xdc, 0x25, 0x0d, 0xde, 0x29, 0x08, 0xdc, 0x28, 0x0b, 0xe0, 0x27, 0x0a, 0xe0, 0x27, 0x0c, 0xdd, 0x27, 0x0b, 0xdf, 0x26, 0x09, 0xe1, 0x28, 0x0b, 0xe2, 0x27, 0x0d, 0xe0, 0x27, 0x0a, 0xde, 0x28, 0x0c, 0xdf, 0x26, 0x0b, 0xde, 0x26, 0x04, 0xe0, 0x34, 0x18, 0xd9, 0x27, 0x0c, 0xdd, 0x24, 0x0b, 0xe1, 0x26, 0x0c, 0xdf, 0x29, 0x0d, 0xe0, 0x27, 0x0e, 0xdf, 0x26, 0x0d, 0xe0, 0x27, 0x0e, 0xe0, 0x25, 0x0d, 0xde, 0x28, 0x0e, 0xde, 0x24, 0x0f, 0xde, 0x28, 0x0e, 0xdd, 0x29, 0x0a, 0xd9, 0x27, 0x0d, 0xe2, 0x25, 0x0e, 0xdc, 0x27, 0x0d, 0xdf, 0x24, 0x0c, 0xdc, 0x28, 0x0b, 0xe1, 0x25, 0x0b, 0xdf, 0x26, 0x0d, 0xe0, 0x27, 0x0c, 0xdf, 0x1f, 0x00, 0xdc, 0x18, 0x00, 0xdc, 0x15, 0x01, 0xda, 0x0f, 0x00, 0xde, 0x10, 0x00, 0xdd, 0x18, 0x00, 0xdc, 0x1e, 0x00, 0xde, 0x26, 0x06, 0xe0, 0x27, 0x0c, 0xdf, 0x25, 0x04, 0xdd, 0x26, 0x10, 0xdd, 0x29, 0x0c, 0xdd, 0x28, 0x07, 0xdf, 0x29, 0x0d, 0xe0, 0x27, 0x0e, 0xdf, 0x24, 0x0a, 0xdf, 0x26, 0x0d, 0xdd, 0x28, 0x0f, 0xde, 0x28, 0x0a, 0xdf, 0x25, 0x0e, 0xdd, 0x27, 0x0b, 0xdd, 0x27, 0x09, 0xde, 0x28, 0x0c, 0xe1, 0x26, 0x0c, 0xe0, 0x22, 0x04, 0xdf, 0x2d, 0x13, 0xe1, 0x3b, 0x1d, 0xe3, 0x34, 0x19, 0xe2, 0x33, 0x17, 0xde, 0x32, 0x15, 0xdf, 0x30, 0x14, 0xe0, 0x31, 0x16, 0xe1, 0x32, 0x17, 0xe0, 0x31, 0x15, 0xe2, 0x31, 0x17, 0xe2, 0x30, 0x16, 0xe2, 0x32, 0x14, 0xe0, 0x31, 0x15, 0xe0, 0x31, 0x16, 0xe2, 0x32, 0x14, 0xde, 0x32, 0x16, 0xe3, 0x33, 0x15, 0xdf, 0x33, 0x17, 0xe1, 0x32, 0x17, 0xe1, 0x32, 0x16, 0xe1, 0x32, 0x16, 0xdf, 0x30, 0x15, 0xe2, 0x33, 0x18, 0xe0, 0x31, 0x15, 0xe1, 0x30, 0x18, 0xde, 0x31, 0x18, 0xde, 0x32, 0x16, 0xe3, 0x33, 0x17, 0xde, 0x32, 0x16, 0xde, 0x31, 0x1a, 0xe4, 0x32, 0x18, 0xe1, 0x30, 0x16, 0xe2, 0x31, 0x1b, 0xe1, 0x2f, 0x1c, 0xde, 0x2f, 0x13, 0xe1, 0x32, 0x17, 0xe1, 0x32, 0x16, 0xe1, 0x32, 0x17, 0xe1, 0x32, 0x16, 0xe2, 0x31, 0x17, 0xe1, 0x32, 0x17, 0xe2, 0x31, 0x17, 0xe1, 0x31, 0x15, 0xe0, 0x31, 0x16, 0xe0, 0x31, 0x16, 0xdf, 0x2f, 0x11, 0xe1, 0x3f, 0x24\n};"
  },
  {
    "path": "esp_jpeg/test_apps/main/test_tjpgd_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"unity.h\"\n#include \"unity_test_runner.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_newlib.h\"\n\n#include \"unity_test_utils_memory.h\"\n\nvoid setUp(void)\n{\n    unity_utils_record_free_mem();\n}\n\nvoid tearDown(void)\n{\n    esp_reent_cleanup();    //clean up some of the newlib's lazy allocations\n    unity_utils_evaluate_leaks_direct(0);\n}\n\nvoid app_main(void)\n{\n    printf(\"Running esp_jpeg component tests\\n\");\n    unity_run_menu();\n}\n"
  },
  {
    "path": "esp_jpeg/test_apps/main/test_usb_camera_2_jpg.h",
    "content": "/*\nRaw data from Logitech C170 USB camera was reconstructed to usb_camera_2.jpg\nIt was converted to RGB888 array with jpg_to_rgb888_hex.py\n*/\n\n// JPEG encoded frame 160x120, 1384 bytes, has broken 0xFFFF marker\nextern const unsigned char camera_2_jpg[] asm(\"_binary_usb_camera_2_jpg_start\");\n\nextern char _binary_usb_camera_2_jpg_start;\nextern char _binary_usb_camera_2_jpg_end;\n// Must be defined as macro because extern variables are not known at compile time (but at link time)\n#define camera_2_jpg_len (&_binary_usb_camera_2_jpg_end - &_binary_usb_camera_2_jpg_start)\n"
  },
  {
    "path": "esp_jpeg/test_apps/main/test_usb_camera_2_rgb888.h",
    "content": "unsigned int usb_camera_2_rgb888[19200] = {\n    0x242422,\n    0x222220,\n    0x21221D,\n    0x252620,\n    0x31322A,\n    0x424437,\n    0x545648,\n    0x5F624F,\n    0x555942,\n    0x55593E,\n    0x555A3C,\n    0x555B39,\n    0x555B37,\n    0x555B35,\n    0x555C33,\n    0x595839,\n    0x655345,\n    0x624642,\n    0x543834,\n    0x492A27,\n    0x422320,\n    0x452220,\n    0x4C2424,\n    0x532728,\n    0x512325,\n    0x542225,\n    0x572025,\n    0x5A1F25,\n    0x5A1F25,\n    0x5C1D25,\n    0x5C1D25,\n    0x532226,\n    0x42332C,\n    0x484A3F,\n    0x5B5D52,\n    0x626459,\n    0x5E6055,\n    0x585A4F,\n    0x595B50,\n    0x5C5E53,\n    0x5B5D52,\n    0x57594E,\n    0x56584D,\n    0x5C5E53,\n    0x606257,\n    0x595B50,\n    0x46483D,\n    0x35362E,\n    0x212622,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x232726,\n    0x242827,\n    0x242827,\n    0x252928,\n    0x262A29,\n    0x272B2A,\n    0x282C2B,\n    0x282C2B,\n    0x363B35,\n    0x363B35,\n    0x363B35,\n    0x383D37,\n    0x3D423C,\n    0x434842,\n    0x4A4F49,\n    0x4E534D,\n    0x3E433D,\n    0x3E433D,\n    0x3E433D,\n    0x3E433D,\n    0x3E433D,\n    0x3E433D,\n    0x3E433D,\n    0x3E433D,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x4F544E,\n    0x4B504A,\n    0x444943,\n    0x3B403A,\n    0x313630,\n    0x282D27,\n    0x212620,\n    0x1F211C,\n    0x252722,\n    0x262722,\n    0x262722,\n    0x262722,\n    0x262722,\n    0x262722,\n    0x262722,\n    0x262722,\n    0x292A25,\n    0x292A25,\n    0x292A25,\n    0x292A25,\n    0x292A25,\n    0x292A25,\n    0x292A25,\n    0x292A25,\n    0x272823,\n    0x272823,\n    0x272823,\n    0x272823,\n    0x272823,\n    0x272823,\n    0x272823,\n    0x272823,\n    0x1D1E19,\n    0x1D1E19,\n    0x1D1E19,\n    0x1D1E19,\n    0x1D1E19,\n    0x1D1E19,\n    0x1D1E19,\n    0x1D1D1B,\n    0x1F2420,\n    0x1F2322,\n    0x1F2322,\n    0x1F2322,\n    0x1F2322,\n    0x1F2322,\n    0x1F2322,\n    0x1F2322,\n    0x1D2120,\n    0x1D2120,\n    0x1D2120,\n    0x1D2120,\n    0x1D2120,\n    0x1D2120,\n    0x1D2120,\n    0x1D2120,\n    0x232726,\n    0x232726,\n    0x232726,\n    0x232726,\n    0x232726,\n    0x232726,\n    0x232726,\n    0x232726,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x2A2A28,\n    0x262624,\n    0x22231E,\n    0x23241E,\n    0x2B2C24,\n    0x393B2E,\n    0x47493B,\n    0x515441,\n    0x555942,\n    0x55593E,\n    0x555A3C,\n    0x555B39,\n    0x555B37,\n    0x555B35,\n    0x555C33,\n    0x595839,\n    0x655345,\n    0x624642,\n    0x543834,\n    0x492A27,\n    0x422320,\n    0x452220,\n    0x4C2424,\n    0x532728,\n    0x512325,\n    0x542225,\n    0x572025,\n    0x5A1F25,\n    0x5A1F25,\n    0x5C1D25,\n    0x5C1D25,\n    0x532226,\n    0x42332C,\n    0x484A3F,\n    0x5B5D52,\n    0x626459,\n    0x5E6055,\n    0x585A4F,\n    0x595B50,\n    0x5C5E53,\n    0x5B5D52,\n    0x57594E,\n    0x56584D,\n    0x5C5E53,\n    0x606257,\n    0x595B50,\n    0x46483D,\n    0x35362E,\n    0x212622,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x222625,\n    0x232726,\n    0x252928,\n    0x282C2B,\n    0x2B2F2E,\n    0x2E3231,\n    0x303433,\n    0x323635,\n    0x393E38,\n    0x393E38,\n    0x3A3F39,\n    0x3D423C,\n    0x424741,\n    0x484D47,\n    0x4D524C,\n    0x50554F,\n    0x424741,\n    0x424741,\n    0x424741,\n    0x424741,\n    0x424741,\n    0x424741,\n    0x424741,\n    0x424741,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x494E48,\n    0x474C46,\n    0x414640,\n    0x3B403A,\n    0x343933,\n    0x2D322C,\n    0x282D27,\n    0x272924,\n    0x2B2D28,\n    0x2C2D28,\n    0x2C2D28,\n    0x2C2D28,\n    0x2C2D28,\n    0x2C2D28,\n    0x2C2D28,\n    0x2C2D28,\n    0x2B2C27,\n    0x2B2C27,\n    0x2B2C27,\n    0x2B2C27,\n    0x2B2C27,\n    0x2B2C27,\n    0x2B2C27,\n    0x2B2C27,\n    0x292A25,\n    0x292A25,\n    0x292A25,\n    0x292A25,\n    0x292A25,\n    0x292A25,\n    0x292A25,\n    0x292A25,\n    0x272823,\n    0x272823,\n    0x272823,\n    0x272823,\n    0x272823,\n    0x272823,\n    0x272823,\n    0x272725,\n    0x282D29,\n    0x282C2B,\n    0x282C2B,\n    0x282C2B,\n    0x282C2B,\n    0x282C2B,\n    0x282C2B,\n    0x282C2B,\n    0x262A29,\n    0x262A29,\n    0x262A29,\n    0x262A29,\n    0x262A29,\n    0x262A29,\n    0x262A29,\n    0x262A29,\n    0x242827,\n    0x242827,\n    0x242827,\n    0x242827,\n    0x242827,\n    0x242827,\n    0x242827,\n    0x242827,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x333331,\n    0x2F2F2D,\n    0x2A2B26,\n    0x282923,\n    0x2E2F27,\n    0x3A3C2F,\n    0x47493B,\n    0x505340,\n    0x555942,\n    0x55593E,\n    0x555A3C,\n    0x555B39,\n    0x555B37,\n    0x555B35,\n    0x555C33,\n    0x595839,\n    0x655345,\n    0x624642,\n    0x543834,\n    0x492A27,\n    0x422320,\n    0x452220,\n    0x4C2424,\n    0x532728,\n    0x512325,\n    0x542225,\n    0x572025,\n    0x5A1F25,\n    0x5A1F25,\n    0x5C1D25,\n    0x5C1D25,\n    0x532226,\n    0x42332C,\n    0x484A3F,\n    0x5B5D52,\n    0x626459,\n    0x5E6055,\n    0x585A4F,\n    0x595B50,\n    0x5C5E53,\n    0x5B5D52,\n    0x57594E,\n    0x56584D,\n    0x5C5E53,\n    0x606257,\n    0x595B50,\n    0x46483D,\n    0x35362E,\n    0x212622,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x202423,\n    0x222625,\n    0x262A29,\n    0x2C302F,\n    0x323635,\n    0x383C3B,\n    0x3C403F,\n    0x3F4342,\n    0x3B403A,\n    0x3D423C,\n    0x414640,\n    0x454A44,\n    0x4A4F49,\n    0x4E534D,\n    0x515650,\n    0x535852,\n    0x484D47,\n    0x484D47,\n    0x484D47,\n    0x484D47,\n    0x484D47,\n    0x484D47,\n    0x484D47,\n    0x484D47,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x40453F,\n    0x3E433D,\n    0x3B403A,\n    0x383D37,\n    0x353A34,\n    0x333832,\n    0x343631,\n    0x343631,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x2F302B,\n    0x2F302B,\n    0x2F302B,\n    0x2F302B,\n    0x2F302B,\n    0x2F302B,\n    0x2F302B,\n    0x2F302B,\n    0x2D2E29,\n    0x2D2E29,\n    0x2D2E29,\n    0x2D2E29,\n    0x2D2E29,\n    0x2D2E29,\n    0x2D2E29,\n    0x2D2E29,\n    0x30312C,\n    0x30312C,\n    0x30312C,\n    0x30312C,\n    0x30312C,\n    0x30312C,\n    0x30312C,\n    0x30302E,\n    0x2F3430,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x262A29,\n    0x262A29,\n    0x262A29,\n    0x262A29,\n    0x262A29,\n    0x262A29,\n    0x262A29,\n    0x262A29,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x31312F,\n    0x2D2D2B,\n    0x2A2B26,\n    0x2C2D27,\n    0x34352D,\n    0x434538,\n    0x525446,\n    0x5C5F4C,\n    0x555942,\n    0x55593E,\n    0x555A3C,\n    0x555B39,\n    0x555B37,\n    0x555B35,\n    0x555C33,\n    0x595839,\n    0x655345,\n    0x624642,\n    0x543834,\n    0x492A27,\n    0x422320,\n    0x452220,\n    0x4C2424,\n    0x532728,\n    0x512325,\n    0x542225,\n    0x572025,\n    0x5A1F25,\n    0x5A1F25,\n    0x5C1D25,\n    0x5C1D25,\n    0x532226,\n    0x42332C,\n    0x484A3F,\n    0x5B5D52,\n    0x626459,\n    0x5E6055,\n    0x585A4F,\n    0x595B50,\n    0x5C5E53,\n    0x5B5D52,\n    0x57594E,\n    0x56584D,\n    0x5C5E53,\n    0x606257,\n    0x595B50,\n    0x46483D,\n    0x35362E,\n    0x212622,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x1E2221,\n    0x212524,\n    0x272B2A,\n    0x2F3332,\n    0x373B3A,\n    0x3F4342,\n    0x454948,\n    0x484C4B,\n    0x3C413B,\n    0x40453F,\n    0x464B45,\n    0x4D524C,\n    0x515650,\n    0x545953,\n    0x545953,\n    0x545953,\n    0x4B504A,\n    0x4B504A,\n    0x4B504A,\n    0x4B504A,\n    0x4B504A,\n    0x4B504A,\n    0x4B504A,\n    0x4B504A,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x3A3F39,\n    0x3B403A,\n    0x3B403A,\n    0x3C413B,\n    0x3C413B,\n    0x3D423C,\n    0x3D423C,\n    0x3F413C,\n    0x3E403B,\n    0x3F403B,\n    0x3F403B,\n    0x3F403B,\n    0x3F403B,\n    0x3F403B,\n    0x3F403B,\n    0x3F403B,\n    0x343530,\n    0x343530,\n    0x343530,\n    0x343530,\n    0x343530,\n    0x343530,\n    0x343530,\n    0x343530,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x323230,\n    0x2F3430,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x2D3130,\n    0x2D3130,\n    0x2D3130,\n    0x2D3130,\n    0x2D3130,\n    0x2D3130,\n    0x2D3130,\n    0x2D3130,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x1B1B19,\n    0x1A1A18,\n    0x1A1B16,\n    0x1F201A,\n    0x2C2D25,\n    0x3E4033,\n    0x515345,\n    0x5C5F4C,\n    0x555942,\n    0x55593E,\n    0x555A3C,\n    0x555B39,\n    0x555B37,\n    0x555B35,\n    0x555C33,\n    0x595839,\n    0x655345,\n    0x624642,\n    0x543834,\n    0x492A27,\n    0x422320,\n    0x452220,\n    0x4C2424,\n    0x532728,\n    0x512325,\n    0x542225,\n    0x572025,\n    0x5A1F25,\n    0x5A1F25,\n    0x5C1D25,\n    0x5C1D25,\n    0x532226,\n    0x42332C,\n    0x484A3F,\n    0x5B5D52,\n    0x626459,\n    0x5E6055,\n    0x585A4F,\n    0x595B50,\n    0x5C5E53,\n    0x5B5D52,\n    0x57594E,\n    0x56584D,\n    0x5C5E53,\n    0x606257,\n    0x595B50,\n    0x46483D,\n    0x35362E,\n    0x212622,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x1E2221,\n    0x212524,\n    0x272B2A,\n    0x2F3332,\n    0x373B3A,\n    0x3F4342,\n    0x454948,\n    0x484C4B,\n    0x383D37,\n    0x3E433D,\n    0x484D47,\n    0x50554F,\n    0x555A54,\n    0x555A54,\n    0x525751,\n    0x50554F,\n    0x4B504A,\n    0x4B504A,\n    0x4B504A,\n    0x4B504A,\n    0x4B504A,\n    0x4B504A,\n    0x4B504A,\n    0x4B504A,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x393E38,\n    0x3A3F39,\n    0x3C413B,\n    0x3E433D,\n    0x40453F,\n    0x424741,\n    0x434842,\n    0x464843,\n    0x434540,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x3A3B36,\n    0x3A3B36,\n    0x3A3B36,\n    0x3A3B36,\n    0x3A3B36,\n    0x3A3B36,\n    0x3A3B36,\n    0x3A3B36,\n    0x383934,\n    0x383934,\n    0x383934,\n    0x383934,\n    0x383934,\n    0x383934,\n    0x383934,\n    0x383934,\n    0x30312C,\n    0x30312C,\n    0x30312C,\n    0x30312C,\n    0x30312C,\n    0x30312C,\n    0x30312C,\n    0x30302E,\n    0x2A2F2B,\n    0x2A2E2D,\n    0x2A2E2D,\n    0x2A2E2D,\n    0x2A2E2D,\n    0x2A2E2D,\n    0x2A2E2D,\n    0x2A2E2D,\n    0x282C2B,\n    0x282C2B,\n    0x282C2B,\n    0x282C2B,\n    0x282C2B,\n    0x282C2B,\n    0x282C2B,\n    0x282C2B,\n    0x2C302F,\n    0x2C302F,\n    0x2C302F,\n    0x2C302F,\n    0x2C302F,\n    0x2C302F,\n    0x2C302F,\n    0x2C302F,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x181816,\n    0x161614,\n    0x151611,\n    0x191A14,\n    0x25261E,\n    0x36382B,\n    0x47493B,\n    0x525542,\n    0x555942,\n    0x55593E,\n    0x555A3C,\n    0x555B39,\n    0x555B37,\n    0x555B35,\n    0x555C33,\n    0x595839,\n    0x655345,\n    0x624642,\n    0x543834,\n    0x492A27,\n    0x422320,\n    0x452220,\n    0x4C2424,\n    0x532728,\n    0x512325,\n    0x542225,\n    0x572025,\n    0x5A1F25,\n    0x5A1F25,\n    0x5C1D25,\n    0x5C1D25,\n    0x532226,\n    0x42332C,\n    0x484A3F,\n    0x5B5D52,\n    0x626459,\n    0x5E6055,\n    0x585A4F,\n    0x595B50,\n    0x5C5E53,\n    0x5B5D52,\n    0x57594E,\n    0x56584D,\n    0x5C5E53,\n    0x606257,\n    0x595B50,\n    0x46483D,\n    0x35362E,\n    0x212622,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x202423,\n    0x222625,\n    0x262A29,\n    0x2C302F,\n    0x323635,\n    0x383C3B,\n    0x3C403F,\n    0x3F4342,\n    0x313630,\n    0x393E38,\n    0x454A44,\n    0x50554F,\n    0x555A54,\n    0x535852,\n    0x4D524C,\n    0x494E48,\n    0x484D47,\n    0x484D47,\n    0x484D47,\n    0x484D47,\n    0x484D47,\n    0x484D47,\n    0x484D47,\n    0x484D47,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x3E433D,\n    0x3E433D,\n    0x3F443E,\n    0x414640,\n    0x424741,\n    0x434842,\n    0x444943,\n    0x474944,\n    0x444641,\n    0x454641,\n    0x454641,\n    0x454641,\n    0x454641,\n    0x454641,\n    0x454641,\n    0x454641,\n    0x3F403B,\n    0x3F403B,\n    0x3F403B,\n    0x3F403B,\n    0x3F403B,\n    0x3F403B,\n    0x3F403B,\n    0x3F403B,\n    0x3D3E39,\n    0x3D3E39,\n    0x3D3E39,\n    0x3D3E39,\n    0x3D3E39,\n    0x3D3E39,\n    0x3D3E39,\n    0x3D3E39,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x323230,\n    0x292E2A,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x272B2A,\n    0x272B2A,\n    0x272B2A,\n    0x272B2A,\n    0x272B2A,\n    0x272B2A,\n    0x272B2A,\n    0x272B2A,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x484846,\n    0x424240,\n    0x3B3C37,\n    0x383933,\n    0x3B3C34,\n    0x444639,\n    0x505244,\n    0x585B48,\n    0x555942,\n    0x55593E,\n    0x555A3C,\n    0x555B39,\n    0x555B37,\n    0x555B35,\n    0x555C33,\n    0x595839,\n    0x655345,\n    0x624642,\n    0x543834,\n    0x492A27,\n    0x422320,\n    0x452220,\n    0x4C2424,\n    0x532728,\n    0x512325,\n    0x542225,\n    0x572025,\n    0x5A1F25,\n    0x5A1F25,\n    0x5C1D25,\n    0x5C1D25,\n    0x532226,\n    0x42332C,\n    0x484A3F,\n    0x5B5D52,\n    0x626459,\n    0x5E6055,\n    0x585A4F,\n    0x595B50,\n    0x5C5E53,\n    0x5B5D52,\n    0x57594E,\n    0x56584D,\n    0x5C5E53,\n    0x606257,\n    0x595B50,\n    0x46483D,\n    0x35362E,\n    0x212622,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x222625,\n    0x232726,\n    0x252928,\n    0x282C2B,\n    0x2B2F2E,\n    0x2E3231,\n    0x303433,\n    0x323635,\n    0x292E28,\n    0x323731,\n    0x414640,\n    0x4D524C,\n    0x525751,\n    0x4E534D,\n    0x464B45,\n    0x40453F,\n    0x424741,\n    0x424741,\n    0x424741,\n    0x424741,\n    0x424741,\n    0x424741,\n    0x424741,\n    0x424741,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x454A44,\n    0x444943,\n    0x444943,\n    0x444943,\n    0x434842,\n    0x424741,\n    0x424741,\n    0x444641,\n    0x434540,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x41423D,\n    0x41423D,\n    0x41423D,\n    0x41423D,\n    0x41423D,\n    0x41423D,\n    0x41423D,\n    0x41423D,\n    0x3C3D38,\n    0x3C3D38,\n    0x3C3D38,\n    0x3C3D38,\n    0x3C3D38,\n    0x3C3D38,\n    0x3C3D38,\n    0x3C3C3A,\n    0x313632,\n    0x313534,\n    0x313534,\n    0x313534,\n    0x313534,\n    0x313534,\n    0x313534,\n    0x313534,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x2F3332,\n    0x313534,\n    0x313534,\n    0x313534,\n    0x313534,\n    0x313534,\n    0x313534,\n    0x313534,\n    0x313534,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x828280,\n    0x7A7A78,\n    0x6D6E69,\n    0x62635D,\n    0x5D5E56,\n    0x5F6154,\n    0x656759,\n    0x6A6D5A,\n    0x555942,\n    0x55593E,\n    0x555A3C,\n    0x555B39,\n    0x555B37,\n    0x555B35,\n    0x555C33,\n    0x595839,\n    0x655345,\n    0x624642,\n    0x543834,\n    0x492A27,\n    0x422320,\n    0x452220,\n    0x4C2424,\n    0x532728,\n    0x512325,\n    0x542225,\n    0x572025,\n    0x5A1F25,\n    0x5A1F25,\n    0x5C1D25,\n    0x5C1D25,\n    0x532226,\n    0x42332C,\n    0x484A3F,\n    0x5B5D52,\n    0x626459,\n    0x5E6055,\n    0x585A4F,\n    0x595B50,\n    0x5C5E53,\n    0x5B5D52,\n    0x57594E,\n    0x56584D,\n    0x5C5E53,\n    0x606257,\n    0x595B50,\n    0x46483D,\n    0x35362E,\n    0x212622,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x232726,\n    0x242827,\n    0x242827,\n    0x252928,\n    0x262A29,\n    0x272B2A,\n    0x282C2B,\n    0x282C2B,\n    0x232822,\n    0x2E332D,\n    0x3E433D,\n    0x4B504A,\n    0x4F544E,\n    0x4B504A,\n    0x424741,\n    0x3B403A,\n    0x3E433D,\n    0x3E433D,\n    0x3E433D,\n    0x3E433D,\n    0x3E433D,\n    0x3E433D,\n    0x3E433D,\n    0x3E433D,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x414640,\n    0x4A4F49,\n    0x494E48,\n    0x474C46,\n    0x454A44,\n    0x434842,\n    0x414640,\n    0x40453F,\n    0x41433E,\n    0x41433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x454641,\n    0x454641,\n    0x454641,\n    0x454641,\n    0x454641,\n    0x454641,\n    0x454641,\n    0x454641,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464644,\n    0x3A3F3B,\n    0x3A3E3D,\n    0x3A3E3D,\n    0x3A3E3D,\n    0x3A3E3D,\n    0x3A3E3D,\n    0x3A3E3D,\n    0x3A3E3D,\n    0x383C3B,\n    0x383C3B,\n    0x383C3B,\n    0x383C3B,\n    0x383C3B,\n    0x383C3B,\n    0x383C3B,\n    0x383C3B,\n    0x323635,\n    0x323635,\n    0x323635,\n    0x323635,\n    0x323635,\n    0x323635,\n    0x323635,\n    0x323635,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x292D2C,\n    0x63B1BD,\n    0x58A5AF,\n    0x4D969F,\n    0x4B8E96,\n    0x508B8F,\n    0x518384,\n    0x4B7372,\n    0x46635E,\n    0x465A4F,\n    0x4F5748,\n    0x545543,\n    0x5B533E,\n    0x615138,\n    0x655035,\n    0x684E33,\n    0x684D38,\n    0x6F594E,\n    0x634E4B,\n    0x563E3C,\n    0x492F2E,\n    0x422625,\n    0x432324,\n    0x482627,\n    0x4F282B,\n    0x4C2226,\n    0x4F2026,\n    0x512026,\n    0x531E26,\n    0x551D26,\n    0x561D26,\n    0x581C26,\n    0x4C2128,\n    0x463E3C,\n    0x424B46,\n    0x4E5752,\n    0x57605B,\n    0x5A635E,\n    0x57605B,\n    0x505954,\n    0x4B544F,\n    0x4F5853,\n    0x515A55,\n    0x545D58,\n    0x555E59,\n    0x535C57,\n    0x4D5651,\n    0x47504B,\n    0x454B47,\n    0x242621,\n    0x252621,\n    0x252621,\n    0x252621,\n    0x252621,\n    0x252621,\n    0x252621,\n    0x252621,\n    0x2E2F2A,\n    0x2D2E29,\n    0x2B2C27,\n    0x292A25,\n    0x272823,\n    0x252621,\n    0x23241F,\n    0x23221D,\n    0x232019,\n    0x2D2920,\n    0x3B372E,\n    0x48443B,\n    0x4F4B42,\n    0x4F4B42,\n    0x4B473E,\n    0x47433A,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x49463D,\n    0x45453B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404139,\n    0x353630,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x67B3C0,\n    0x5CA6B1,\n    0x5296A1,\n    0x508F98,\n    0x548B90,\n    0x558285,\n    0x4C7372,\n    0x48635E,\n    0x47584E,\n    0x4F5547,\n    0x555442,\n    0x5C513D,\n    0x614F37,\n    0x664E34,\n    0x6A4C32,\n    0x684C37,\n    0x664E44,\n    0x5B4643,\n    0x4F3735,\n    0x442A29,\n    0x3F2322,\n    0x422223,\n    0x492728,\n    0x50292C,\n    0x4C2226,\n    0x4F2026,\n    0x512026,\n    0x531E26,\n    0x551D26,\n    0x561D26,\n    0x581C26,\n    0x4E2128,\n    0x3E3331,\n    0x3D3F3A,\n    0x4A4C47,\n    0x565853,\n    0x5C5E59,\n    0x5A5C57,\n    0x555752,\n    0x50524D,\n    0x535550,\n    0x555752,\n    0x585A55,\n    0x595B56,\n    0x575954,\n    0x51534E,\n    0x4B4D48,\n    0x474944,\n    0x262722,\n    0x262722,\n    0x262722,\n    0x262722,\n    0x262722,\n    0x262722,\n    0x262722,\n    0x262722,\n    0x2E2F2A,\n    0x2D2E29,\n    0x2B2C27,\n    0x292A25,\n    0x272823,\n    0x252621,\n    0x23241F,\n    0x23221D,\n    0x232019,\n    0x2D2920,\n    0x3B372E,\n    0x48443B,\n    0x4F4B42,\n    0x4F4B42,\n    0x4B473E,\n    0x47433A,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x49463D,\n    0x45453B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404139,\n    0x363731,\n    0x363732,\n    0x363732,\n    0x363732,\n    0x363732,\n    0x363732,\n    0x363732,\n    0x363732,\n    0x33342F,\n    0x33342F,\n    0x33342F,\n    0x33342F,\n    0x33342F,\n    0x33342F,\n    0x33342F,\n    0x33342F,\n    0x71B6C5,\n    0x64A8B5,\n    0x5999A5,\n    0x558F9A,\n    0x598B92,\n    0x588185,\n    0x506F71,\n    0x4B5F5D,\n    0x49544C,\n    0x515145,\n    0x575040,\n    0x5E4D3B,\n    0x644B35,\n    0x684A32,\n    0x6B4930,\n    0x694835,\n    0x594137,\n    0x4E3936,\n    0x452D2B,\n    0x3D2322,\n    0x3B1F1E,\n    0x412122,\n    0x4A2829,\n    0x522B2E,\n    0x4C2226,\n    0x4F2026,\n    0x512026,\n    0x531E26,\n    0x551D26,\n    0x561D26,\n    0x581C26,\n    0x4F2026,\n    0x34211D,\n    0x362F27,\n    0x463F37,\n    0x544D45,\n    0x5D564E,\n    0x5E574F,\n    0x5B544C,\n    0x585149,\n    0x585149,\n    0x5A534B,\n    0x5D564E,\n    0x5E574F,\n    0x5C554D,\n    0x564F47,\n    0x504941,\n    0x4A453F,\n    0x292823,\n    0x282924,\n    0x282924,\n    0x282924,\n    0x282924,\n    0x282924,\n    0x282924,\n    0x282924,\n    0x2E2F2A,\n    0x2D2E29,\n    0x2B2C27,\n    0x292A25,\n    0x272823,\n    0x252621,\n    0x23241F,\n    0x23221D,\n    0x232019,\n    0x2D2920,\n    0x3B372E,\n    0x48443B,\n    0x4F4B42,\n    0x4F4B42,\n    0x4B473E,\n    0x47433A,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x49463D,\n    0x45453B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404139,\n    0x383933,\n    0x383934,\n    0x383934,\n    0x383934,\n    0x383934,\n    0x383934,\n    0x383934,\n    0x383934,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x7CB9CB,\n    0x70ABBB,\n    0x629AA9,\n    0x5F909E,\n    0x5F8A93,\n    0x5E7F86,\n    0x546D71,\n    0x4E5C5C,\n    0x4A4F49,\n    0x534C42,\n    0x5A4A3D,\n    0x614738,\n    0x654632,\n    0x69452F,\n    0x6D432D,\n    0x6A4332,\n    0x52372E,\n    0x46312E,\n    0x3E2624,\n    0x381E1D,\n    0x391D1C,\n    0x402021,\n    0x4B292A,\n    0x542D30,\n    0x4C2226,\n    0x4F2026,\n    0x512026,\n    0x531E26,\n    0x551D26,\n    0x561D26,\n    0x581C26,\n    0x521F24,\n    0x30130F,\n    0x342017,\n    0x453128,\n    0x554138,\n    0x604C43,\n    0x634F46,\n    0x624E45,\n    0x5F4B42,\n    0x5E4A41,\n    0x604C43,\n    0x634F46,\n    0x655148,\n    0x624E45,\n    0x5D4940,\n    0x564239,\n    0x4E3F38,\n    0x2E2923,\n    0x2A2B26,\n    0x2A2B26,\n    0x2A2B26,\n    0x2A2B26,\n    0x2A2B26,\n    0x2A2B26,\n    0x2A2B26,\n    0x2E2F2A,\n    0x2D2E29,\n    0x2B2C27,\n    0x292A25,\n    0x272823,\n    0x252621,\n    0x23241F,\n    0x23221D,\n    0x232019,\n    0x2D2920,\n    0x3B372E,\n    0x48443B,\n    0x4F4B42,\n    0x4F4B42,\n    0x4B473E,\n    0x47433A,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x49463D,\n    0x45453B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404139,\n    0x3B3C36,\n    0x3B3C37,\n    0x3B3C37,\n    0x3B3C37,\n    0x3B3C37,\n    0x3B3C37,\n    0x3B3C37,\n    0x3B3C37,\n    0x373833,\n    0x373833,\n    0x373833,\n    0x373833,\n    0x373833,\n    0x373833,\n    0x373833,\n    0x373833,\n    0x87BED2,\n    0x7AAFC1,\n    0x6D9CAE,\n    0x6791A1,\n    0x658995,\n    0x627D86,\n    0x586970,\n    0x53585B,\n    0x4D4946,\n    0x55463F,\n    0x5B453A,\n    0x624235,\n    0x67402F,\n    0x6C3F2C,\n    0x6E3E2A,\n    0x6A3F2F,\n    0x53362E,\n    0x46312E,\n    0x3E2624,\n    0x381E1D,\n    0x391D1C,\n    0x402021,\n    0x4B292A,\n    0x542D30,\n    0x4C2226,\n    0x4F2026,\n    0x512026,\n    0x531E26,\n    0x551D26,\n    0x561D26,\n    0x581C26,\n    0x551E23,\n    0x350C06,\n    0x3D190D,\n    0x4E2A1E,\n    0x5E3A2E,\n    0x694539,\n    0x6D493D,\n    0x6B473B,\n    0x694539,\n    0x674337,\n    0x6A463A,\n    0x6D493D,\n    0x6E4A3E,\n    0x6B473B,\n    0x664236,\n    0x603C30,\n    0x553A31,\n    0x342B24,\n    0x2D2E29,\n    0x2D2E29,\n    0x2D2E29,\n    0x2D2E29,\n    0x2D2E29,\n    0x2D2E29,\n    0x2D2E29,\n    0x2E2F2A,\n    0x2D2E29,\n    0x2B2C27,\n    0x292A25,\n    0x272823,\n    0x252621,\n    0x23241F,\n    0x23221D,\n    0x232019,\n    0x2D2920,\n    0x3B372E,\n    0x48443B,\n    0x4F4B42,\n    0x4F4B42,\n    0x4B473E,\n    0x47433A,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x49463D,\n    0x45453B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404139,\n    0x3E3F39,\n    0x3E3F3A,\n    0x3E3F3A,\n    0x3E3F3A,\n    0x3E3F3A,\n    0x3E3F3A,\n    0x3E3F3A,\n    0x3E3F3A,\n    0x3A3B36,\n    0x3A3B36,\n    0x3A3B36,\n    0x3A3B36,\n    0x3A3B36,\n    0x3A3B36,\n    0x3A3B36,\n    0x3A3B36,\n    0x93C1D8,\n    0x85B2C7,\n    0x769FB3,\n    0x6E91A4,\n    0x6D8997,\n    0x697B87,\n    0x5D6770,\n    0x56555A,\n    0x4E4443,\n    0x56413C,\n    0x5D3F37,\n    0x643C32,\n    0x6A3A2C,\n    0x6E3929,\n    0x713827,\n    0x6B3A2C,\n    0x5D3F37,\n    0x4E3936,\n    0x452D2B,\n    0x3D2322,\n    0x3B1F1E,\n    0x412122,\n    0x4A2829,\n    0x522B2E,\n    0x4C2226,\n    0x4F2026,\n    0x512026,\n    0x531E26,\n    0x551D26,\n    0x561D26,\n    0x581C26,\n    0x561D23,\n    0x440F07,\n    0x4C1B0D,\n    0x5B2A1C,\n    0x6A392B,\n    0x724133,\n    0x744335,\n    0x714032,\n    0x6E3D2F,\n    0x6E3D2F,\n    0x703F31,\n    0x734234,\n    0x744335,\n    0x724133,\n    0x6C3B2D,\n    0x663527,\n    0x5A3429,\n    0x382D27,\n    0x30312C,\n    0x30312C,\n    0x30312C,\n    0x30312C,\n    0x30312C,\n    0x30312C,\n    0x30312C,\n    0x2E2F2A,\n    0x2D2E29,\n    0x2B2C27,\n    0x292A25,\n    0x272823,\n    0x252621,\n    0x23241F,\n    0x23221D,\n    0x232019,\n    0x2D2920,\n    0x3B372E,\n    0x48443B,\n    0x4F4B42,\n    0x4F4B42,\n    0x4B473E,\n    0x47433A,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x49463D,\n    0x45453B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404139,\n    0x41423C,\n    0x41423D,\n    0x41423D,\n    0x41423D,\n    0x41423D,\n    0x41423D,\n    0x41423D,\n    0x41423D,\n    0x3D3E39,\n    0x3D3E39,\n    0x3D3E39,\n    0x3D3E39,\n    0x3D3E39,\n    0x3D3E39,\n    0x3D3E39,\n    0x3D3E39,\n    0x9BC5DD,\n    0x8CB5CB,\n    0x7EA1B7,\n    0x7692A7,\n    0x738899,\n    0x6D7987,\n    0x60646F,\n    0x595259,\n    0x504041,\n    0x593D3A,\n    0x5E3B35,\n    0x653930,\n    0x6B372A,\n    0x6F3527,\n    0x733425,\n    0x6C362A,\n    0x6C4B44,\n    0x5B4643,\n    0x4F3735,\n    0x442A29,\n    0x3F2322,\n    0x422223,\n    0x492728,\n    0x50292C,\n    0x4C2226,\n    0x4F2026,\n    0x512026,\n    0x531E26,\n    0x551D26,\n    0x561D26,\n    0x581C26,\n    0x591C21,\n    0x541A0F,\n    0x5D2212,\n    0x6A2F1F,\n    0x763B2B,\n    0x7B4030,\n    0x7A3F2F,\n    0x753A2A,\n    0x703525,\n    0x733828,\n    0x753A2A,\n    0x783D2D,\n    0x793E2E,\n    0x773C2C,\n    0x713626,\n    0x6B3020,\n    0x5C3023,\n    0x3D2E27,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x32332E,\n    0x2E2F2A,\n    0x2D2E29,\n    0x2B2C27,\n    0x292A25,\n    0x272823,\n    0x252621,\n    0x23241F,\n    0x23221D,\n    0x232019,\n    0x2D2920,\n    0x3B372E,\n    0x48443B,\n    0x4F4B42,\n    0x4F4B42,\n    0x4B473E,\n    0x47433A,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x49463D,\n    0x45453B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404139,\n    0x43443E,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x3F403B,\n    0x3F403B,\n    0x3F403B,\n    0x3F403B,\n    0x3F403B,\n    0x3F403B,\n    0x3F403B,\n    0x3F403B,\n    0xA0C5DF,\n    0x92B6CE,\n    0x81A1B8,\n    0x7893A8,\n    0x76899A,\n    0x707988,\n    0x61636F,\n    0x5B5159,\n    0x513E40,\n    0x593B39,\n    0x603934,\n    0x67362F,\n    0x6D3429,\n    0x713326,\n    0x743224,\n    0x6D3429,\n    0x76554E,\n    0x634E4B,\n    0x563E3C,\n    0x492F2E,\n    0x422625,\n    0x432324,\n    0x482627,\n    0x4F282B,\n    0x4C2226,\n    0x4F2026,\n    0x512026,\n    0x531E26,\n    0x551D26,\n    0x561D26,\n    0x581C26,\n    0x591C21,\n    0x602016,\n    0x6A2818,\n    0x753323,\n    0x7F3D2D,\n    0x824030,\n    0x7F3D2D,\n    0x783626,\n    0x733121,\n    0x773525,\n    0x793727,\n    0x7C3A2A,\n    0x7D3B2B,\n    0x7B3929,\n    0x753323,\n    0x6F2D1D,\n    0x5F2E20,\n    0x3E2F28,\n    0x33342F,\n    0x33342F,\n    0x33342F,\n    0x33342F,\n    0x33342F,\n    0x33342F,\n    0x33342F,\n    0x2E2F2A,\n    0x2D2E29,\n    0x2B2C27,\n    0x292A25,\n    0x272823,\n    0x252621,\n    0x23241F,\n    0x23221D,\n    0x232019,\n    0x2D2920,\n    0x3B372E,\n    0x48443B,\n    0x4F4B42,\n    0x4F4B42,\n    0x4B473E,\n    0x47433A,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x49463D,\n    0x45453B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x44463B,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404139,\n    0x44453F,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x96C1E3,\n    0x8DB6D6,\n    0x83A6C6,\n    0x7F9CBA,\n    0x7B93AD,\n    0x74839A,\n    0x64697D,\n    0x5B5464,\n    0x554550,\n    0x5D4249,\n    0x634044,\n    0x6A3E3F,\n    0x6F3C39,\n    0x743A36,\n    0x763934,\n    0x793832,\n    0x76312C,\n    0x752E2A,\n    0x722B27,\n    0x6E2723,\n    0x69221E,\n    0x641D19,\n    0x611A16,\n    0x5F1814,\n    0x67201C,\n    0x67201C,\n    0x67201C,\n    0x67201C,\n    0x67201C,\n    0x67201C,\n    0x67201C,\n    0x65221C,\n    0x5D2318,\n    0x5F291D,\n    0x673125,\n    0x6E382C,\n    0x733D31,\n    0x743E32,\n    0x733D31,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x673F35,\n    0x3D3125,\n    0x323429,\n    0x313328,\n    0x2F3126,\n    0x2C2E23,\n    0x2A2C21,\n    0x292B20,\n    0x282A1F,\n    0x2E3025,\n    0x2B2D22,\n    0x27291E,\n    0x24261B,\n    0x25271C,\n    0x292B20,\n    0x2E3025,\n    0x333329,\n    0x38352C,\n    0x3A362D,\n    0x3D3930,\n    0x413D34,\n    0x454138,\n    0x48443B,\n    0x4B473E,\n    0x4D4940,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x474539,\n    0x434337,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x96C3E4,\n    0x8CB7D7,\n    0x81A8C7,\n    0x7D9FBB,\n    0x7C96AF,\n    0x74849B,\n    0x636B7E,\n    0x595765,\n    0x50434D,\n    0x594046,\n    0x5E3E41,\n    0x653B3C,\n    0x6B3A36,\n    0x6F3833,\n    0x723731,\n    0x75362F,\n    0x73342F,\n    0x72312D,\n    0x6F2E2A,\n    0x6B2A26,\n    0x662521,\n    0x62211D,\n    0x5E1D19,\n    0x5C1B17,\n    0x601F1B,\n    0x601F1B,\n    0x601F1B,\n    0x601F1B,\n    0x601F1B,\n    0x601F1B,\n    0x601F1B,\n    0x5F201B,\n    0x5C2318,\n    0x5F291D,\n    0x673125,\n    0x6E382C,\n    0x733D31,\n    0x743E32,\n    0x733D31,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x673F35,\n    0x3D3125,\n    0x323429,\n    0x313328,\n    0x2F3126,\n    0x2C2E23,\n    0x2A2C21,\n    0x292B20,\n    0x282A1F,\n    0x2D2F24,\n    0x2B2D22,\n    0x27291E,\n    0x25271C,\n    0x26281D,\n    0x2B2D22,\n    0x303227,\n    0x35352B,\n    0x3A372E,\n    0x3D3930,\n    0x3F3B32,\n    0x423E35,\n    0x464239,\n    0x49453C,\n    0x4B473E,\n    0x4C483F,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x474539,\n    0x434337,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x94C7E6,\n    0x8ABBD9,\n    0x80ACC9,\n    0x7DA2BD,\n    0x7A9AB1,\n    0x72889D,\n    0x626F80,\n    0x585A67,\n    0x49424A,\n    0x523F43,\n    0x573D3E,\n    0x5E3B39,\n    0x643933,\n    0x683730,\n    0x6B362E,\n    0x6C352E,\n    0x6F3835,\n    0x6D3534,\n    0x6A3231,\n    0x662E2D,\n    0x612928,\n    0x5D2524,\n    0x592120,\n    0x571F1E,\n    0x551D1C,\n    0x551D1C,\n    0x551D1C,\n    0x551D1C,\n    0x551D1C,\n    0x551D1C,\n    0x551D1C,\n    0x551E1B,\n    0x5A241A,\n    0x5F291D,\n    0x673125,\n    0x6E382C,\n    0x733D31,\n    0x743E32,\n    0x733D31,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x673F35,\n    0x3D3125,\n    0x323429,\n    0x313328,\n    0x2F3126,\n    0x2C2E23,\n    0x2A2C21,\n    0x292B20,\n    0x282A1F,\n    0x2D2F24,\n    0x2A2C21,\n    0x27291E,\n    0x26281D,\n    0x292B20,\n    0x2E3025,\n    0x35372C,\n    0x3A3A30,\n    0x3F3C33,\n    0x413D34,\n    0x433F36,\n    0x454138,\n    0x47433A,\n    0x49453C,\n    0x4B473E,\n    0x4B473E,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x474539,\n    0x434337,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x93CCE9,\n    0x88C0DB,\n    0x7EB1CC,\n    0x79A7BF,\n    0x789EB3,\n    0x708D9F,\n    0x5F7583,\n    0x555F69,\n    0x424348,\n    0x4A4041,\n    0x513D3C,\n    0x583B37,\n    0x5E3931,\n    0x62372E,\n    0x65362C,\n    0x65362E,\n    0x6A3E3B,\n    0x663C3D,\n    0x63393A,\n    0x5E3435,\n    0x592F30,\n    0x552B2C,\n    0x522829,\n    0x502627,\n    0x4A2021,\n    0x4A2021,\n    0x4A2021,\n    0x4A2021,\n    0x4A2021,\n    0x4A2021,\n    0x4A2021,\n    0x4D201D,\n    0x57251C,\n    0x5F291D,\n    0x673125,\n    0x6E382C,\n    0x733D31,\n    0x743E32,\n    0x733D31,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x673F35,\n    0x3D3125,\n    0x323429,\n    0x313328,\n    0x2F3126,\n    0x2C2E23,\n    0x2A2C21,\n    0x292B20,\n    0x282A1F,\n    0x2C2E23,\n    0x2A2C21,\n    0x282A1F,\n    0x282A1F,\n    0x2C2E23,\n    0x33352A,\n    0x3A3C31,\n    0x404036,\n    0x46433A,\n    0x47433A,\n    0x47433A,\n    0x48443B,\n    0x49453C,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x474539,\n    0x434337,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x90D2EC,\n    0x85C5DE,\n    0x7BB7CF,\n    0x76ADC2,\n    0x75A4B6,\n    0x6D92A2,\n    0x5D7985,\n    0x53646C,\n    0x40484B,\n    0x494544,\n    0x4E433F,\n    0x55413A,\n    0x5B3F34,\n    0x5F3D31,\n    0x623C2F,\n    0x613C33,\n    0x634442,\n    0x604347,\n    0x5C3F43,\n    0x583B3F,\n    0x53363A,\n    0x4F3236,\n    0x4C2F33,\n    0x4A2D31,\n    0x44272B,\n    0x44272B,\n    0x44272B,\n    0x44272B,\n    0x44272B,\n    0x44272B,\n    0x44272B,\n    0x492525,\n    0x55261E,\n    0x5F291D,\n    0x673125,\n    0x6E382C,\n    0x733D31,\n    0x743E32,\n    0x733D31,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x673F35,\n    0x3D3125,\n    0x323429,\n    0x313328,\n    0x2F3126,\n    0x2C2E23,\n    0x2A2C21,\n    0x292B20,\n    0x282A1F,\n    0x2A2C21,\n    0x292B20,\n    0x292B20,\n    0x2A2C21,\n    0x303227,\n    0x383A2F,\n    0x414338,\n    0x47473D,\n    0x4C4940,\n    0x4D4940,\n    0x4C483F,\n    0x4C483F,\n    0x4B473E,\n    0x4A463D,\n    0x4A463D,\n    0x49453C,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x474539,\n    0x434337,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x8ED6EE,\n    0x84CBE1,\n    0x79BBD1,\n    0x75B2C5,\n    0x74A9B9,\n    0x6C98A5,\n    0x5A7F88,\n    0x516A6F,\n    0x425252,\n    0x4A4F4B,\n    0x514C46,\n    0x584A41,\n    0x5C493B,\n    0x614738,\n    0x654536,\n    0x62463B,\n    0x5E4A49,\n    0x58494E,\n    0x55464B,\n    0x514247,\n    0x4C3D42,\n    0x48393E,\n    0x44353A,\n    0x423338,\n    0x403136,\n    0x403136,\n    0x403136,\n    0x403136,\n    0x403136,\n    0x403136,\n    0x403136,\n    0x472F2F,\n    0x532620,\n    0x5F291D,\n    0x673125,\n    0x6E382C,\n    0x733D31,\n    0x743E32,\n    0x733D31,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x673F35,\n    0x3D3125,\n    0x323429,\n    0x313328,\n    0x2F3126,\n    0x2C2E23,\n    0x2A2C21,\n    0x292B20,\n    0x282A1F,\n    0x292B20,\n    0x292B20,\n    0x292B20,\n    0x2C2E23,\n    0x33352A,\n    0x3D3F34,\n    0x46483D,\n    0x4D4D43,\n    0x524F46,\n    0x534F46,\n    0x514D44,\n    0x4F4B42,\n    0x4D4940,\n    0x4B473E,\n    0x49453C,\n    0x48443B,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x474539,\n    0x434337,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x8CDAF0,\n    0x82CFE3,\n    0x77C0D3,\n    0x73B6C7,\n    0x72ADBB,\n    0x6A9CA7,\n    0x58838A,\n    0x4F6E71,\n    0x465A59,\n    0x4E5752,\n    0x54554D,\n    0x5B5348,\n    0x615142,\n    0x65503F,\n    0x684E3D,\n    0x654F42,\n    0x594F50,\n    0x534E55,\n    0x504B52,\n    0x4C474E,\n    0x474249,\n    0x433E45,\n    0x3F3A41,\n    0x3D383F,\n    0x413C43,\n    0x413C43,\n    0x413C43,\n    0x413C43,\n    0x413C43,\n    0x413C43,\n    0x413C43,\n    0x4B383C,\n    0x502820,\n    0x5F291D,\n    0x673125,\n    0x6E382C,\n    0x733D31,\n    0x743E32,\n    0x733D31,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x673F35,\n    0x3D3125,\n    0x323429,\n    0x313328,\n    0x2F3126,\n    0x2C2E23,\n    0x2A2C21,\n    0x292B20,\n    0x282A1F,\n    0x292B20,\n    0x282A1F,\n    0x2A2C21,\n    0x2E3025,\n    0x36382D,\n    0x404237,\n    0x4B4D42,\n    0x525248,\n    0x57544B,\n    0x57534A,\n    0x555148,\n    0x524E45,\n    0x4E4A41,\n    0x4B473E,\n    0x49453C,\n    0x48443B,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x474539,\n    0x434337,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x8BDCF1,\n    0x82D0E4,\n    0x76C1D4,\n    0x73B8C8,\n    0x71AFBC,\n    0x699DA8,\n    0x58858B,\n    0x4E7072,\n    0x48615E,\n    0x515E57,\n    0x585B52,\n    0x5F594D,\n    0x635747,\n    0x675644,\n    0x6B5442,\n    0x675549,\n    0x575151,\n    0x505058,\n    0x4D4D55,\n    0x494951,\n    0x44444C,\n    0x404048,\n    0x3C3C44,\n    0x3B3B43,\n    0x42424A,\n    0x42424A,\n    0x42424A,\n    0x42424A,\n    0x42424A,\n    0x42424A,\n    0x42424A,\n    0x4B3F41,\n    0x502721,\n    0x5F291D,\n    0x673125,\n    0x6E382C,\n    0x733D31,\n    0x743E32,\n    0x733D31,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x713B2F,\n    0x673F35,\n    0x3D3125,\n    0x323429,\n    0x313328,\n    0x2F3126,\n    0x2C2E23,\n    0x2A2C21,\n    0x292B20,\n    0x282A1F,\n    0x282A1F,\n    0x282A1F,\n    0x2A2C21,\n    0x2E3025,\n    0x37392E,\n    0x424439,\n    0x4D4F44,\n    0x55554B,\n    0x5A574E,\n    0x59554C,\n    0x57534A,\n    0x534F46,\n    0x4F4B42,\n    0x4B473E,\n    0x49453C,\n    0x47433A,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x474539,\n    0x434337,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x424439,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x404237,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x3E4035,\n    0x5B9193,\n    0x578A8D,\n    0x508386,\n    0x4D7D81,\n    0x4D7D81,\n    0x568187,\n    0x60878E,\n    0x698B94,\n    0x496A73,\n    0x4A6671,\n    0x49616D,\n    0x465967,\n    0x405361,\n    0x3C4C5B,\n    0x384857,\n    0x354552,\n    0x354A4F,\n    0x324A4C,\n    0x31494B,\n    0x2F4749,\n    0x2C4446,\n    0x2A4244,\n    0x284042,\n    0x273F41,\n    0x324A4C,\n    0x324A4C,\n    0x324A4C,\n    0x324A4C,\n    0x324A4C,\n    0x324A4C,\n    0x324A4C,\n    0x384848,\n    0x444643,\n    0x4D4844,\n    0x544D47,\n    0x595049,\n    0x5B5148,\n    0x5C4E43,\n    0x5A4A3D,\n    0x594637,\n    0x5B4432,\n    0x5E432E,\n    0x5F432D,\n    0x624229,\n    0x644227,\n    0x654226,\n    0x664124,\n    0x62422D,\n    0x49322C,\n    0x422F31,\n    0x3B2B2C,\n    0x362828,\n    0x332727,\n    0x332B29,\n    0x35302D,\n    0x353430,\n    0x2D2F2A,\n    0x272E27,\n    0x202A22,\n    0x1E2B22,\n    0x233329,\n    0x2F4036,\n    0x3C5045,\n    0x4A574D,\n    0x505245,\n    0x534F43,\n    0x514D41,\n    0x4F4B3F,\n    0x4C483C,\n    0x4A463A,\n    0x494539,\n    0x484438,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444035,\n    0x423E33,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x71A7A9,\n    0x6C9FA2,\n    0x619497,\n    0x59898D,\n    0x538387,\n    0x558086,\n    0x5A8188,\n    0x5F818A,\n    0x45666F,\n    0x47636E,\n    0x475F6B,\n    0x475A68,\n    0x435664,\n    0x425261,\n    0x40505F,\n    0x3E4E5B,\n    0x354A4F,\n    0x324A4C,\n    0x31494B,\n    0x2F4749,\n    0x2C4446,\n    0x2A4244,\n    0x284042,\n    0x273F41,\n    0x2D4547,\n    0x2D4547,\n    0x2D4547,\n    0x2D4547,\n    0x2D4547,\n    0x2D4547,\n    0x2D4547,\n    0x314345,\n    0x3B3F3E,\n    0x464241,\n    0x4D4A45,\n    0x564E4B,\n    0x59524A,\n    0x5B5148,\n    0x5B4D42,\n    0x5C4A3C,\n    0x5B4839,\n    0x5E4735,\n    0x614631,\n    0x644530,\n    0x64462C,\n    0x67452C,\n    0x674529,\n    0x644531,\n    0x48312B,\n    0x402D2F,\n    0x39292A,\n    0x332525,\n    0x302424,\n    0x302826,\n    0x312C29,\n    0x31302C,\n    0x2D2F2A,\n    0x272E27,\n    0x202A22,\n    0x1E2B22,\n    0x233329,\n    0x2F4036,\n    0x3C5045,\n    0x4A574D,\n    0x505245,\n    0x534F43,\n    0x514D41,\n    0x4F4B3F,\n    0x4C483C,\n    0x4A463A,\n    0x494539,\n    0x484438,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444035,\n    0x423E33,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x80B6B8,\n    0x7BAEB1,\n    0x6FA2A5,\n    0x649498,\n    0x58888C,\n    0x547F85,\n    0x547B82,\n    0x557780,\n    0x496A73,\n    0x4B6772,\n    0x4B636F,\n    0x4B5E6C,\n    0x475A68,\n    0x465665,\n    0x445463,\n    0x42525F,\n    0x354A4F,\n    0x324A4C,\n    0x31494B,\n    0x2F4749,\n    0x2C4446,\n    0x2A4244,\n    0x284042,\n    0x273F41,\n    0x253D3F,\n    0x253D3F,\n    0x253D3F,\n    0x253D3F,\n    0x253D3F,\n    0x253D3F,\n    0x253D3F,\n    0x293B3D,\n    0x2E383A,\n    0x393A3E,\n    0x424443,\n    0x4D4C4A,\n    0x56524F,\n    0x5B544E,\n    0x5C534C,\n    0x5E5148,\n    0x5F4F42,\n    0x614E3F,\n    0x634E3D,\n    0x664D39,\n    0x674C37,\n    0x684C36,\n    0x6A4C34,\n    0x674C3B,\n    0x45302B,\n    0x3F2C2E,\n    0x372728,\n    0x302222,\n    0x2C2020,\n    0x2B2321,\n    0x2B2623,\n    0x2B2A26,\n    0x2D2F2A,\n    0x272E27,\n    0x202A22,\n    0x1E2B22,\n    0x233329,\n    0x2F4036,\n    0x3C5045,\n    0x4A574D,\n    0x505245,\n    0x534F43,\n    0x514D41,\n    0x4F4B3F,\n    0x4C483C,\n    0x4A463A,\n    0x494539,\n    0x484438,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444035,\n    0x423E33,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x73A9AB,\n    0x70A3A6,\n    0x699C9F,\n    0x629296,\n    0x5A8A8E,\n    0x578288,\n    0x557C83,\n    0x567881,\n    0x5D7E87,\n    0x5C7883,\n    0x59717D,\n    0x536674,\n    0x4A5D6B,\n    0x435362,\n    0x3C4C5B,\n    0x394956,\n    0x354A4F,\n    0x324A4C,\n    0x31494B,\n    0x2F4749,\n    0x2C4446,\n    0x2A4244,\n    0x284042,\n    0x273F41,\n    0x1F3739,\n    0x1F3739,\n    0x1F3739,\n    0x1F3739,\n    0x1F3739,\n    0x1F3739,\n    0x1F3739,\n    0x223539,\n    0x233036,\n    0x2C353C,\n    0x383F45,\n    0x454A4E,\n    0x4E5255,\n    0x565656,\n    0x5A5653,\n    0x5D5650,\n    0x5D544D,\n    0x60534A,\n    0x635346,\n    0x655244,\n    0x655241,\n    0x685141,\n    0x68523D,\n    0x685143,\n    0x473430,\n    0x412E30,\n    0x372728,\n    0x302222,\n    0x2A1E1E,\n    0x271F1D,\n    0x27221F,\n    0x262521,\n    0x2D2F2A,\n    0x272E27,\n    0x202A22,\n    0x1E2B22,\n    0x233329,\n    0x2F4036,\n    0x3C5045,\n    0x4A574D,\n    0x505245,\n    0x534F43,\n    0x514D41,\n    0x4F4B3F,\n    0x4C483C,\n    0x4A463A,\n    0x494539,\n    0x484438,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444035,\n    0x423E33,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x508688,\n    0x54878A,\n    0x56898C,\n    0x5A8A8E,\n    0x5A8A8E,\n    0x5D888E,\n    0x5F868D,\n    0x61838C,\n    0x75969F,\n    0x728E99,\n    0x69818D,\n    0x5C6F7D,\n    0x4C5F6D,\n    0x3E4E5D,\n    0x324251,\n    0x2C3C49,\n    0x354A4F,\n    0x324A4C,\n    0x31494B,\n    0x2F4749,\n    0x2C4446,\n    0x2A4244,\n    0x284042,\n    0x273F41,\n    0x1C3436,\n    0x1C3436,\n    0x1C3436,\n    0x1C3436,\n    0x1C3436,\n    0x1C3436,\n    0x1C3436,\n    0x1E3338,\n    0x1C2E38,\n    0x253340,\n    0x303E47,\n    0x3E4852,\n    0x465157,\n    0x4D545A,\n    0x515558,\n    0x545454,\n    0x575654,\n    0x5A5551,\n    0x5D544D,\n    0x60534A,\n    0x615348,\n    0x635346,\n    0x645244,\n    0x645248,\n    0x4C3A38,\n    0x473436,\n    0x3C2C2D,\n    0x332525,\n    0x2C2020,\n    0x28201E,\n    0x27221F,\n    0x252420,\n    0x2D2F2A,\n    0x272E27,\n    0x202A22,\n    0x1E2B22,\n    0x233329,\n    0x2F4036,\n    0x3C5045,\n    0x4A574D,\n    0x505245,\n    0x534F43,\n    0x514D41,\n    0x4F4B3F,\n    0x4C483C,\n    0x4A463A,\n    0x494539,\n    0x484438,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444035,\n    0x423E33,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x376D6F,\n    0x407376,\n    0x4A7D80,\n    0x56868A,\n    0x5E8E92,\n    0x669197,\n    0x6A9198,\n    0x6D8F98,\n    0x7E9FA8,\n    0x7A96A1,\n    0x708894,\n    0x627583,\n    0x506371,\n    0x415160,\n    0x344453,\n    0x2D3D4A,\n    0x354A4F,\n    0x324A4C,\n    0x31494B,\n    0x2F4749,\n    0x2C4446,\n    0x2A4244,\n    0x284042,\n    0x273F41,\n    0x1D3537,\n    0x1D3537,\n    0x1D3537,\n    0x1D3537,\n    0x1D3537,\n    0x1D3537,\n    0x1D3537,\n    0x1D343A,\n    0x1C323F,\n    0x213647,\n    0x2C3F4E,\n    0x364856,\n    0x3E4E5B,\n    0x435059,\n    0x454F58,\n    0x464D53,\n    0x4F5356,\n    0x525252,\n    0x535250,\n    0x56514D,\n    0x58514B,\n    0x5A4F49,\n    0x5A5046,\n    0x5D4E47,\n    0x544444,\n    0x513E40,\n    0x453536,\n    0x3A2C2C,\n    0x312525,\n    0x2C2422,\n    0x2A2522,\n    0x282723,\n    0x2D2F2A,\n    0x272E27,\n    0x202A22,\n    0x1E2B22,\n    0x233329,\n    0x2F4036,\n    0x3C5045,\n    0x4A574D,\n    0x505245,\n    0x534F43,\n    0x514D41,\n    0x4F4B3F,\n    0x4C483C,\n    0x4A463A,\n    0x494539,\n    0x484438,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444035,\n    0x423E33,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x386E70,\n    0x427578,\n    0x4F8285,\n    0x5E8E92,\n    0x67979B,\n    0x6E999F,\n    0x71989F,\n    0x73959E,\n    0x73949D,\n    0x718D98,\n    0x6C8490,\n    0x637684,\n    0x576A78,\n    0x4E5E6D,\n    0x455564,\n    0x40505D,\n    0x354A4F,\n    0x324A4C,\n    0x31494B,\n    0x2F4749,\n    0x2C4446,\n    0x2A4244,\n    0x284042,\n    0x273F41,\n    0x21393B,\n    0x21393B,\n    0x21393B,\n    0x21393B,\n    0x21393B,\n    0x21393B,\n    0x21393B,\n    0x203940,\n    0x1E3847,\n    0x233C52,\n    0x2A4455,\n    0x33485B,\n    0x364C5A,\n    0x394B59,\n    0x394752,\n    0x3A444D,\n    0x454E55,\n    0x484D51,\n    0x4B4C4E,\n    0x4D4B4C,\n    0x4D4C48,\n    0x504B48,\n    0x504B45,\n    0x534947,\n    0x5F4F4F,\n    0x5A4749,\n    0x4E3E3F,\n    0x433535,\n    0x392D2D,\n    0x322A28,\n    0x2F2A27,\n    0x2C2B27,\n    0x2D2F2A,\n    0x272E27,\n    0x202A22,\n    0x1E2B22,\n    0x233329,\n    0x2F4036,\n    0x3C5045,\n    0x4A574D,\n    0x505245,\n    0x534F43,\n    0x514D41,\n    0x4F4B3F,\n    0x4C483C,\n    0x4A463A,\n    0x494539,\n    0x484438,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444035,\n    0x423E33,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x43797B,\n    0x4D8083,\n    0x5A8D90,\n    0x68989C,\n    0x6F9FA3,\n    0x739EA4,\n    0x749BA2,\n    0x74969F,\n    0x63848D,\n    0x64808B,\n    0x647C88,\n    0x627583,\n    0x5D707E,\n    0x5A6A79,\n    0x566675,\n    0x546471,\n    0x354A4F,\n    0x324A4C,\n    0x31494B,\n    0x2F4749,\n    0x2C4446,\n    0x2A4244,\n    0x284042,\n    0x273F41,\n    0x243C3E,\n    0x243C3E,\n    0x243C3E,\n    0x243C3E,\n    0x243C3E,\n    0x243C3E,\n    0x243C3E,\n    0x233C43,\n    0x223D4E,\n    0x244056,\n    0x2B465B,\n    0x30495D,\n    0x334A5C,\n    0x344756,\n    0x314351,\n    0x313F4A,\n    0x414B54,\n    0x434A50,\n    0x454A4E,\n    0x48494B,\n    0x494949,\n    0x4A4947,\n    0x4C4845,\n    0x4F4745,\n    0x645656,\n    0x614E50,\n    0x544445,\n    0x483A3A,\n    0x3D3131,\n    0x372F2D,\n    0x332E2B,\n    0x302F2B,\n    0x2D2F2A,\n    0x272E27,\n    0x202A22,\n    0x1E2B22,\n    0x233329,\n    0x2F4036,\n    0x3C5045,\n    0x4A574D,\n    0x505245,\n    0x534F43,\n    0x514D41,\n    0x4F4B3F,\n    0x4C483C,\n    0x4A463A,\n    0x494539,\n    0x484438,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x4A463A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444035,\n    0x423E33,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x4B6B7A,\n    0x496978,\n    0x496978,\n    0x4F6F7E,\n    0x5A7A89,\n    0x688897,\n    0x7393A2,\n    0x7999A8,\n    0x648493,\n    0x5C7C8B,\n    0x577786,\n    0x597988,\n    0x5E7E8D,\n    0x597988,\n    0x4B6B7A,\n    0x405C68,\n    0x3D545A,\n    0x3D5054,\n    0x394C50,\n    0x33464A,\n    0x2D4044,\n    0x273A3E,\n    0x23363A,\n    0x203337,\n    0x203337,\n    0x203337,\n    0x203337,\n    0x203337,\n    0x203337,\n    0x203337,\n    0x203337,\n    0x213337,\n    0x26353A,\n    0x28353B,\n    0x2A373D,\n    0x2C393F,\n    0x2E3B41,\n    0x313E44,\n    0x323F45,\n    0x334046,\n    0x3B484E,\n    0x3B484E,\n    0x3B484E,\n    0x3B484E,\n    0x3B484E,\n    0x3B484E,\n    0x3B484E,\n    0x3D484C,\n    0x3C4846,\n    0x3D4844,\n    0x3D4844,\n    0x3D4844,\n    0x3D4844,\n    0x3D4844,\n    0x3D4844,\n    0x3D4844,\n    0x2B3632,\n    0x27322E,\n    0x232E2A,\n    0x212C28,\n    0x26312D,\n    0x2F3A36,\n    0x3A4541,\n    0x444A46,\n    0x3F3F37,\n    0x433F36,\n    0x454138,\n    0x47433A,\n    0x49453C,\n    0x4B473E,\n    0x4D4940,\n    0x4E4A41,\n    0x454138,\n    0x454138,\n    0x454138,\n    0x454138,\n    0x454138,\n    0x454138,\n    0x454138,\n    0x474038,\n    0x4C463A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x60808F,\n    0x557584,\n    0x496978,\n    0x446473,\n    0x486877,\n    0x50707F,\n    0x567685,\n    0x587887,\n    0x648493,\n    0x5D7D8C,\n    0x567685,\n    0x577786,\n    0x5A7A89,\n    0x547483,\n    0x446473,\n    0x395561,\n    0x3A5157,\n    0x3B4E52,\n    0x374A4E,\n    0x324549,\n    0x2C3F43,\n    0x273A3E,\n    0x23363A,\n    0x213438,\n    0x213438,\n    0x213438,\n    0x213438,\n    0x213438,\n    0x213438,\n    0x213438,\n    0x213438,\n    0x223438,\n    0x27363B,\n    0x29363C,\n    0x2B383E,\n    0x2D3A40,\n    0x303D43,\n    0x323F45,\n    0x334046,\n    0x344147,\n    0x37444A,\n    0x37444A,\n    0x37444A,\n    0x37444A,\n    0x37444A,\n    0x37444A,\n    0x37444A,\n    0x394448,\n    0x3B4745,\n    0x3C4743,\n    0x3C4743,\n    0x3C4743,\n    0x3C4743,\n    0x3C4743,\n    0x3C4743,\n    0x3C4743,\n    0x3B4642,\n    0x36413D,\n    0x2F3A36,\n    0x293430,\n    0x28332F,\n    0x2C3733,\n    0x323D39,\n    0x393F3B,\n    0x3F3F37,\n    0x433F36,\n    0x454138,\n    0x47433A,\n    0x49453C,\n    0x4B473E,\n    0x4D4940,\n    0x4E4A41,\n    0x464239,\n    0x464239,\n    0x464239,\n    0x464239,\n    0x464239,\n    0x464239,\n    0x464239,\n    0x484139,\n    0x4C463A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x88A8B7,\n    0x7696A5,\n    0x628291,\n    0x567685,\n    0x537382,\n    0x50707F,\n    0x476776,\n    0x3E5E6D,\n    0x638392,\n    0x5B7B8A,\n    0x537382,\n    0x527281,\n    0x537382,\n    0x4B6B7A,\n    0x3A5A69,\n    0x2E4A56,\n    0x354C52,\n    0x374A4E,\n    0x33464A,\n    0x2F4246,\n    0x2B3E42,\n    0x26393D,\n    0x23363A,\n    0x213438,\n    0x23363A,\n    0x23363A,\n    0x23363A,\n    0x23363A,\n    0x23363A,\n    0x23363A,\n    0x23363A,\n    0x24363A,\n    0x29383D,\n    0x2B383E,\n    0x2D3A40,\n    0x2F3C42,\n    0x323F45,\n    0x344147,\n    0x354248,\n    0x364349,\n    0x323F45,\n    0x323F45,\n    0x323F45,\n    0x323F45,\n    0x323F45,\n    0x323F45,\n    0x323F45,\n    0x343F43,\n    0x394543,\n    0x3A4541,\n    0x3A4541,\n    0x3A4541,\n    0x3A4541,\n    0x3A4541,\n    0x3A4541,\n    0x3A4541,\n    0x495450,\n    0x444F4B,\n    0x3C4743,\n    0x343F3B,\n    0x2F3A36,\n    0x2D3834,\n    0x2E3935,\n    0x323834,\n    0x3F3F37,\n    0x433F36,\n    0x454138,\n    0x47433A,\n    0x49453C,\n    0x4B473E,\n    0x4D4940,\n    0x4E4A41,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x48443B,\n    0x4A433B,\n    0x4C463A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0xB7D7E6,\n    0xA9C9D8,\n    0x9BBBCA,\n    0x97B7C6,\n    0x95B5C4,\n    0x84A4B3,\n    0x638392,\n    0x486877,\n    0x5D7D8C,\n    0x557584,\n    0x4C6C7B,\n    0x4A6A79,\n    0x4A6A79,\n    0x426271,\n    0x315160,\n    0x24404C,\n    0x2F464C,\n    0x314448,\n    0x2F4246,\n    0x2C3F43,\n    0x293C40,\n    0x26393D,\n    0x24373B,\n    0x223539,\n    0x26393D,\n    0x26393D,\n    0x26393D,\n    0x26393D,\n    0x26393D,\n    0x26393D,\n    0x26393D,\n    0x27393D,\n    0x2C3B40,\n    0x2E3B41,\n    0x303D43,\n    0x323F45,\n    0x344147,\n    0x364349,\n    0x38454B,\n    0x39464C,\n    0x2E3B41,\n    0x2E3B41,\n    0x2E3B41,\n    0x2E3B41,\n    0x2E3B41,\n    0x2E3B41,\n    0x2E3B41,\n    0x303B3F,\n    0x364240,\n    0x37423E,\n    0x37423E,\n    0x37423E,\n    0x37423E,\n    0x37423E,\n    0x37423E,\n    0x37423E,\n    0x444F4B,\n    0x414C48,\n    0x3E4945,\n    0x3A4541,\n    0x37423E,\n    0x35403C,\n    0x35403C,\n    0x383E3A,\n    0x3F3F37,\n    0x433F36,\n    0x454138,\n    0x47433A,\n    0x49453C,\n    0x4B473E,\n    0x4D4940,\n    0x4E4A41,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4C453D,\n    0x4C463A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0xDCFCFF,\n    0xD2F2FF,\n    0xCEEEFD,\n    0xD6F6FF,\n    0xDAFAFF,\n    0xC1E1F0,\n    0x8DADBC,\n    0x618190,\n    0x517180,\n    0x496978,\n    0x416170,\n    0x416170,\n    0x436372,\n    0x3C5C6B,\n    0x2B4B5A,\n    0x203C48,\n    0x283F45,\n    0x2B3E42,\n    0x2A3D41,\n    0x283B3F,\n    0x273A3E,\n    0x25383C,\n    0x24373B,\n    0x24373B,\n    0x283B3F,\n    0x283B3F,\n    0x283B3F,\n    0x283B3F,\n    0x283B3F,\n    0x283B3F,\n    0x283B3F,\n    0x293B3F,\n    0x2F3E43,\n    0x313E44,\n    0x323F45,\n    0x354248,\n    0x37444A,\n    0x39464C,\n    0x3B484E,\n    0x3C494F,\n    0x2E3B41,\n    0x2E3B41,\n    0x2E3B41,\n    0x2E3B41,\n    0x2E3B41,\n    0x2E3B41,\n    0x2E3B41,\n    0x303B3F,\n    0x333F3D,\n    0x343F3B,\n    0x343F3B,\n    0x343F3B,\n    0x343F3B,\n    0x343F3B,\n    0x343F3B,\n    0x343F3B,\n    0x313C38,\n    0x333E3A,\n    0x37423E,\n    0x3B4642,\n    0x3E4945,\n    0x3F4A46,\n    0x404B47,\n    0x434945,\n    0x3F3F37,\n    0x433F36,\n    0x454138,\n    0x47433A,\n    0x49453C,\n    0x4B473E,\n    0x4D4940,\n    0x4E4A41,\n    0x4D4940,\n    0x4D4940,\n    0x4D4940,\n    0x4D4940,\n    0x4D4940,\n    0x4D4940,\n    0x4D4940,\n    0x4F4840,\n    0x4C463A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0xE7FFFF,\n    0xD5F5FF,\n    0xC8E8F7,\n    0xCEEEFD,\n    0xD7F7FF,\n    0xC2E2F1,\n    0x8DADBC,\n    0x5E7E8D,\n    0x40606F,\n    0x395968,\n    0x345463,\n    0x375766,\n    0x3D5D6C,\n    0x395968,\n    0x2B4B5A,\n    0x213D49,\n    0x22393F,\n    0x25383C,\n    0x25383C,\n    0x25383C,\n    0x25383C,\n    0x25383C,\n    0x25383C,\n    0x25383C,\n    0x2B3E42,\n    0x2B3E42,\n    0x2B3E42,\n    0x2B3E42,\n    0x2B3E42,\n    0x2B3E42,\n    0x2B3E42,\n    0x2C3E42,\n    0x324146,\n    0x334046,\n    0x354248,\n    0x37444A,\n    0x3A474D,\n    0x3C494F,\n    0x3D4A50,\n    0x3E4B51,\n    0x323F45,\n    0x323F45,\n    0x323F45,\n    0x323F45,\n    0x323F45,\n    0x323F45,\n    0x323F45,\n    0x343F43,\n    0x303C3A,\n    0x313C38,\n    0x313C38,\n    0x313C38,\n    0x313C38,\n    0x313C38,\n    0x313C38,\n    0x313C38,\n    0x242F2B,\n    0x293430,\n    0x313C38,\n    0x394440,\n    0x3E4945,\n    0x404B47,\n    0x3F4A46,\n    0x414743,\n    0x3F3F37,\n    0x433F36,\n    0x454138,\n    0x47433A,\n    0x49453C,\n    0x4B473E,\n    0x4D4940,\n    0x4E4A41,\n    0x504C43,\n    0x504C43,\n    0x504C43,\n    0x504C43,\n    0x504C43,\n    0x504C43,\n    0x504C43,\n    0x524B43,\n    0x4C463A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0xDFFFFF,\n    0xB5D5E4,\n    0x88A8B7,\n    0x7A9AA9,\n    0x82A2B1,\n    0x7A9AA9,\n    0x567685,\n    0x325261,\n    0x2F4F5E,\n    0x2A4A59,\n    0x284857,\n    0x2F4F5E,\n    0x395968,\n    0x395968,\n    0x2E4E5D,\n    0x26424E,\n    0x1D343A,\n    0x213438,\n    0x213438,\n    0x223539,\n    0x23363A,\n    0x24373B,\n    0x25383C,\n    0x25383C,\n    0x2D4044,\n    0x2D4044,\n    0x2D4044,\n    0x2D4044,\n    0x2D4044,\n    0x2D4044,\n    0x2D4044,\n    0x2E4044,\n    0x344348,\n    0x354248,\n    0x37444A,\n    0x39464C,\n    0x3C494F,\n    0x3E4B51,\n    0x3F4C52,\n    0x404D53,\n    0x37444A,\n    0x37444A,\n    0x37444A,\n    0x37444A,\n    0x37444A,\n    0x37444A,\n    0x37444A,\n    0x394448,\n    0x2E3A38,\n    0x2F3A36,\n    0x2F3A36,\n    0x2F3A36,\n    0x2F3A36,\n    0x2F3A36,\n    0x2F3A36,\n    0x2F3A36,\n    0x26312D,\n    0x2B3632,\n    0x333E3A,\n    0x38433F,\n    0x394440,\n    0x36413D,\n    0x303B37,\n    0x2F3531,\n    0x3F3F37,\n    0x433F36,\n    0x454138,\n    0x47433A,\n    0x49453C,\n    0x4B473E,\n    0x4D4940,\n    0x4E4A41,\n    0x524E45,\n    0x524E45,\n    0x524E45,\n    0x524E45,\n    0x524E45,\n    0x524E45,\n    0x524E45,\n    0x544D45,\n    0x4C463A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0xD2F2FF,\n    0x92B2C1,\n    0x486877,\n    0x264655,\n    0x2B4B5A,\n    0x30505F,\n    0x1D3D4C,\n    0x042433,\n    0x254554,\n    0x214150,\n    0x214150,\n    0x2B4B5A,\n    0x375766,\n    0x3A5A69,\n    0x315160,\n    0x294551,\n    0x1B3238,\n    0x1E3135,\n    0x203337,\n    0x213438,\n    0x23363A,\n    0x24373B,\n    0x25383C,\n    0x26393D,\n    0x2E4145,\n    0x2E4145,\n    0x2E4145,\n    0x2E4145,\n    0x2E4145,\n    0x2E4145,\n    0x2E4145,\n    0x2F4145,\n    0x354449,\n    0x364349,\n    0x38454B,\n    0x3A474D,\n    0x3D4A50,\n    0x3F4C52,\n    0x404D53,\n    0x414E54,\n    0x3B484E,\n    0x3B484E,\n    0x3B484E,\n    0x3B484E,\n    0x3B484E,\n    0x3B484E,\n    0x3B484E,\n    0x3D484C,\n    0x2D3937,\n    0x2E3935,\n    0x2E3935,\n    0x2E3935,\n    0x2E3935,\n    0x2E3935,\n    0x2E3935,\n    0x2E3935,\n    0x2F3A36,\n    0x323D39,\n    0x37423E,\n    0x38433F,\n    0x343F3B,\n    0x2B3632,\n    0x202B27,\n    0x1C221E,\n    0x3F3F37,\n    0x433F36,\n    0x454138,\n    0x47433A,\n    0x49453C,\n    0x4B473E,\n    0x4D4940,\n    0x4E4A41,\n    0x534F46,\n    0x534F46,\n    0x534F46,\n    0x534F46,\n    0x534F46,\n    0x534F46,\n    0x534F46,\n    0x554E46,\n    0x4C463A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x4D453A,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x484438,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x464236,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0xD7F3FF,\n    0x96B2D9,\n    0x4B678C,\n    0x294668,\n    0x304D6D,\n    0x395773,\n    0x2B4963,\n    0x153449,\n    0x2B4A5C,\n    0x2C4C59,\n    0x2E4E59,\n    0x305158,\n    0x325358,\n    0x345658,\n    0x365859,\n    0x39585B,\n    0x2B4449,\n    0x2B424A,\n    0x2A4149,\n    0x273E46,\n    0x253C44,\n    0x233A42,\n    0x213840,\n    0x20373F,\n    0x283F47,\n    0x283F47,\n    0x283F47,\n    0x283F47,\n    0x283F47,\n    0x283F47,\n    0x283F47,\n    0x2A3E45,\n    0x334849,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x394B4B,\n    0x364646,\n    0x364445,\n    0x344243,\n    0x324041,\n    0x303E3F,\n    0x2E3C3D,\n    0x2C3A3B,\n    0x2B393A,\n    0x2F3D3E,\n    0x2F3D3E,\n    0x2D3B3C,\n    0x2B393A,\n    0x283637,\n    0x263435,\n    0x253334,\n    0x263232,\n    0x373D3D,\n    0x393D3C,\n    0x3C403F,\n    0x404443,\n    0x444847,\n    0x474B4A,\n    0x4A4E4D,\n    0x4C504F,\n    0x464A49,\n    0x464A49,\n    0x484C4B,\n    0x4A4E4D,\n    0x4D5150,\n    0x4F5352,\n    0x505453,\n    0x535552,\n    0x55584F,\n    0x57594E,\n    0x585A4F,\n    0x5A5C51,\n    0x5D5F54,\n    0x5F6156,\n    0x616358,\n    0x616358,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4D4D43,\n    0x504A3E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0xE3FFFF,\n    0xA5C1E8,\n    0x5C789D,\n    0x3A5779,\n    0x3E5B7B,\n    0x466480,\n    0x385670,\n    0x244358,\n    0x304F61,\n    0x31515E,\n    0x33535E,\n    0x35565D,\n    0x37585D,\n    0x395B5D,\n    0x3B5D5E,\n    0x3E5D60,\n    0x2C454A,\n    0x2C434B,\n    0x2B424A,\n    0x294048,\n    0x263D45,\n    0x243B43,\n    0x223941,\n    0x213840,\n    0x294048,\n    0x294048,\n    0x294048,\n    0x294048,\n    0x294048,\n    0x294048,\n    0x294048,\n    0x2B3F46,\n    0x334849,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x394B4B,\n    0x374747,\n    0x374546,\n    0x354344,\n    0x334142,\n    0x313F40,\n    0x2F3D3E,\n    0x2D3B3C,\n    0x2C3A3B,\n    0x303E3F,\n    0x303E3F,\n    0x2E3C3D,\n    0x2C3A3B,\n    0x293738,\n    0x273536,\n    0x263435,\n    0x273333,\n    0x333939,\n    0x363A39,\n    0x383C3B,\n    0x3B3F3E,\n    0x3E4241,\n    0x414544,\n    0x444847,\n    0x454948,\n    0x434746,\n    0x444847,\n    0x464A49,\n    0x484C4B,\n    0x4A4E4D,\n    0x4D5150,\n    0x4E5251,\n    0x515350,\n    0x53564D,\n    0x54564B,\n    0x56584D,\n    0x585A4F,\n    0x5B5D52,\n    0x5D5F54,\n    0x5E6055,\n    0x5F6156,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4D4D43,\n    0x504A3E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0xE7FFFF,\n    0xB6D2F9,\n    0x738FB4,\n    0x506D8F,\n    0x506D8D,\n    0x54728E,\n    0x486680,\n    0x36556A,\n    0x385769,\n    0x395966,\n    0x3A5A65,\n    0x3C5D64,\n    0x3F6065,\n    0x416365,\n    0x426465,\n    0x456467,\n    0x2E474C,\n    0x2E454D,\n    0x2D444C,\n    0x2B424A,\n    0x283F47,\n    0x263D45,\n    0x243B43,\n    0x233A42,\n    0x2B424A,\n    0x2B424A,\n    0x2B424A,\n    0x2B424A,\n    0x2B424A,\n    0x2B424A,\n    0x2B424A,\n    0x2D4148,\n    0x334849,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x394B4B,\n    0x394949,\n    0x394748,\n    0x374546,\n    0x354344,\n    0x334142,\n    0x313F40,\n    0x2F3D3E,\n    0x2E3C3D,\n    0x324041,\n    0x324041,\n    0x303E3F,\n    0x2E3C3D,\n    0x2B393A,\n    0x293738,\n    0x283637,\n    0x293535,\n    0x2F3535,\n    0x303433,\n    0x323635,\n    0x343837,\n    0x363A39,\n    0x383C3B,\n    0x3A3E3D,\n    0x3B3F3E,\n    0x3F4342,\n    0x404443,\n    0x424645,\n    0x444847,\n    0x464A49,\n    0x494D4C,\n    0x4A4E4D,\n    0x4D4F4C,\n    0x4F5249,\n    0x505247,\n    0x525449,\n    0x54564B,\n    0x57594E,\n    0x595B50,\n    0x5A5C51,\n    0x5B5D52,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4D4D43,\n    0x504A3E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0xE7FFFF,\n    0xBEDAFF,\n    0x829EC3,\n    0x5F7C9E,\n    0x597696,\n    0x597793,\n    0x4E6C86,\n    0x405F74,\n    0x3E5D6F,\n    0x3F5F6C,\n    0x41616C,\n    0x43646B,\n    0x45666B,\n    0x47696B,\n    0x496B6C,\n    0x4C6B6E,\n    0x314A4F,\n    0x314850,\n    0x2F464E,\n    0x2D444C,\n    0x2B424A,\n    0x294048,\n    0x273E46,\n    0x263D45,\n    0x2E454D,\n    0x2E454D,\n    0x2E454D,\n    0x2E454D,\n    0x2E454D,\n    0x2E454D,\n    0x2E454D,\n    0x30444B,\n    0x334849,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x394B4B,\n    0x3C4C4C,\n    0x3C4A4B,\n    0x3A4849,\n    0x384647,\n    0x364445,\n    0x334142,\n    0x324041,\n    0x313F40,\n    0x354344,\n    0x344243,\n    0x334142,\n    0x303E3F,\n    0x2E3C3D,\n    0x2C3A3B,\n    0x2A3839,\n    0x2B3737,\n    0x2C3232,\n    0x2D3130,\n    0x2D3130,\n    0x2E3231,\n    0x2F3332,\n    0x303433,\n    0x303433,\n    0x313534,\n    0x3A3E3D,\n    0x3B3F3E,\n    0x3D4140,\n    0x3F4342,\n    0x414544,\n    0x434746,\n    0x454948,\n    0x484A47,\n    0x494C43,\n    0x4B4D42,\n    0x4D4F44,\n    0x4F5146,\n    0x515348,\n    0x54564B,\n    0x55574C,\n    0x56584D,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4D4D43,\n    0x504A3E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0xE6FFFF,\n    0xBEDAFF,\n    0x8AA6CB,\n    0x6784A6,\n    0x5A7797,\n    0x55738F,\n    0x4C6A84,\n    0x426176,\n    0x416072,\n    0x42626F,\n    0x44646F,\n    0x46676E,\n    0x48696E,\n    0x4A6C6E,\n    0x4C6E6F,\n    0x4F6E71,\n    0x344D52,\n    0x344B53,\n    0x324951,\n    0x30474F,\n    0x2E454D,\n    0x2B424A,\n    0x2A4149,\n    0x294048,\n    0x314850,\n    0x314850,\n    0x314850,\n    0x314850,\n    0x314850,\n    0x314850,\n    0x314850,\n    0x33474E,\n    0x334849,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x394B4B,\n    0x3E4E4E,\n    0x3F4D4E,\n    0x3D4B4C,\n    0x3B494A,\n    0x384647,\n    0x364445,\n    0x354344,\n    0x344243,\n    0x384647,\n    0x374546,\n    0x354344,\n    0x334142,\n    0x313F40,\n    0x2F3D3E,\n    0x2D3B3C,\n    0x2E3A3A,\n    0x2D3333,\n    0x2D3130,\n    0x2D3130,\n    0x2C302F,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2A2E2D,\n    0x2A2E2D,\n    0x353938,\n    0x353938,\n    0x373B3A,\n    0x393D3C,\n    0x3C403F,\n    0x3E4241,\n    0x3F4342,\n    0x424441,\n    0x44473E,\n    0x46483D,\n    0x47493E,\n    0x494B40,\n    0x4C4E43,\n    0x4E5045,\n    0x505247,\n    0x505247,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4D4D43,\n    0x504A3E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0xDFFBFF,\n    0xBFDBFF,\n    0x92AED3,\n    0x6E8BAD,\n    0x5B7898,\n    0x52708C,\n    0x4A6882,\n    0x446378,\n    0x405F71,\n    0x41616E,\n    0x42626D,\n    0x44656C,\n    0x47686D,\n    0x496B6D,\n    0x4B6D6E,\n    0x4D6C6F,\n    0x364F54,\n    0x364D55,\n    0x354C54,\n    0x334A52,\n    0x30474F,\n    0x2E454D,\n    0x2C434B,\n    0x2C434B,\n    0x334A52,\n    0x334A52,\n    0x334A52,\n    0x334A52,\n    0x334A52,\n    0x334A52,\n    0x334A52,\n    0x354950,\n    0x334849,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x394B4B,\n    0x415151,\n    0x414F50,\n    0x3F4D4E,\n    0x3D4B4C,\n    0x3B494A,\n    0x394748,\n    0x374546,\n    0x364445,\n    0x3B494A,\n    0x3A4849,\n    0x384647,\n    0x364445,\n    0x334142,\n    0x313F40,\n    0x303E3F,\n    0x313D3D,\n    0x323838,\n    0x323635,\n    0x303433,\n    0x2E3231,\n    0x2C302F,\n    0x2A2E2D,\n    0x282C2B,\n    0x272B2A,\n    0x2F3332,\n    0x303433,\n    0x323635,\n    0x343837,\n    0x363A39,\n    0x393D3C,\n    0x3A3E3D,\n    0x3D3F3C,\n    0x3E4138,\n    0x404237,\n    0x424439,\n    0x44463B,\n    0x46483D,\n    0x494B40,\n    0x4A4C41,\n    0x4B4D42,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4D4D43,\n    0x504A3E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0xDFFBFF,\n    0xC5E1FF,\n    0x9DB9DE,\n    0x7996B8,\n    0x617E9E,\n    0x55738F,\n    0x4E6C86,\n    0x4B6A7F,\n    0x3C5B6D,\n    0x3D5D6A,\n    0x3F5F6A,\n    0x416269,\n    0x436469,\n    0x456769,\n    0x47696A,\n    0x4A696C,\n    0x385156,\n    0x384F57,\n    0x374E56,\n    0x354C54,\n    0x324951,\n    0x30474F,\n    0x2E454D,\n    0x2E454D,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x374B52,\n    0x334849,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x394B4B,\n    0x435353,\n    0x435152,\n    0x414F50,\n    0x3F4D4E,\n    0x3D4B4C,\n    0x3B494A,\n    0x394748,\n    0x384647,\n    0x3D4B4C,\n    0x3C4A4B,\n    0x3A4849,\n    0x384647,\n    0x354344,\n    0x334142,\n    0x324041,\n    0x333F3F,\n    0x383E3E,\n    0x383C3B,\n    0x353938,\n    0x323635,\n    0x2F3332,\n    0x2C302F,\n    0x2A2E2D,\n    0x282C2B,\n    0x2B2F2E,\n    0x2C302F,\n    0x2E3231,\n    0x303433,\n    0x323635,\n    0x353938,\n    0x363A39,\n    0x393B38,\n    0x3A3D34,\n    0x3C3E33,\n    0x3E4035,\n    0x404237,\n    0x424439,\n    0x45473C,\n    0x46483D,\n    0x47493E,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4D4D43,\n    0x504A3E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0xE3FFFF,\n    0xCBE7FF,\n    0xA7C3E8,\n    0x83A0C2,\n    0x6885A5,\n    0x5A7894,\n    0x54728C,\n    0x527186,\n    0x39586A,\n    0x3A5A67,\n    0x3C5C67,\n    0x3E5F66,\n    0x406166,\n    0x426466,\n    0x446667,\n    0x476669,\n    0x395257,\n    0x395058,\n    0x384F57,\n    0x364D55,\n    0x334A52,\n    0x314850,\n    0x2F464E,\n    0x2F464E,\n    0x364D55,\n    0x364D55,\n    0x364D55,\n    0x364D55,\n    0x364D55,\n    0x364D55,\n    0x364D55,\n    0x384C53,\n    0x334849,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x344847,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x394B4B,\n    0x445454,\n    0x445253,\n    0x435152,\n    0x404E4F,\n    0x3E4C4D,\n    0x3C4A4B,\n    0x3A4849,\n    0x394748,\n    0x3E4C4D,\n    0x3D4B4C,\n    0x3B494A,\n    0x394748,\n    0x374546,\n    0x344243,\n    0x334142,\n    0x344040,\n    0x3C4242,\n    0x3C403F,\n    0x393D3C,\n    0x353938,\n    0x323635,\n    0x2E3231,\n    0x2B2F2E,\n    0x2A2E2D,\n    0x292D2C,\n    0x2A2E2D,\n    0x2C302F,\n    0x2E3231,\n    0x303433,\n    0x323635,\n    0x343837,\n    0x373936,\n    0x383B32,\n    0x3A3C31,\n    0x3C3E33,\n    0x3E4035,\n    0x404237,\n    0x424439,\n    0x44463B,\n    0x45473C,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4C4E43,\n    0x4D4D43,\n    0x504A3E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x51493E,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4F473C,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x4B4338,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x444034,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x423E32,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x413D31,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0xE0FFFF,\n    0xC2E7F9,\n    0x98BDCF,\n    0x759AAC,\n    0x608597,\n    0x557A8C,\n    0x4D7284,\n    0x476C7E,\n    0x3C6173,\n    0x3A5F71,\n    0x395E70,\n    0x395E70,\n    0x3D6274,\n    0x44697B,\n    0x4B7082,\n    0x537483,\n    0x415C67,\n    0x40575F,\n    0x3A5159,\n    0x344B53,\n    0x324951,\n    0x334A52,\n    0x364D55,\n    0x384F57,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x374B52,\n    0x394E4F,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x384C4B,\n    0x394C4A,\n    0x334340,\n    0x33423D,\n    0x31403B,\n    0x2F3E39,\n    0x2C3B36,\n    0x2A3934,\n    0x293833,\n    0x283732,\n    0x2C3B36,\n    0x2D3C37,\n    0x2E3D38,\n    0x2F3E39,\n    0x31403B,\n    0x32413C,\n    0x34433E,\n    0x36423E,\n    0x2D3331,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x434746,\n    0x444847,\n    0x454948,\n    0x484C4B,\n    0x4A4E4D,\n    0x4C504F,\n    0x4E5251,\n    0x515350,\n    0x43463D,\n    0x45473C,\n    0x46483D,\n    0x484A3F,\n    0x4B4D42,\n    0x4D4F44,\n    0x4F5146,\n    0x505247,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4B4B41,\n    0x4B483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x413D34,\n    0x48443B,\n    0x47433A,\n    0x464239,\n    0x444037,\n    0x413D34,\n    0x3F3B32,\n    0x3D3930,\n    0x3C382F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0xDFFFFF,\n    0xC4E9FB,\n    0x9DC2D4,\n    0x7A9FB1,\n    0x63889A,\n    0x567B8D,\n    0x4E7385,\n    0x4A6F81,\n    0x3E6375,\n    0x3C6173,\n    0x395E70,\n    0x395E70,\n    0x3C6173,\n    0x43687A,\n    0x4A6F81,\n    0x517281,\n    0x415C67,\n    0x40575F,\n    0x3A5159,\n    0x344B53,\n    0x324951,\n    0x334A52,\n    0x364D55,\n    0x384F57,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x374B52,\n    0x394E4F,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x394D4C,\n    0x394D4C,\n    0x394D4C,\n    0x394D4C,\n    0x394D4C,\n    0x394D4C,\n    0x394D4C,\n    0x3A4D4B,\n    0x354542,\n    0x35443F,\n    0x33423D,\n    0x31403B,\n    0x2F3E39,\n    0x2C3B36,\n    0x2B3A35,\n    0x2A3934,\n    0x2B3A35,\n    0x2B3A35,\n    0x2C3B36,\n    0x2D3C37,\n    0x2E3D38,\n    0x2F3E39,\n    0x2F3E39,\n    0x323E3A,\n    0x2D3331,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x3D4140,\n    0x3E4241,\n    0x3F4342,\n    0x424645,\n    0x444847,\n    0x464A49,\n    0x484C4B,\n    0x4B4D4A,\n    0x45483F,\n    0x46483D,\n    0x484A3F,\n    0x4A4C41,\n    0x4D4F44,\n    0x4F5146,\n    0x505247,\n    0x515348,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4B4B41,\n    0x4B483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x423E35,\n    0x48443B,\n    0x47433A,\n    0x464239,\n    0x444037,\n    0x413D34,\n    0x3F3B32,\n    0x3D3930,\n    0x3C382F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0xDCFFFF,\n    0xC8EDFF,\n    0xA6CBDD,\n    0x83A8BA,\n    0x678C9E,\n    0x577C8E,\n    0x507587,\n    0x4F7486,\n    0x406577,\n    0x3E6375,\n    0x3B6072,\n    0x3A5F71,\n    0x3C6173,\n    0x416678,\n    0x476C7E,\n    0x4F707F,\n    0x415C67,\n    0x40575F,\n    0x3A5159,\n    0x344B53,\n    0x324951,\n    0x334A52,\n    0x364D55,\n    0x384F57,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x374B52,\n    0x394E4F,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3B4F4E,\n    0x3B4F4E,\n    0x3B4F4E,\n    0x3B4F4E,\n    0x3B4F4E,\n    0x3B4F4E,\n    0x3B4F4E,\n    0x3C4F4D,\n    0x394946,\n    0x394843,\n    0x374641,\n    0x35443F,\n    0x33423D,\n    0x303F3A,\n    0x2F3E39,\n    0x2E3D38,\n    0x2A3934,\n    0x2A3934,\n    0x2A3934,\n    0x2A3934,\n    0x2A3934,\n    0x2A3934,\n    0x2A3934,\n    0x2C3834,\n    0x2D3331,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x333736,\n    0x343837,\n    0x363A39,\n    0x383C3B,\n    0x3A3E3D,\n    0x3C403F,\n    0x3E4241,\n    0x414340,\n    0x464940,\n    0x484A3F,\n    0x4A4C41,\n    0x4C4E43,\n    0x4E5045,\n    0x505247,\n    0x525449,\n    0x53554A,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4B4B41,\n    0x4B483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x444037,\n    0x444037,\n    0x444037,\n    0x444037,\n    0x444037,\n    0x444037,\n    0x444037,\n    0x444037,\n    0x48443B,\n    0x47433A,\n    0x464239,\n    0x444037,\n    0x413D34,\n    0x3F3B32,\n    0x3D3930,\n    0x3C382F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0xDAFFFF,\n    0xCDF2FF,\n    0xB2D7E9,\n    0x8FB4C6,\n    0x6C91A3,\n    0x587D8F,\n    0x53788A,\n    0x557A8C,\n    0x44697B,\n    0x416678,\n    0x3D6274,\n    0x3A5F71,\n    0x3B6072,\n    0x3F6476,\n    0x44697B,\n    0x4B6C7B,\n    0x415C67,\n    0x40575F,\n    0x3A5159,\n    0x344B53,\n    0x324951,\n    0x334A52,\n    0x364D55,\n    0x384F57,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x374B52,\n    0x394E4F,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3F5250,\n    0x3E4E4B,\n    0x3E4D48,\n    0x3C4B46,\n    0x3A4944,\n    0x384742,\n    0x364540,\n    0x34433E,\n    0x33423D,\n    0x2C3B36,\n    0x2C3B36,\n    0x2B3A35,\n    0x293833,\n    0x283732,\n    0x263530,\n    0x25342F,\n    0x27332F,\n    0x2D3331,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2A2E2D,\n    0x2B2F2E,\n    0x2D3130,\n    0x2F3332,\n    0x313534,\n    0x333736,\n    0x353938,\n    0x383A37,\n    0x45483F,\n    0x47493E,\n    0x484A3F,\n    0x4A4C41,\n    0x4D4F44,\n    0x4F5146,\n    0x515348,\n    0x525449,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4B4B41,\n    0x4B483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x47433A,\n    0x47433A,\n    0x47433A,\n    0x47433A,\n    0x47433A,\n    0x47433A,\n    0x47433A,\n    0x47433A,\n    0x48443B,\n    0x47433A,\n    0x464239,\n    0x444037,\n    0x413D34,\n    0x3F3B32,\n    0x3D3930,\n    0x3C382F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0xD7FCFF,\n    0xD2F7FF,\n    0xBFE4F6,\n    0x9BC0D2,\n    0x7297A9,\n    0x597E90,\n    0x567B8D,\n    0x5C8193,\n    0x486D7F,\n    0x44697B,\n    0x3F6476,\n    0x3B6072,\n    0x3A5F71,\n    0x3D6274,\n    0x416678,\n    0x476877,\n    0x415C67,\n    0x40575F,\n    0x3A5159,\n    0x344B53,\n    0x324951,\n    0x334A52,\n    0x364D55,\n    0x384F57,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x374B52,\n    0x394E4F,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x415554,\n    0x415554,\n    0x415554,\n    0x415554,\n    0x415554,\n    0x415554,\n    0x415554,\n    0x425553,\n    0x445451,\n    0x44534E,\n    0x42514C,\n    0x404F4A,\n    0x3E4D48,\n    0x3B4A45,\n    0x3A4944,\n    0x394843,\n    0x33423D,\n    0x32413C,\n    0x303F3A,\n    0x2D3C37,\n    0x2A3934,\n    0x273631,\n    0x25342F,\n    0x25312D,\n    0x2D3331,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x242827,\n    0x252928,\n    0x272B2A,\n    0x292D2C,\n    0x2C302F,\n    0x2E3231,\n    0x2F3332,\n    0x323431,\n    0x3F4239,\n    0x414338,\n    0x43453A,\n    0x45473C,\n    0x47493E,\n    0x494B40,\n    0x4B4D42,\n    0x4C4E43,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4B4B41,\n    0x4B483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x49453C,\n    0x49453C,\n    0x49453C,\n    0x49453C,\n    0x49453C,\n    0x49453C,\n    0x49453C,\n    0x49453C,\n    0x48443B,\n    0x47433A,\n    0x464239,\n    0x444037,\n    0x413D34,\n    0x3F3B32,\n    0x3D3930,\n    0x3C382F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0xD4F9FF,\n    0xD7FCFF,\n    0xCBF0FF,\n    0xA7CCDE,\n    0x789DAF,\n    0x5A7F91,\n    0x587D8F,\n    0x628799,\n    0x4C7183,\n    0x476C7E,\n    0x416678,\n    0x3C6173,\n    0x3A5F71,\n    0x3B6072,\n    0x3E6375,\n    0x436473,\n    0x415C67,\n    0x40575F,\n    0x3A5159,\n    0x344B53,\n    0x324951,\n    0x334A52,\n    0x364D55,\n    0x384F57,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x374B52,\n    0x394E4F,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x435756,\n    0x435756,\n    0x435756,\n    0x435756,\n    0x435756,\n    0x435756,\n    0x435756,\n    0x445755,\n    0x495956,\n    0x495853,\n    0x475651,\n    0x45544F,\n    0x43524D,\n    0x41504B,\n    0x3F4E49,\n    0x3E4D48,\n    0x3D4C47,\n    0x3C4B46,\n    0x384742,\n    0x34433E,\n    0x303F3A,\n    0x2B3A35,\n    0x283732,\n    0x283430,\n    0x2D3331,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x232726,\n    0x242827,\n    0x262A29,\n    0x282C2B,\n    0x2A2E2D,\n    0x2C302F,\n    0x2E3231,\n    0x313330,\n    0x363930,\n    0x383A2F,\n    0x3A3C31,\n    0x3C3E33,\n    0x3E4035,\n    0x404237,\n    0x424439,\n    0x43453A,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4B4B41,\n    0x4B483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x48443B,\n    0x47433A,\n    0x464239,\n    0x444037,\n    0x413D34,\n    0x3F3B32,\n    0x3D3930,\n    0x3C382F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0xD2F7FF,\n    0xDBFFFF,\n    0xD5FAFF,\n    0xB0D5E7,\n    0x7CA1B3,\n    0x5B8092,\n    0x5B8092,\n    0x678C9E,\n    0x4E7385,\n    0x4A6F81,\n    0x43687A,\n    0x3C6173,\n    0x395E70,\n    0x395E70,\n    0x3C6173,\n    0x416271,\n    0x415C67,\n    0x40575F,\n    0x3A5159,\n    0x344B53,\n    0x324951,\n    0x334A52,\n    0x364D55,\n    0x384F57,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x374B52,\n    0x394E4F,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x455958,\n    0x455958,\n    0x455958,\n    0x455958,\n    0x455958,\n    0x455958,\n    0x455958,\n    0x465957,\n    0x4D5D5A,\n    0x4D5C57,\n    0x4B5A55,\n    0x495853,\n    0x475651,\n    0x45544F,\n    0x43524D,\n    0x42514C,\n    0x485752,\n    0x465550,\n    0x42514C,\n    0x3C4B46,\n    0x374641,\n    0x31403B,\n    0x2D3C37,\n    0x2D3935,\n    0x2D3331,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x252928,\n    0x262A29,\n    0x272B2A,\n    0x292D2C,\n    0x2C302F,\n    0x2E3231,\n    0x303433,\n    0x323431,\n    0x2C2F26,\n    0x2E3025,\n    0x303227,\n    0x323429,\n    0x34362B,\n    0x37392E,\n    0x383A2F,\n    0x393B30,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4B4B41,\n    0x4B483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4E4A41,\n    0x4E4A41,\n    0x4E4A41,\n    0x4E4A41,\n    0x4E4A41,\n    0x4E4A41,\n    0x4E4A41,\n    0x4E4A41,\n    0x48443B,\n    0x47433A,\n    0x464239,\n    0x444037,\n    0x413D34,\n    0x3F3B32,\n    0x3D3930,\n    0x3C382F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0xD1F6FF,\n    0xDDFFFF,\n    0xDAFFFF,\n    0xB5DAEC,\n    0x7FA4B6,\n    0x5C8193,\n    0x5C8193,\n    0x6A8FA1,\n    0x507587,\n    0x4B7082,\n    0x44697B,\n    0x3D6274,\n    0x395E70,\n    0x395E70,\n    0x3A5F71,\n    0x3F606F,\n    0x415C67,\n    0x40575F,\n    0x3A5159,\n    0x344B53,\n    0x324951,\n    0x334A52,\n    0x364D55,\n    0x384F57,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x354C54,\n    0x374B52,\n    0x394E4F,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3A4E4D,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3C504F,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x3E5251,\n    0x465A59,\n    0x465A59,\n    0x465A59,\n    0x465A59,\n    0x465A59,\n    0x465A59,\n    0x465A59,\n    0x475A58,\n    0x4F5F5C,\n    0x4F5E59,\n    0x4D5C57,\n    0x4B5A55,\n    0x495853,\n    0x475651,\n    0x45544F,\n    0x44534E,\n    0x4E5D58,\n    0x4C5B56,\n    0x475651,\n    0x42514C,\n    0x3B4A45,\n    0x364540,\n    0x31403B,\n    0x313D39,\n    0x2D3331,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x2E3231,\n    0x262A29,\n    0x272B2A,\n    0x292D2C,\n    0x2B2F2E,\n    0x2E3231,\n    0x303433,\n    0x313534,\n    0x343633,\n    0x262920,\n    0x282A1F,\n    0x2A2C21,\n    0x2C2E23,\n    0x2E3025,\n    0x313328,\n    0x323429,\n    0x33352A,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4A4C41,\n    0x4B4B41,\n    0x4B483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4C483F,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4A463D,\n    0x4F4B42,\n    0x4F4B42,\n    0x4F4B42,\n    0x4F4B42,\n    0x4F4B42,\n    0x4F4B42,\n    0x4F4B42,\n    0x4F4B42,\n    0x48443B,\n    0x47433A,\n    0x464239,\n    0x444037,\n    0x413D34,\n    0x3F3B32,\n    0x3D3930,\n    0x3C382F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3F3B2F,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0x3D392D,\n    0xC5EAFC,\n    0xCEF3FF,\n    0xCBF0FF,\n    0xAED3E5,\n    0x83A8BA,\n    0x658A9C,\n    0x608597,\n    0x678C9E,\n    0x4A6F81,\n    0x466B7D,\n    0x406577,\n    0x3A5F71,\n    0x385D6F,\n    0x395E70,\n    0x3C6173,\n    0x416271,\n    0x3D5863,\n    0x3F565E,\n    0x3E555D,\n    0x3C535B,\n    0x395058,\n    0x374E56,\n    0x364D55,\n    0x354C54,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E54,\n    0x395155,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D59,\n    0x465F59,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x3F5950,\n    0x3F5950,\n    0x3F5950,\n    0x3F5950,\n    0x3F5950,\n    0x3F5950,\n    0x3F5950,\n    0x455650,\n    0x3E4241,\n    0x423E3F,\n    0x3D393A,\n    0x373334,\n    0x312D2E,\n    0x2B2728,\n    0x272324,\n    0x252122,\n    0x292526,\n    0x2A2627,\n    0x2B2728,\n    0x2C2829,\n    0x2E2A2B,\n    0x2F2B2C,\n    0x302C2D,\n    0x2F2D2E,\n    0x2D2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2E3231,\n    0x2E3231,\n    0x303433,\n    0x323635,\n    0x353938,\n    0x373B3A,\n    0x383C3B,\n    0x393D3C,\n    0x3E433D,\n    0x3F443E,\n    0x414640,\n    0x434842,\n    0x454A44,\n    0x474C46,\n    0x494E48,\n    0x4A4F49,\n    0x434842,\n    0x434842,\n    0x424741,\n    0x40453F,\n    0x3F443E,\n    0x3D423C,\n    0x3C413B,\n    0x3E403B,\n    0x454742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x353631,\n    0x353631,\n    0xC5EAFC,\n    0xD1F6FF,\n    0xD2F7FF,\n    0xB8DDEF,\n    0x8DB2C4,\n    0x6B90A2,\n    0x608597,\n    0x64899B,\n    0x4A6F81,\n    0x466B7D,\n    0x406577,\n    0x3A5F71,\n    0x385D6F,\n    0x395E70,\n    0x3C6173,\n    0x416271,\n    0x3D5863,\n    0x3F565E,\n    0x3E555D,\n    0x3C535B,\n    0x395058,\n    0x374E56,\n    0x364D55,\n    0x354C54,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E54,\n    0x395155,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D59,\n    0x465F59,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x405A51,\n    0x405A51,\n    0x405A51,\n    0x405A51,\n    0x405A51,\n    0x405A51,\n    0x405A51,\n    0x445751,\n    0x434947,\n    0x454545,\n    0x414141,\n    0x3B3B3B,\n    0x363636,\n    0x303030,\n    0x2C2C2C,\n    0x2A2A2A,\n    0x272727,\n    0x272727,\n    0x282828,\n    0x292929,\n    0x2A2A2A,\n    0x2B2B2B,\n    0x2C2C2C,\n    0x2C2C2C,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2D3130,\n    0x2D3130,\n    0x2F3332,\n    0x313534,\n    0x343837,\n    0x363A39,\n    0x373B3A,\n    0x383C3B,\n    0x3C413B,\n    0x3D423C,\n    0x3E433D,\n    0x414640,\n    0x434842,\n    0x454A44,\n    0x474C46,\n    0x484D47,\n    0x454A44,\n    0x444943,\n    0x444943,\n    0x434842,\n    0x424741,\n    0x414640,\n    0x40453F,\n    0x42443F,\n    0x454742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x363732,\n    0x363732,\n    0x363732,\n    0x363732,\n    0x363732,\n    0x363732,\n    0x363732,\n    0x363732,\n    0xC5EAFC,\n    0xD5FAFF,\n    0xDCFFFF,\n    0xC6EBFD,\n    0x9ABFD1,\n    0x7297A9,\n    0x608597,\n    0x5E8395,\n    0x4A6F81,\n    0x466B7D,\n    0x406577,\n    0x3A5F71,\n    0x385D6F,\n    0x395E70,\n    0x3C6173,\n    0x416271,\n    0x3D5863,\n    0x3F565E,\n    0x3E555D,\n    0x3C535B,\n    0x395058,\n    0x374E56,\n    0x364D55,\n    0x354C54,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E54,\n    0x395155,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D59,\n    0x465F59,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x425C53,\n    0x425C53,\n    0x425C53,\n    0x425C53,\n    0x425C53,\n    0x425C53,\n    0x425C53,\n    0x465953,\n    0x495450,\n    0x4B4F4E,\n    0x484C4B,\n    0x434746,\n    0x3F4342,\n    0x3B3F3E,\n    0x373B3A,\n    0x363A39,\n    0x272B2A,\n    0x272B2A,\n    0x272B2A,\n    0x272B2A,\n    0x272B2A,\n    0x272B2A,\n    0x272B2A,\n    0x272B2A,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2D3130,\n    0x2F3332,\n    0x323635,\n    0x343837,\n    0x353938,\n    0x363A39,\n    0x383D37,\n    0x393E38,\n    0x3A3F39,\n    0x3D423C,\n    0x3F443E,\n    0x414640,\n    0x434842,\n    0x444943,\n    0x464B45,\n    0x464B45,\n    0x464B45,\n    0x464B45,\n    0x464B45,\n    0x464B45,\n    0x464B45,\n    0x484A45,\n    0x454742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x383934,\n    0x383934,\n    0x383934,\n    0x383934,\n    0x383934,\n    0x383934,\n    0x383934,\n    0x383934,\n    0xC7ECFE,\n    0xDAFFFF,\n    0xE3FFFF,\n    0xD1F6FF,\n    0xA3C8DA,\n    0x769BAD,\n    0x5E8395,\n    0x597E90,\n    0x4A6F81,\n    0x466B7D,\n    0x406577,\n    0x3A5F71,\n    0x385D6F,\n    0x395E70,\n    0x3C6173,\n    0x416271,\n    0x3D5863,\n    0x3F565E,\n    0x3E555D,\n    0x3C535B,\n    0x395058,\n    0x374E56,\n    0x364D55,\n    0x354C54,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E54,\n    0x395155,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D59,\n    0x465F59,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x445E55,\n    0x445E55,\n    0x445E55,\n    0x445E55,\n    0x445E55,\n    0x445E55,\n    0x445E55,\n    0x475C55,\n    0x4D5E58,\n    0x4E5A56,\n    0x4C5854,\n    0x495551,\n    0x46524E,\n    0x434F4B,\n    0x414D49,\n    0x404C48,\n    0x2A3632,\n    0x293531,\n    0x283430,\n    0x27332F,\n    0x25312D,\n    0x24302C,\n    0x222E2A,\n    0x232E2A,\n    0x2A302E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x282C2B,\n    0x292D2C,\n    0x2A2E2D,\n    0x2D3130,\n    0x2F3332,\n    0x313534,\n    0x333736,\n    0x343837,\n    0x333832,\n    0x343933,\n    0x353A34,\n    0x373C36,\n    0x3A3F39,\n    0x3C413B,\n    0x3E433D,\n    0x3E433D,\n    0x434842,\n    0x444943,\n    0x454A44,\n    0x464B45,\n    0x484D47,\n    0x494E48,\n    0x4B504A,\n    0x4D4F4A,\n    0x454742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x3B3C37,\n    0x3B3C37,\n    0x3B3C37,\n    0x3B3C37,\n    0x3B3C37,\n    0x3B3C37,\n    0x3B3C37,\n    0x3B3C37,\n    0xCBF0FF,\n    0xDDFFFF,\n    0xE3FFFF,\n    0xD2F7FF,\n    0xA2C7D9,\n    0x7499AB,\n    0x5B8092,\n    0x557A8C,\n    0x4A6F81,\n    0x466B7D,\n    0x406577,\n    0x3A5F71,\n    0x385D6F,\n    0x395E70,\n    0x3C6173,\n    0x416271,\n    0x3D5863,\n    0x3F565E,\n    0x3E555D,\n    0x3C535B,\n    0x395058,\n    0x374E56,\n    0x364D55,\n    0x354C54,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E54,\n    0x395155,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D59,\n    0x465F59,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x476158,\n    0x476158,\n    0x476158,\n    0x476158,\n    0x476158,\n    0x476158,\n    0x476158,\n    0x496058,\n    0x4E635C,\n    0x4F625C,\n    0x4E615B,\n    0x4C5F59,\n    0x4B5E58,\n    0x495C56,\n    0x485B55,\n    0x475A54,\n    0x31443E,\n    0x30433D,\n    0x2E413B,\n    0x2B3E38,\n    0x283B35,\n    0x253832,\n    0x233630,\n    0x24332E,\n    0x28312E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x252928,\n    0x262A29,\n    0x282C2B,\n    0x2A2E2D,\n    0x2C302F,\n    0x2E3231,\n    0x303433,\n    0x313534,\n    0x2D322C,\n    0x2E332D,\n    0x30352F,\n    0x323731,\n    0x343933,\n    0x363B35,\n    0x383D37,\n    0x393E38,\n    0x3D423C,\n    0x3E433D,\n    0x40453F,\n    0x434842,\n    0x464B45,\n    0x494E48,\n    0x4B504A,\n    0x4E504B,\n    0x454742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x3E3F3A,\n    0x3E3F3A,\n    0x3E3F3A,\n    0x3E3F3A,\n    0x3E3F3A,\n    0x3E3F3A,\n    0x3E3F3A,\n    0x3E3F3A,\n    0xD0F5FF,\n    0xDFFFFF,\n    0xE3FFFF,\n    0xC9EEFF,\n    0x98BDCF,\n    0x6C91A3,\n    0x577C8E,\n    0x53788A,\n    0x4A6F81,\n    0x466B7D,\n    0x406577,\n    0x3A5F71,\n    0x385D6F,\n    0x395E70,\n    0x3C6173,\n    0x416271,\n    0x3D5863,\n    0x3F565E,\n    0x3E555D,\n    0x3C535B,\n    0x395058,\n    0x374E56,\n    0x364D55,\n    0x354C54,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E54,\n    0x395155,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D59,\n    0x465F59,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x4A645B,\n    0x4A645B,\n    0x4A645B,\n    0x4A645B,\n    0x4A645B,\n    0x4A645B,\n    0x4A645B,\n    0x4A645B,\n    0x4B665D,\n    0x4A655C,\n    0x4A655C,\n    0x4A655C,\n    0x4A655C,\n    0x4A655C,\n    0x4A655C,\n    0x4A655C,\n    0x3C574E,\n    0x3A554C,\n    0x375249,\n    0x324D44,\n    0x2E4940,\n    0x2A453C,\n    0x264138,\n    0x293E37,\n    0x27322E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x222625,\n    0x232726,\n    0x252928,\n    0x272B2A,\n    0x2A2E2D,\n    0x2C302F,\n    0x2D3130,\n    0x2E3231,\n    0x282D27,\n    0x292E28,\n    0x2A2F29,\n    0x2D322C,\n    0x2F342E,\n    0x313630,\n    0x333832,\n    0x343933,\n    0x323731,\n    0x343933,\n    0x373C36,\n    0x3C413B,\n    0x40453F,\n    0x444943,\n    0x484D47,\n    0x4B4D48,\n    0x454742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x41423D,\n    0x41423D,\n    0x41423D,\n    0x41423D,\n    0x41423D,\n    0x41423D,\n    0x41423D,\n    0x41423D,\n    0xD6FBFF,\n    0xDFFFFF,\n    0xDBFFFF,\n    0xBBE0F2,\n    0x89AEC0,\n    0x618698,\n    0x527789,\n    0x53788A,\n    0x4A6F81,\n    0x466B7D,\n    0x406577,\n    0x3A5F71,\n    0x385D6F,\n    0x395E70,\n    0x3C6173,\n    0x416271,\n    0x3D5863,\n    0x3F565E,\n    0x3E555D,\n    0x3C535B,\n    0x395058,\n    0x374E56,\n    0x364D55,\n    0x354C54,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E54,\n    0x395155,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D59,\n    0x465F59,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x4C665D,\n    0x4C665D,\n    0x4C665D,\n    0x4C665D,\n    0x4C665D,\n    0x4C665D,\n    0x4C665D,\n    0x4B665D,\n    0x46645A,\n    0x46665B,\n    0x46665B,\n    0x47675C,\n    0x48685D,\n    0x49695E,\n    0x4A6A5F,\n    0x4A6A5F,\n    0x47675C,\n    0x45655A,\n    0x416156,\n    0x3B5B50,\n    0x36564B,\n    0x315146,\n    0x2D4D42,\n    0x2E483F,\n    0x27322E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x202423,\n    0x212524,\n    0x232726,\n    0x252928,\n    0x282C2B,\n    0x2A2E2D,\n    0x2B2F2E,\n    0x2C302F,\n    0x242923,\n    0x252A24,\n    0x262B25,\n    0x292E28,\n    0x2B302A,\n    0x2D322C,\n    0x2F342E,\n    0x30352F,\n    0x282D27,\n    0x2A2F29,\n    0x2E332D,\n    0x333832,\n    0x393E38,\n    0x3E433D,\n    0x424741,\n    0x474944,\n    0x454742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0x43443F,\n    0xD9FEFF,\n    0xDFFFFF,\n    0xD6FBFF,\n    0xB2D7E9,\n    0x7FA4B6,\n    0x5A7F91,\n    0x4F7486,\n    0x54798B,\n    0x4A6F81,\n    0x466B7D,\n    0x406577,\n    0x3A5F71,\n    0x385D6F,\n    0x395E70,\n    0x3C6173,\n    0x416271,\n    0x3D5863,\n    0x3F565E,\n    0x3E555D,\n    0x3C535B,\n    0x395058,\n    0x374E56,\n    0x364D55,\n    0x354C54,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E56,\n    0x374E54,\n    0x395155,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x395153,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x3C5456,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x405956,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D5A,\n    0x445D59,\n    0x465F59,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x466057,\n    0x4D675E,\n    0x4D675E,\n    0x4D675E,\n    0x4D675E,\n    0x4D675E,\n    0x4D675E,\n    0x4D675E,\n    0x4C675E,\n    0x426358,\n    0x416559,\n    0x42665A,\n    0x43675B,\n    0x45695D,\n    0x466A5E,\n    0x476B5F,\n    0x486C60,\n    0x4D7165,\n    0x4A6E62,\n    0x466A5E,\n    0x406458,\n    0x3A5E52,\n    0x34584C,\n    0x2F5347,\n    0x334E45,\n    0x26322E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x2B2F2E,\n    0x1F2322,\n    0x202423,\n    0x222625,\n    0x242827,\n    0x262A29,\n    0x292D2C,\n    0x2A2E2D,\n    0x2B2F2E,\n    0x222721,\n    0x232822,\n    0x242923,\n    0x262B25,\n    0x292E28,\n    0x2B302A,\n    0x2D322C,\n    0x2D322C,\n    0x222721,\n    0x242923,\n    0x282D27,\n    0x2E332D,\n    0x343933,\n    0x3A3F39,\n    0x3F443E,\n    0x434540,\n    0x454742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x464742,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x42433E,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x40413C,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x444540,\n    0x96D4F9,\n    0x90CEF3,\n    0x85C1E5,\n    0x77B2D4,\n    0x679FC0,\n    0x598EAD,\n    0x4F829F,\n    0x4C7B95,\n    0x3D6A81,\n    0x3F687C,\n    0x3F6578,\n    0x3F6373,\n    0x3E5F6E,\n    0x3D5D6A,\n    0x3E5C67,\n    0x3E5A65,\n    0x3F5761,\n    0x3F565E,\n    0x3E555D,\n    0x3C535B,\n    0x395058,\n    0x374E56,\n    0x364D55,\n    0x354C54,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395056,\n    0x3B5357,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3D5758,\n    0x3F5C58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476660,\n    0x4B6A62,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x446459,\n    0x446459,\n    0x446459,\n    0x446459,\n    0x446459,\n    0x446459,\n    0x446459,\n    0x456359,\n    0x3A5149,\n    0x384D46,\n    0x354842,\n    0x31423C,\n    0x2C3B36,\n    0x293430,\n    0x282E2C,\n    0x282A29,\n    0x303030,\n    0x332F30,\n    0x352C2F,\n    0x362A2E,\n    0x35292D,\n    0x38272D,\n    0x37262C,\n    0x34282C,\n    0x262425,\n    0x232726,\n    0x242827,\n    0x262A29,\n    0x272B2A,\n    0x292D2C,\n    0x2A2E2D,\n    0x2A2E2D,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x3B3F3E,\n    0x3C403F,\n    0x3E4241,\n    0x404443,\n    0x424645,\n    0x454948,\n    0x464A49,\n    0x474B4A,\n    0x3C403F,\n    0x3D4140,\n    0x3F4342,\n    0x414544,\n    0x434746,\n    0x454948,\n    0x474B4A,\n    0x484C4B,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x90CEF3,\n    0x8AC8ED,\n    0x81BDE1,\n    0x73AED0,\n    0x659DBE,\n    0x588DAC,\n    0x4F829F,\n    0x4B7A94,\n    0x3D6A81,\n    0x3F687C,\n    0x3F6578,\n    0x3F6373,\n    0x3E5F6E,\n    0x3D5D6A,\n    0x3E5C67,\n    0x3E5A65,\n    0x3F5761,\n    0x3F565E,\n    0x3E555D,\n    0x3C535B,\n    0x395058,\n    0x374E56,\n    0x364D55,\n    0x354C54,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395056,\n    0x3B5357,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3D5758,\n    0x3F5C58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476660,\n    0x4B6A62,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x45655A,\n    0x45655A,\n    0x45655A,\n    0x45655A,\n    0x45655A,\n    0x45655A,\n    0x45655A,\n    0x46645A,\n    0x3D574E,\n    0x3D544C,\n    0x3A4F48,\n    0x364943,\n    0x32433D,\n    0x303C38,\n    0x2D3834,\n    0x2E3432,\n    0x303231,\n    0x312F30,\n    0x322E2F,\n    0x342B2E,\n    0x34292D,\n    0x33272B,\n    0x34252A,\n    0x31262A,\n    0x242424,\n    0x212524,\n    0x222625,\n    0x232726,\n    0x242827,\n    0x252928,\n    0x262A29,\n    0x262A29,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x353938,\n    0x363A39,\n    0x383C3B,\n    0x3A3E3D,\n    0x3C403F,\n    0x3F4342,\n    0x404443,\n    0x414544,\n    0x3A3E3D,\n    0x3B3F3E,\n    0x3D4140,\n    0x3F4342,\n    0x414544,\n    0x434746,\n    0x454948,\n    0x464A49,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x84C2E7,\n    0x7FBDE2,\n    0x77B3D7,\n    0x6CA7C9,\n    0x6098B9,\n    0x558AA9,\n    0x4D809D,\n    0x4B7A94,\n    0x3D6A81,\n    0x3F687C,\n    0x3F6578,\n    0x3F6373,\n    0x3E5F6E,\n    0x3D5D6A,\n    0x3E5C67,\n    0x3E5A65,\n    0x3F5761,\n    0x3F565E,\n    0x3E555D,\n    0x3C535B,\n    0x395058,\n    0x374E56,\n    0x364D55,\n    0x354C54,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395056,\n    0x3B5357,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3D5758,\n    0x3F5C58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476660,\n    0x4B6A62,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x47675C,\n    0x47675C,\n    0x47675C,\n    0x47675C,\n    0x47675C,\n    0x47675C,\n    0x47675C,\n    0x47675C,\n    0x436157,\n    0x415F55,\n    0x405B52,\n    0x3D574E,\n    0x3A5149,\n    0x384B45,\n    0x374842,\n    0x384440,\n    0x2E3734,\n    0x303433,\n    0x313131,\n    0x322E2F,\n    0x2F2B2C,\n    0x30272A,\n    0x2E2528,\n    0x2B2527,\n    0x232323,\n    0x202423,\n    0x202423,\n    0x202423,\n    0x202423,\n    0x202423,\n    0x202423,\n    0x202423,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x2C302F,\n    0x2D3130,\n    0x2E3231,\n    0x303433,\n    0x333736,\n    0x353938,\n    0x373B3A,\n    0x383C3B,\n    0x363A39,\n    0x373B3A,\n    0x393D3C,\n    0x3B3F3E,\n    0x3D4140,\n    0x3F4342,\n    0x414544,\n    0x424645,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x75B3D8,\n    0x71AFD4,\n    0x6BA7CB,\n    0x629DBF,\n    0x5991B2,\n    0x5186A5,\n    0x4C7F9C,\n    0x4A7993,\n    0x3D6A81,\n    0x3F687C,\n    0x3F6578,\n    0x3F6373,\n    0x3E5F6E,\n    0x3D5D6A,\n    0x3E5C67,\n    0x3E5A65,\n    0x3F5761,\n    0x3F565E,\n    0x3E555D,\n    0x3C535B,\n    0x395058,\n    0x374E56,\n    0x364D55,\n    0x354C54,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395056,\n    0x3B5357,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3D5758,\n    0x3F5C58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476660,\n    0x4B6A62,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4A6A5F,\n    0x4A6A5F,\n    0x4A6A5F,\n    0x4A6A5F,\n    0x4A6A5F,\n    0x4A6A5F,\n    0x4A6A5F,\n    0x4A6A5F,\n    0x476B5F,\n    0x466A5E,\n    0x46675C,\n    0x446459,\n    0x426056,\n    0x425C53,\n    0x425951,\n    0x42554F,\n    0x31403B,\n    0x333E3A,\n    0x313A37,\n    0x313534,\n    0x2F3130,\n    0x2C2C2C,\n    0x2A2829,\n    0x282828,\n    0x252726,\n    0x222625,\n    0x212524,\n    0x1F2322,\n    0x1E2221,\n    0x1C201F,\n    0x1B1F1E,\n    0x1B1F1E,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x232726,\n    0x242827,\n    0x252928,\n    0x272B2A,\n    0x2A2E2D,\n    0x2C302F,\n    0x2D3130,\n    0x2E3231,\n    0x313534,\n    0x323635,\n    0x333736,\n    0x363A39,\n    0x383C3B,\n    0x3A3E3D,\n    0x3C403F,\n    0x3D4140,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x65A3C8,\n    0x62A0C5,\n    0x5F9BBF,\n    0x5893B5,\n    0x528AAB,\n    0x4D82A1,\n    0x4A7D9A,\n    0x4A7993,\n    0x3D6A81,\n    0x3F687C,\n    0x3F6578,\n    0x3F6373,\n    0x3E5F6E,\n    0x3D5D6A,\n    0x3E5C67,\n    0x3E5A65,\n    0x3F5761,\n    0x3F565E,\n    0x3E555D,\n    0x3C535B,\n    0x395058,\n    0x374E56,\n    0x364D55,\n    0x354C54,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395056,\n    0x3B5357,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3D5758,\n    0x3F5C58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476660,\n    0x4B6A62,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4D6D62,\n    0x4D6D62,\n    0x4D6D62,\n    0x4D6D62,\n    0x4D6D62,\n    0x4D6D62,\n    0x4D6D62,\n    0x4C6D62,\n    0x487264,\n    0x467263,\n    0x467062,\n    0x466F61,\n    0x466C5F,\n    0x48695E,\n    0x47675C,\n    0x4A655C,\n    0x395048,\n    0x394C46,\n    0x374842,\n    0x35413D,\n    0x303B37,\n    0x2C3532,\n    0x2A302E,\n    0x282E2C,\n    0x292D2C,\n    0x282C2B,\n    0x262A29,\n    0x232726,\n    0x202423,\n    0x1D2120,\n    0x1B1F1E,\n    0x1A1E1D,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x1D2120,\n    0x1E2221,\n    0x202423,\n    0x222625,\n    0x242827,\n    0x262A29,\n    0x282C2B,\n    0x292D2C,\n    0x2B2F2E,\n    0x2C302F,\n    0x2E3231,\n    0x303433,\n    0x323635,\n    0x343837,\n    0x363A39,\n    0x373B3A,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x5694B9,\n    0x5492B7,\n    0x538FB3,\n    0x4F8AAC,\n    0x4C84A5,\n    0x4A7F9E,\n    0x487B98,\n    0x497892,\n    0x3D6A81,\n    0x3F687C,\n    0x3F6578,\n    0x3F6373,\n    0x3E5F6E,\n    0x3D5D6A,\n    0x3E5C67,\n    0x3E5A65,\n    0x3F5761,\n    0x3F565E,\n    0x3E555D,\n    0x3C535B,\n    0x395058,\n    0x374E56,\n    0x364D55,\n    0x354C54,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395056,\n    0x3B5357,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3D5758,\n    0x3F5C58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476660,\n    0x4B6A62,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4F6F64,\n    0x4F6F64,\n    0x4F6F64,\n    0x4F6F64,\n    0x4F6F64,\n    0x4F6F64,\n    0x4F6F64,\n    0x4C7064,\n    0x447464,\n    0x427564,\n    0x427564,\n    0x457464,\n    0x457464,\n    0x487264,\n    0x4A7063,\n    0x4D6E63,\n    0x436157,\n    0x445E55,\n    0x415850,\n    0x3C4F49,\n    0x374842,\n    0x32413C,\n    0x2F3B37,\n    0x2D3834,\n    0x323836,\n    0x323635,\n    0x2F3332,\n    0x2A2E2D,\n    0x262A29,\n    0x212524,\n    0x1E2221,\n    0x1D2120,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x1C201F,\n    0x1D2120,\n    0x1E2221,\n    0x202423,\n    0x232726,\n    0x252928,\n    0x272B2A,\n    0x272B2A,\n    0x262A29,\n    0x272B2A,\n    0x282C2B,\n    0x2B2F2E,\n    0x2D3130,\n    0x2F3332,\n    0x313534,\n    0x323635,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x4A88AD,\n    0x4987AC,\n    0x4985A9,\n    0x4883A5,\n    0x477FA0,\n    0x477C9B,\n    0x477A97,\n    0x497892,\n    0x3D6A81,\n    0x3F687C,\n    0x3F6578,\n    0x3F6373,\n    0x3E5F6E,\n    0x3D5D6A,\n    0x3E5C67,\n    0x3E5A65,\n    0x3F5761,\n    0x3F565E,\n    0x3E555D,\n    0x3C535B,\n    0x395058,\n    0x374E56,\n    0x364D55,\n    0x354C54,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395056,\n    0x3B5357,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3D5758,\n    0x3F5C58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476660,\n    0x4B6A62,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x517166,\n    0x517166,\n    0x517166,\n    0x517166,\n    0x517166,\n    0x517166,\n    0x517166,\n    0x4D7366,\n    0x407362,\n    0x3C7562,\n    0x3F7663,\n    0x417664,\n    0x437665,\n    0x477666,\n    0x497566,\n    0x4C7567,\n    0x4D7165,\n    0x4D6D62,\n    0x49675D,\n    0x445E55,\n    0x3E554D,\n    0x384D46,\n    0x334640,\n    0x33423D,\n    0x3B4441,\n    0x3C403F,\n    0x383C3B,\n    0x323635,\n    0x2D3130,\n    0x272B2A,\n    0x232726,\n    0x212524,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x1D2120,\n    0x1E2221,\n    0x202423,\n    0x222625,\n    0x242827,\n    0x262A29,\n    0x282C2B,\n    0x292D2C,\n    0x222625,\n    0x232726,\n    0x242827,\n    0x272B2A,\n    0x292D2C,\n    0x2B2F2E,\n    0x2D3130,\n    0x2E3231,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x4482A7,\n    0x4482A7,\n    0x4480A4,\n    0x447FA1,\n    0x457D9E,\n    0x457A99,\n    0x467996,\n    0x487791,\n    0x3D6A81,\n    0x3F687C,\n    0x3F6578,\n    0x3F6373,\n    0x3E5F6E,\n    0x3D5D6A,\n    0x3E5C67,\n    0x3E5A65,\n    0x3F5761,\n    0x3F565E,\n    0x3E555D,\n    0x3C535B,\n    0x395058,\n    0x374E56,\n    0x364D55,\n    0x354C54,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395058,\n    0x395056,\n    0x3B5357,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3B5355,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3E5658,\n    0x3D5758,\n    0x3F5C58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x3E5D58,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x42615C,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476661,\n    0x476660,\n    0x4B6A62,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x4B6B60,\n    0x527267,\n    0x527267,\n    0x527267,\n    0x527267,\n    0x527267,\n    0x527267,\n    0x527267,\n    0x4E7467,\n    0x3C7360,\n    0x397460,\n    0x3A7561,\n    0x3F7663,\n    0x407764,\n    0x447766,\n    0x487767,\n    0x4B7567,\n    0x537C6E,\n    0x53776B,\n    0x507065,\n    0x4B665D,\n    0x435D54,\n    0x3D544C,\n    0x384D46,\n    0x384943,\n    0x414A47,\n    0x424645,\n    0x3D4140,\n    0x383C3B,\n    0x313534,\n    0x2C302F,\n    0x272B2A,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x252928,\n    0x1F2322,\n    0x202423,\n    0x222625,\n    0x242827,\n    0x262A29,\n    0x282C2B,\n    0x2A2E2D,\n    0x2B2F2E,\n    0x202423,\n    0x212524,\n    0x222625,\n    0x242827,\n    0x272B2A,\n    0x292D2C,\n    0x2B2F2E,\n    0x2C302F,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x3A3F39,\n    0x4A7EA3,\n    0x497DA2,\n    0x497B9C,\n    0x48799A,\n    0x487795,\n    0x487491,\n    0x48728B,\n    0x4A7087,\n    0x45687E,\n    0x47667A,\n    0x476474,\n    0x476170,\n    0x475F6B,\n    0x465C69,\n    0x465A63,\n    0x455962,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3A5358,\n    0x3B575A,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B64,\n    0x4C7066,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4D7368,\n    0x4B736A,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x436C64,\n    0x436C64,\n    0x436C64,\n    0x436C64,\n    0x436C64,\n    0x436C64,\n    0x436C64,\n    0x466B64,\n    0x3A5753,\n    0x3B5451,\n    0x384E4C,\n    0x344847,\n    0x2E4040,\n    0x2C3A3B,\n    0x293436,\n    0x293134,\n    0x202328,\n    0x242329,\n    0x27242B,\n    0x2D262E,\n    0x322831,\n    0x362A34,\n    0x392C36,\n    0x382E36,\n    0x252527,\n    0x232726,\n    0x242827,\n    0x262A29,\n    0x272B2A,\n    0x292D2C,\n    0x2A2E2D,\n    0x2A2E2D,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212526,\n    0x2C3033,\n    0x2C2F34,\n    0x2C2F34,\n    0x2C2F34,\n    0x2C2F34,\n    0x2C2F34,\n    0x2C2F34,\n    0x2C2F34,\n    0x3B3E43,\n    0x3B3E43,\n    0x3B3E43,\n    0x3B3E43,\n    0x3B3E43,\n    0x3B3E43,\n    0x3B3E43,\n    0x3B3E43,\n    0x497DA2,\n    0x487CA1,\n    0x487A9B,\n    0x477899,\n    0x477694,\n    0x46728F,\n    0x47718A,\n    0x496F86,\n    0x44677D,\n    0x466579,\n    0x466373,\n    0x46606F,\n    0x465E6A,\n    0x455B68,\n    0x455962,\n    0x445861,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3A5358,\n    0x3B575A,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B64,\n    0x4C7066,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4D7368,\n    0x4B736A,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x446D65,\n    0x446D65,\n    0x446D65,\n    0x446D65,\n    0x446D65,\n    0x446D65,\n    0x446D65,\n    0x476C65,\n    0x3E5E59,\n    0x405A57,\n    0x3C5653,\n    0x394F4D,\n    0x344A48,\n    0x314343,\n    0x303E3F,\n    0x303A3C,\n    0x242C2F,\n    0x282B30,\n    0x2B2A30,\n    0x2E2930,\n    0x2E2930,\n    0x312730,\n    0x312730,\n    0x2F282F,\n    0x242426,\n    0x212524,\n    0x222625,\n    0x232726,\n    0x242827,\n    0x252928,\n    0x262A29,\n    0x262A29,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212526,\n    0x2B2F32,\n    0x2B2E33,\n    0x2B2E33,\n    0x2B2E33,\n    0x2B2E33,\n    0x2B2E33,\n    0x2B2E33,\n    0x2B2E33,\n    0x383B40,\n    0x383B40,\n    0x383B40,\n    0x383B40,\n    0x383B40,\n    0x383B40,\n    0x383B40,\n    0x383B40,\n    0x477BA0,\n    0x467A9F,\n    0x467899,\n    0x457697,\n    0x457492,\n    0x44708D,\n    0x456F88,\n    0x476D84,\n    0x42657B,\n    0x446377,\n    0x446171,\n    0x445E6D,\n    0x445C68,\n    0x435966,\n    0x435760,\n    0x42565F,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3A5358,\n    0x3B575A,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B64,\n    0x4C7066,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4D7368,\n    0x4B736A,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x476F67,\n    0x446962,\n    0x456560,\n    0x42625D,\n    0x3F5C58,\n    0x3D5754,\n    0x3C5250,\n    0x394D4C,\n    0x3B4B4B,\n    0x2F3A3C,\n    0x30383B,\n    0x2F3438,\n    0x2E2F34,\n    0x2B2A30,\n    0x29262D,\n    0x28232A,\n    0x242227,\n    0x222325,\n    0x202423,\n    0x202423,\n    0x202423,\n    0x202423,\n    0x202423,\n    0x202423,\n    0x202423,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212526,\n    0x292D30,\n    0x292C31,\n    0x292C31,\n    0x292C31,\n    0x292C31,\n    0x292C31,\n    0x292C31,\n    0x292C31,\n    0x34373C,\n    0x34373C,\n    0x34373C,\n    0x34373C,\n    0x34373C,\n    0x34373C,\n    0x34373C,\n    0x34373C,\n    0x44789D,\n    0x43779C,\n    0x437596,\n    0x427394,\n    0x42718F,\n    0x426E8B,\n    0x426C85,\n    0x446A81,\n    0x3F6278,\n    0x416074,\n    0x425F6F,\n    0x425C6B,\n    0x415965,\n    0x405663,\n    0x40545D,\n    0x40545D,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3A5358,\n    0x3B575A,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B64,\n    0x4C7066,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4D7368,\n    0x4B736A,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x49726A,\n    0x487169,\n    0x466E66,\n    0x466B64,\n    0x436660,\n    0x44635E,\n    0x445E5B,\n    0x465C5A,\n    0x394D4C,\n    0x394949,\n    0x374244,\n    0x323A3D,\n    0x2A3235,\n    0x26292E,\n    0x212429,\n    0x202125,\n    0x232728,\n    0x222625,\n    0x212524,\n    0x1F2322,\n    0x1E2221,\n    0x1C201F,\n    0x1B1F1E,\n    0x1B1F1E,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212526,\n    0x262A2D,\n    0x26292E,\n    0x26292E,\n    0x26292E,\n    0x26292E,\n    0x26292E,\n    0x26292E,\n    0x26292E,\n    0x2F3237,\n    0x2F3237,\n    0x2F3237,\n    0x2F3237,\n    0x2F3237,\n    0x2F3237,\n    0x2F3237,\n    0x2F3237,\n    0x41759A,\n    0x407499,\n    0x417394,\n    0x407192,\n    0x3F6E8C,\n    0x3F6B88,\n    0x3F6982,\n    0x41677E,\n    0x3C5F75,\n    0x3F5E72,\n    0x3F5C6C,\n    0x3F5968,\n    0x3E5662,\n    0x3D5360,\n    0x3E525B,\n    0x3D515A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3A5358,\n    0x3B575A,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B64,\n    0x4C7066,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4D7368,\n    0x4B736A,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4B746C,\n    0x4B746C,\n    0x4B746C,\n    0x4B746C,\n    0x4B746C,\n    0x4B746C,\n    0x4B746C,\n    0x4A756C,\n    0x49786E,\n    0x49786E,\n    0x48776D,\n    0x49746B,\n    0x48736A,\n    0x487068,\n    0x4A6D67,\n    0x4C6B66,\n    0x425F5B,\n    0x425B58,\n    0x3E5251,\n    0x394949,\n    0x313F40,\n    0x2A3537,\n    0x252F31,\n    0x222A2C,\n    0x282E2E,\n    0x282C2B,\n    0x262A29,\n    0x232726,\n    0x202423,\n    0x1D2120,\n    0x1B1F1E,\n    0x1A1E1D,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212526,\n    0x23272A,\n    0x23262B,\n    0x23262B,\n    0x23262B,\n    0x23262B,\n    0x23262B,\n    0x23262B,\n    0x23262B,\n    0x2A2D32,\n    0x2A2D32,\n    0x2A2D32,\n    0x2A2D32,\n    0x2A2D32,\n    0x2A2D32,\n    0x2A2D32,\n    0x2A2D32,\n    0x3F7398,\n    0x3E7297,\n    0x3E7091,\n    0x3D6E8F,\n    0x3D6C8A,\n    0x3C6885,\n    0x3D6780,\n    0x3F657C,\n    0x3A5D73,\n    0x3C5B6F,\n    0x3C5969,\n    0x3C5665,\n    0x3C5460,\n    0x3B515E,\n    0x3B4F58,\n    0x3A4E57,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3A5358,\n    0x3B575A,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B64,\n    0x4C7066,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4D7368,\n    0x4B736A,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4B796F,\n    0x477B6F,\n    0x447C6F,\n    0x467C6F,\n    0x467A6E,\n    0x47796E,\n    0x4A786E,\n    0x4C776E,\n    0x4E766E,\n    0x4B6E68,\n    0x4B6A65,\n    0x46635F,\n    0x415A57,\n    0x3A504E,\n    0x354747,\n    0x2F4141,\n    0x303C3C,\n    0x303938,\n    0x323635,\n    0x2F3332,\n    0x2A2E2D,\n    0x262A29,\n    0x212524,\n    0x1E2221,\n    0x1D2120,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212526,\n    0x212528,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x24272C,\n    0x24272C,\n    0x24272C,\n    0x24272C,\n    0x24272C,\n    0x24272C,\n    0x24272C,\n    0x24272C,\n    0x3D7196,\n    0x3C7095,\n    0x3C6E8F,\n    0x3B6C8D,\n    0x3B6A88,\n    0x3A6683,\n    0x3B657E,\n    0x3D637A,\n    0x385B71,\n    0x3A596D,\n    0x3A5767,\n    0x3A5463,\n    0x3A525E,\n    0x394F5C,\n    0x394D56,\n    0x384C55,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3A5358,\n    0x3B575A,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B64,\n    0x4C7066,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4D7368,\n    0x4B736A,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x507971,\n    0x507971,\n    0x507971,\n    0x507971,\n    0x507971,\n    0x507971,\n    0x507971,\n    0x4D7B71,\n    0x407A6C,\n    0x3F7C6D,\n    0x3F7C6D,\n    0x437B6E,\n    0x447C6F,\n    0x487C70,\n    0x4C7B71,\n    0x4F7A71,\n    0x4F7870,\n    0x50756E,\n    0x4E6E69,\n    0x4A6763,\n    0x44615D,\n    0x415A57,\n    0x3C5552,\n    0x3E514F,\n    0x3B4443,\n    0x3C403F,\n    0x383C3B,\n    0x323635,\n    0x2D3130,\n    0x272B2A,\n    0x232726,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212526,\n    0x1F2326,\n    0x1F2227,\n    0x1F2227,\n    0x1F2227,\n    0x1F2227,\n    0x1F2227,\n    0x1F2227,\n    0x1F2227,\n    0x202328,\n    0x202328,\n    0x202328,\n    0x202328,\n    0x202328,\n    0x202328,\n    0x202328,\n    0x202328,\n    0x3C7095,\n    0x3B6F94,\n    0x3B6D8E,\n    0x3A6B8C,\n    0x396886,\n    0x396582,\n    0x3A647D,\n    0x3C6279,\n    0x375A70,\n    0x39586C,\n    0x395666,\n    0x395362,\n    0x39515D,\n    0x384E5B,\n    0x384C55,\n    0x374B54,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3A5358,\n    0x3B575A,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x3C5A5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x405F5A,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x466560,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B64,\n    0x4C7066,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4C7064,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4E7266,\n    0x4D7368,\n    0x4B736A,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x517A72,\n    0x517A72,\n    0x517A72,\n    0x517A72,\n    0x517A72,\n    0x517A72,\n    0x517A72,\n    0x4D7C72,\n    0x3E786A,\n    0x3B7B6B,\n    0x3D7B6C,\n    0x3F7C6D,\n    0x437D6F,\n    0x477D70,\n    0x497D71,\n    0x4D7C72,\n    0x537E75,\n    0x537B73,\n    0x51766F,\n    0x50706B,\n    0x4C6B66,\n    0x486561,\n    0x47615E,\n    0x495D5B,\n    0x404A49,\n    0x424645,\n    0x3D4140,\n    0x383C3B,\n    0x313534,\n    0x2C302F,\n    0x272B2A,\n    0x252928,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212524,\n    0x212526,\n    0x1E2225,\n    0x1E2126,\n    0x1E2126,\n    0x1E2126,\n    0x1E2126,\n    0x1E2126,\n    0x1E2126,\n    0x1E2126,\n    0x1E2126,\n    0x1E2126,\n    0x1E2126,\n    0x1E2126,\n    0x1E2126,\n    0x1E2126,\n    0x1E2126,\n    0x1E2126,\n    0x435E6F,\n    0x435E6F,\n    0x435E6F,\n    0x435E6F,\n    0x435E6F,\n    0x435E6F,\n    0x435E6F,\n    0x435E6F,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x395362,\n    0x3A525C,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3B5459,\n    0x3B575A,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4B7069,\n    0x4B736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7872,\n    0x4F7872,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x517573,\n    0x496566,\n    0x496163,\n    0x455A5D,\n    0x3E5155,\n    0x36484C,\n    0x313E44,\n    0x2D383E,\n    0x2C333B,\n    0x181B24,\n    0x1C1A25,\n    0x1F1C27,\n    0x241C29,\n    0x291E2C,\n    0x2D212F,\n    0x302231,\n    0x2F2432,\n    0x1F1E24,\n    0x1C1F24,\n    0x1D2025,\n    0x1F2227,\n    0x202328,\n    0x22252A,\n    0x23262B,\n    0x24272C,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x425D6E,\n    0x425D6E,\n    0x425D6E,\n    0x425D6E,\n    0x425D6E,\n    0x425D6E,\n    0x425D6E,\n    0x425D6E,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x395362,\n    0x3A525C,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3B5459,\n    0x3B575A,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4B7069,\n    0x4B736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7872,\n    0x4F7872,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x517573,\n    0x4C6C6B,\n    0x4D6768,\n    0x476162,\n    0x43585B,\n    0x3B5053,\n    0x35474B,\n    0x323F45,\n    0x323B42,\n    0x20272F,\n    0x23262F,\n    0x26242F,\n    0x29232F,\n    0x29232F,\n    0x2D2230,\n    0x2D2230,\n    0x2B2330,\n    0x212026,\n    0x1F2227,\n    0x1F2227,\n    0x202328,\n    0x212429,\n    0x22252A,\n    0x23262B,\n    0x23262B,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x405B6C,\n    0x405B6C,\n    0x405B6C,\n    0x405B6C,\n    0x405B6C,\n    0x405B6C,\n    0x405B6C,\n    0x405B6C,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x395362,\n    0x3A525C,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3B5459,\n    0x3B575A,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4B7069,\n    0x4B736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7872,\n    0x4F7872,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4F7673,\n    0x4F7371,\n    0x50706F,\n    0x4B6B6A,\n    0x476364,\n    0x425C5D,\n    0x3E5356,\n    0x3A4D51,\n    0x3B4A4F,\n    0x303B41,\n    0x313840,\n    0x30343D,\n    0x2F2F39,\n    0x2C2A35,\n    0x2A2732,\n    0x29232F,\n    0x25222D,\n    0x25262B,\n    0x23262B,\n    0x23262B,\n    0x23262B,\n    0x23262B,\n    0x23262B,\n    0x22252A,\n    0x22252A,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x3E596A,\n    0x3E596A,\n    0x3E596A,\n    0x3E596A,\n    0x3E596A,\n    0x3E596A,\n    0x3E596A,\n    0x3E596A,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x395362,\n    0x3A525C,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3B5459,\n    0x3B575A,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4B7069,\n    0x4B736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7872,\n    0x4F7872,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x527B77,\n    0x507975,\n    0x4D7471,\n    0x4A6E6C,\n    0x466867,\n    0x436161,\n    0x435D5E,\n    0x44595C,\n    0x3E5155,\n    0x3E4D52,\n    0x3C474D,\n    0x373E46,\n    0x2F363E,\n    0x2B2E37,\n    0x262932,\n    0x25252F,\n    0x292C31,\n    0x292C31,\n    0x282B30,\n    0x26292E,\n    0x25282D,\n    0x23262B,\n    0x22252A,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x3B5667,\n    0x3B5667,\n    0x3B5667,\n    0x3B5667,\n    0x3B5667,\n    0x3B5667,\n    0x3B5667,\n    0x3B5667,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x395362,\n    0x3A525C,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3B5459,\n    0x3B575A,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4B7069,\n    0x4B736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7872,\n    0x4F7872,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4D7773,\n    0x507F79,\n    0x4E7D77,\n    0x4B7A74,\n    0x4B7571,\n    0x47716D,\n    0x456C69,\n    0x466867,\n    0x476565,\n    0x476364,\n    0x475F61,\n    0x43565A,\n    0x3E4D52,\n    0x354248,\n    0x2F3A40,\n    0x293239,\n    0x272E36,\n    0x2F3438,\n    0x2F3237,\n    0x2D3035,\n    0x2A2D32,\n    0x272A2F,\n    0x24272C,\n    0x22252A,\n    0x202328,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x395362,\n    0x3A525C,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3B5459,\n    0x3B575A,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4B7069,\n    0x4B736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7872,\n    0x4F7872,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4B7873,\n    0x4A7D76,\n    0x467E75,\n    0x477C74,\n    0x457871,\n    0x44756F,\n    0x45726D,\n    0x456F6B,\n    0x466D6A,\n    0x4C6E6D,\n    0x4B6969,\n    0x476364,\n    0x425A5C,\n    0x3B5053,\n    0x35474B,\n    0x2F4145,\n    0x313C42,\n    0x333B3E,\n    0x35383D,\n    0x313439,\n    0x2D3035,\n    0x282B30,\n    0x24272C,\n    0x212429,\n    0x1F2227,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x365162,\n    0x365162,\n    0x365162,\n    0x365162,\n    0x365162,\n    0x365162,\n    0x365162,\n    0x365162,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x395362,\n    0x3A525C,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3B5459,\n    0x3B575A,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4B7069,\n    0x4B736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7872,\n    0x4F7872,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4B7873,\n    0x427B72,\n    0x407C72,\n    0x3F7B71,\n    0x40786F,\n    0x3F776E,\n    0x41746D,\n    0x43726C,\n    0x456F6B,\n    0x4B7470,\n    0x4B6F6D,\n    0x4A6A69,\n    0x466263,\n    0x3F5B5C,\n    0x3C5456,\n    0x385052,\n    0x394B4F,\n    0x384043,\n    0x393C41,\n    0x35383D,\n    0x303338,\n    0x2A2D32,\n    0x25282D,\n    0x212429,\n    0x1F2227,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x355061,\n    0x355061,\n    0x355061,\n    0x355061,\n    0x355061,\n    0x355061,\n    0x355061,\n    0x355061,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x385364,\n    0x395362,\n    0x3A525C,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3B5459,\n    0x3B575A,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3A5858,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x3E5C5C,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x41645E,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x446761,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x486B65,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4C6F69,\n    0x4B7069,\n    0x4B736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4A736B,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4E776F,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7870,\n    0x4F7872,\n    0x4F7872,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4F7874,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4A7973,\n    0x3F786F,\n    0x3B7A6F,\n    0x3B796E,\n    0x3B776D,\n    0x3D766D,\n    0x3F746C,\n    0x3F726B,\n    0x42716B,\n    0x4A7470,\n    0x4A716E,\n    0x496D6B,\n    0x476766,\n    0x436161,\n    0x405C5D,\n    0x3E5859,\n    0x405357,\n    0x3A4446,\n    0x3B3E43,\n    0x373A3F,\n    0x313439,\n    0x2B2E33,\n    0x25282D,\n    0x212429,\n    0x1E2126,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x212429,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x36515C,\n    0x3A535A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3B545B,\n    0x3D585F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D61,\n    0x416364,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x436765,\n    0x476F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x48716B,\n    0x4C756F,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B78,\n    0x4E7A79,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4E7779,\n    0x4D7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4D7577,\n    0x4B7375,\n    0x497173,\n    0x476F71,\n    0x456D6F,\n    0x436B6D,\n    0x45686C,\n    0x3E5960,\n    0x3E555D,\n    0x3C5059,\n    0x374953,\n    0x32434D,\n    0x2F3B47,\n    0x2D3743,\n    0x2C3240,\n    0x272938,\n    0x292637,\n    0x2A2637,\n    0x2C2336,\n    0x2D2135,\n    0x2D2034,\n    0x2D1E33,\n    0x2D1E33,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x36515C,\n    0x3A535A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3B545B,\n    0x3D585F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D61,\n    0x416364,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x436765,\n    0x476F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x48716B,\n    0x4C756F,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B78,\n    0x4E7A79,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4E7779,\n    0x4D7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4D7577,\n    0x4B7375,\n    0x497173,\n    0x476F71,\n    0x456D6F,\n    0x436B6D,\n    0x45686C,\n    0x405F64,\n    0x425B62,\n    0x3E575E,\n    0x3C5059,\n    0x364A53,\n    0x33444E,\n    0x323E4A,\n    0x333B48,\n    0x2C3240,\n    0x2E303F,\n    0x2F2C3D,\n    0x2F283A,\n    0x2C2537,\n    0x2C2034,\n    0x2A1E32,\n    0x291C30,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x36515C,\n    0x3A535A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3B545B,\n    0x3D585F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D61,\n    0x416364,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x436765,\n    0x476F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x48716B,\n    0x4C756F,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B78,\n    0x4E7A79,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4E7779,\n    0x4D7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4D7577,\n    0x4B7375,\n    0x497173,\n    0x476F71,\n    0x456D6F,\n    0x436B6D,\n    0x43696C,\n    0x44676B,\n    0x456469,\n    0x426166,\n    0x405B62,\n    0x3D565D,\n    0x3C5059,\n    0x3A4C56,\n    0x3B4954,\n    0x38424E,\n    0x383E4C,\n    0x353847,\n    0x333242,\n    0x2D2A3B,\n    0x292536,\n    0x261F31,\n    0x241D2F,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x36515C,\n    0x3A535A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3B545B,\n    0x3D585F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D61,\n    0x416364,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x436765,\n    0x476F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x48716B,\n    0x4C756F,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B78,\n    0x4E7A79,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4E7779,\n    0x4D7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4D7577,\n    0x4B7375,\n    0x497173,\n    0x476F71,\n    0x456D6F,\n    0x436B6D,\n    0x426A6C,\n    0x466E70,\n    0x456D6F,\n    0x446A6D,\n    0x43666A,\n    0x416267,\n    0x415E64,\n    0x425B62,\n    0x445861,\n    0x3F515B,\n    0x3F4D58,\n    0x3C4652,\n    0x363C4A,\n    0x2E3442,\n    0x292B3A,\n    0x232534,\n    0x222131,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x36515C,\n    0x3A535A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3B545B,\n    0x3D585F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D61,\n    0x416364,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x436765,\n    0x476F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x48716B,\n    0x4C756F,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B78,\n    0x4E7A79,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4E7779,\n    0x4D7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4D7577,\n    0x4B7375,\n    0x497173,\n    0x476F71,\n    0x456D6F,\n    0x436B6D,\n    0x416A6C,\n    0x447272,\n    0x447272,\n    0x437171,\n    0x446D6F,\n    0x426B6D,\n    0x43696C,\n    0x45666B,\n    0x47646A,\n    0x425D64,\n    0x425961,\n    0x3F515B,\n    0x3A4853,\n    0x333F4B,\n    0x2D3743,\n    0x28303D,\n    0x252D3A,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x36515C,\n    0x3A535A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3B545B,\n    0x3D585F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D61,\n    0x416364,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x436765,\n    0x476F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x48716B,\n    0x4C756F,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B78,\n    0x4E7A79,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4E7779,\n    0x4D7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4D7577,\n    0x4B7375,\n    0x497173,\n    0x476F71,\n    0x456D6F,\n    0x436B6D,\n    0x3F6B6C,\n    0x3F7170,\n    0x3C7370,\n    0x3E7270,\n    0x3F7170,\n    0x407070,\n    0x426E6F,\n    0x446D6F,\n    0x466C6F,\n    0x406166,\n    0x415E64,\n    0x3D585F,\n    0x3B525A,\n    0x364A53,\n    0x33444E,\n    0x2E3F49,\n    0x2E3C47,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x36515C,\n    0x3A535A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3B545B,\n    0x3D585F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D61,\n    0x416364,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x436765,\n    0x476F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x48716B,\n    0x4C756F,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B78,\n    0x4E7A79,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4E7779,\n    0x4D7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4D7577,\n    0x4B7375,\n    0x497173,\n    0x476F71,\n    0x456D6F,\n    0x436B6D,\n    0x3F6B6C,\n    0x376F6C,\n    0x35706C,\n    0x36716D,\n    0x3A716E,\n    0x3B726F,\n    0x3E706F,\n    0x427070,\n    0x466F71,\n    0x3B6365,\n    0x3C5F63,\n    0x3D5C61,\n    0x3C575E,\n    0x39545B,\n    0x395058,\n    0x374E56,\n    0x384C55,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x35515C,\n    0x36515C,\n    0x3A535A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3B525A,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3C535B,\n    0x3B545B,\n    0x3D585F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x3C595F,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D63,\n    0x405D61,\n    0x416364,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x416362,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x446665,\n    0x436765,\n    0x476F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x466F67,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x487169,\n    0x48716B,\n    0x4C756F,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4C7571,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4E7773,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4C7974,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B76,\n    0x4E7B78,\n    0x4E7A79,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4E7A7B,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4E7779,\n    0x4D7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4E7678,\n    0x4D7577,\n    0x4B7375,\n    0x497173,\n    0x476F71,\n    0x456D6F,\n    0x436B6D,\n    0x3E6C6C,\n    0x336B68,\n    0x306E69,\n    0x326F6A,\n    0x346F6B,\n    0x38706D,\n    0x3D716F,\n    0x3F7170,\n    0x427070,\n    0x376062,\n    0x395F62,\n    0x3A5D61,\n    0x3C5B60,\n    0x3C595F,\n    0x3C575E,\n    0x3E575E,\n    0x3D565D,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3E6163,\n    0x406766,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7875,\n    0x4C7877,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C787B,\n    0x4B777A,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x497278,\n    0x436C72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x436A71,\n    0x426970,\n    0x40676E,\n    0x3E656C,\n    0x3B6269,\n    0x396067,\n    0x385F66,\n    0x375E65,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3E6163,\n    0x406766,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7875,\n    0x4C7877,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C787B,\n    0x4B777A,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x497278,\n    0x436C72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x436A71,\n    0x426970,\n    0x40676E,\n    0x3E656C,\n    0x3B6269,\n    0x396067,\n    0x385F66,\n    0x375E65,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3E6163,\n    0x406766,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7875,\n    0x4C7877,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C787B,\n    0x4B777A,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x497278,\n    0x436C72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x436A71,\n    0x426970,\n    0x40676E,\n    0x3E656C,\n    0x3B6269,\n    0x396067,\n    0x385F66,\n    0x375E65,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3E6163,\n    0x406766,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7875,\n    0x4C7877,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C787B,\n    0x4B777A,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x497278,\n    0x436C72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x436A71,\n    0x426970,\n    0x40676E,\n    0x3E656C,\n    0x3B6269,\n    0x396067,\n    0x385F66,\n    0x375E65,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3E6163,\n    0x406766,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7875,\n    0x4C7877,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C787B,\n    0x4B777A,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x497278,\n    0x436C72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x436A71,\n    0x426970,\n    0x40676E,\n    0x3E656C,\n    0x3B6269,\n    0x396067,\n    0x385F66,\n    0x375E65,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3E6163,\n    0x406766,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7875,\n    0x4C7877,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C787B,\n    0x4B777A,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x497278,\n    0x436C72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x436A71,\n    0x426970,\n    0x40676E,\n    0x3E656C,\n    0x3B6269,\n    0x396067,\n    0x385F66,\n    0x375E65,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3E6163,\n    0x406766,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7875,\n    0x4C7877,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C787B,\n    0x4B777A,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x497278,\n    0x436C72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x436A71,\n    0x426970,\n    0x40676E,\n    0x3E656C,\n    0x3B6269,\n    0x396067,\n    0x385F66,\n    0x375E65,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3E6163,\n    0x406766,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x3F6864,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x426B67,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x466F6B,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x48716D,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x497671,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7873,\n    0x4B7875,\n    0x4C7877,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C7879,\n    0x4C787B,\n    0x4B777A,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x497278,\n    0x436C72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x446B72,\n    0x436A71,\n    0x426970,\n    0x40676E,\n    0x3E656C,\n    0x3B6269,\n    0x396067,\n    0x385F66,\n    0x375E65,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3E6165,\n    0x406669,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B777A,\n    0x4B777A,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x4B747A,\n    0x497278,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3E6165,\n    0x406669,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B777A,\n    0x4B777A,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x4B747A,\n    0x497278,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3E6165,\n    0x406669,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B777A,\n    0x4B777A,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x4B747A,\n    0x497278,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3E6165,\n    0x406669,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B777A,\n    0x4B777A,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x4B747A,\n    0x497278,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3E6165,\n    0x406669,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B777A,\n    0x4B777A,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x4B747A,\n    0x497278,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3E6165,\n    0x406669,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B777A,\n    0x4B777A,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x4B747A,\n    0x497278,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3E6165,\n    0x406669,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B777A,\n    0x4B777A,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x4B747A,\n    0x497278,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2B484E,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x2F4C52,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x355258,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x38555B,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x395A5F,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3F6065,\n    0x3E6165,\n    0x406669,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x466E70,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x487072,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x497576,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B7778,\n    0x4B777A,\n    0x4B777A,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x4B767C,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x4B747A,\n    0x497278,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x4A7178,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x3F666D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545C,\n    0x395A61,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3C5E67,\n    0x406669,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457174,\n    0x477376,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x477076,\n    0x456E74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x436871,\n    0x436571,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545C,\n    0x395A61,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3C5E67,\n    0x406669,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457174,\n    0x477376,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x477076,\n    0x456E74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x436871,\n    0x436571,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545C,\n    0x395A61,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3C5E67,\n    0x406669,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457174,\n    0x477376,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x477076,\n    0x456E74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x436871,\n    0x436571,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545C,\n    0x395A61,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3C5E67,\n    0x406669,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457174,\n    0x477376,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x477076,\n    0x456E74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x436871,\n    0x436571,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545C,\n    0x395A61,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3C5E67,\n    0x406669,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457174,\n    0x477376,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x477076,\n    0x456E74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x436871,\n    0x436571,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545C,\n    0x395A61,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3C5E67,\n    0x406669,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457174,\n    0x477376,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x477076,\n    0x456E74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x436871,\n    0x436571,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545C,\n    0x395A61,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3C5E67,\n    0x406669,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457174,\n    0x477376,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x477076,\n    0x456E74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x436871,\n    0x436571,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x26424D,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x2D4954,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x335056,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545A,\n    0x37545C,\n    0x395A61,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x395A63,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3D5E67,\n    0x3C5E67,\n    0x406669,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x3F6769,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x426A6C,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457172,\n    0x457174,\n    0x477376,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x49747A,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x477278,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x457076,\n    0x477076,\n    0x456E74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x466D74,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x426970,\n    0x436871,\n    0x436571,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x446473,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E,\n    0x3F5F6E\n};\n"
  },
  {
    "path": "esp_jpeg/test_apps/main/test_usb_camera_jpg.h",
    "content": "/*\nRaw data from Logitech C270 USB camera was reconstructed to usb_camera.jpg\nIt was converted to RGB888 array with jpg_to_rgb888_hex.py\n*/\n\n// JPEG encoded frame 160x120, 2632 bytes, no huffman tables, double block size (16x8 pixels)\nextern const unsigned char jpeg_no_huffman[] asm(\"_binary_usb_camera_jpg_start\");\n\nextern char _binary_usb_camera_jpg_start;\nextern char _binary_usb_camera_jpg_end;\n// Must be defined as macro because extern variables are not known at compile time (but at link time)\n#define jpeg_no_huffman_len (&_binary_usb_camera_jpg_end - &_binary_usb_camera_jpg_start)\n"
  },
  {
    "path": "esp_jpeg/test_apps/main/test_usb_camera_rgb888.h",
    "content": "unsigned int jpeg_no_huffman_rgb888[19200] = {\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000E00,\n    0x000900,\n    0x000800,\n    0x000600,\n    0x131E10,\n    0x767E71,\n    0x787E72,\n    0x74776C,\n    0x787B70,\n    0x7F8176,\n    0x84867B,\n    0x86887A,\n    0x87897B,\n    0x888A7C,\n    0x888A7C,\n    0x888A7C,\n    0x898B7D,\n    0x898B7D,\n    0x8A8C7E,\n    0x8A8C7E,\n    0x898B7D,\n    0x888A7C,\n    0x888A7C,\n    0x848678,\n    0x87897B,\n    0x8A8C7E,\n    0x8C8E80,\n    0x8D8F81,\n    0x8D8F81,\n    0x8D8F81,\n    0x8E9082,\n    0x8E9082,\n    0x8D8F81,\n    0x8D8F81,\n    0x8D8F81,\n    0x8D8F81,\n    0x8D8F81,\n    0x8C8E80,\n    0x8B8D7F,\n    0x8B8D7F,\n    0x8B8D7F,\n    0x8B8D7F,\n    0x8A8C7E,\n    0x8A8C7E,\n    0x898B7D,\n    0x898B7D,\n    0x878B7C,\n    0x818A79,\n    0x7F8A79,\n    0x7F8A79,\n    0x808B7A,\n    0x818C7B,\n    0x808B7A,\n    0x7D8A78,\n    0x7B8876,\n    0x788573,\n    0x788573,\n    0x788774,\n    0x788774,\n    0x778673,\n    0x768572,\n    0x748370,\n    0x73826F,\n    0x74816F,\n    0x73806E,\n    0x73806E,\n    0x727F6D,\n    0x707F6C,\n    0x6F7E6B,\n    0x6E7D6A,\n    0x6E7D6A,\n    0x6A7B68,\n    0x6A7B68,\n    0x687B67,\n    0x677A66,\n    0x667965,\n    0x657864,\n    0x647763,\n    0x657664,\n    0x667463,\n    0x667264,\n    0x657362,\n    0x657362,\n    0x647563,\n    0x647563,\n    0x617461,\n    0x5F7161,\n    0x627363,\n    0x5D6D62,\n    0x5E6B61,\n    0x5D6A63,\n    0x626D67,\n    0x495450,\n    0x313A39,\n    0x000802,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000D00,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x182315,\n    0x788073,\n    0x797F73,\n    0x7A7D72,\n    0x7D8075,\n    0x818378,\n    0x83857A,\n    0x848678,\n    0x858779,\n    0x86887A,\n    0x87897B,\n    0x87897B,\n    0x888A7C,\n    0x898B7D,\n    0x8A8C7E,\n    0x8B8D7F,\n    0x8C8E80,\n    0x8D8F81,\n    0x8D8F81,\n    0x858779,\n    0x888A7C,\n    0x8B8D7F,\n    0x8E9082,\n    0x8E9082,\n    0x8E9082,\n    0x8E9082,\n    0x8F9183,\n    0x8F9183,\n    0x8F9183,\n    0x8F9183,\n    0x8F9183,\n    0x8F9183,\n    0x8F9183,\n    0x8F9183,\n    0x8E9082,\n    0x8B8D7F,\n    0x8B8D7F,\n    0x8A8C7E,\n    0x8A8C7E,\n    0x898B7D,\n    0x898B7D,\n    0x888A7C,\n    0x878B7C,\n    0x888F7F,\n    0x868F7E,\n    0x848D7C,\n    0x838C7B,\n    0x828B7A,\n    0x7F8877,\n    0x798473,\n    0x768170,\n    0x768170,\n    0x768170,\n    0x768170,\n    0x768170,\n    0x74816F,\n    0x73806E,\n    0x727F6D,\n    0x717E6C,\n    0x727D6C,\n    0x727D6C,\n    0x727D6C,\n    0x727D6C,\n    0x707D6B,\n    0x707D6B,\n    0x707D6B,\n    0x707D6B,\n    0x6C7B68,\n    0x6C7B68,\n    0x6B7A67,\n    0x6A7966,\n    0x687966,\n    0x677865,\n    0x677865,\n    0x687665,\n    0x6D7B6A,\n    0x6D796B,\n    0x6A7867,\n    0x697766,\n    0x677866,\n    0x657664,\n    0x627562,\n    0x607262,\n    0x637464,\n    0x5F6F64,\n    0x616E64,\n    0x5E6B64,\n    0x636E68,\n    0x4E5955,\n    0x363F3E,\n    0x000802,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000D00,\n    0x000A00,\n    0x000B00,\n    0x000A00,\n    0x202B1D,\n    0x798174,\n    0x787E72,\n    0x797C71,\n    0x7A7D72,\n    0x7C7E73,\n    0x7C7E73,\n    0x7D7F71,\n    0x7E8072,\n    0x808274,\n    0x828476,\n    0x808274,\n    0x808274,\n    0x818375,\n    0x818375,\n    0x838577,\n    0x858779,\n    0x87897B,\n    0x888A7C,\n    0x86887A,\n    0x898B7D,\n    0x8D8F81,\n    0x8F9183,\n    0x8F9183,\n    0x8F9183,\n    0x909284,\n    0x909284,\n    0x8E9082,\n    0x8E9082,\n    0x8E9082,\n    0x8E9082,\n    0x8E9082,\n    0x8E9082,\n    0x8E9082,\n    0x8F9183,\n    0x8F9183,\n    0x8F9183,\n    0x8E9082,\n    0x8E9082,\n    0x8D8F81,\n    0x8D8F81,\n    0x8C8E80,\n    0x8C8E80,\n    0x888C7D,\n    0x878B7C,\n    0x868A7B,\n    0x868A7B,\n    0x868A7B,\n    0x848879,\n    0x808777,\n    0x7D8474,\n    0x707767,\n    0x707767,\n    0x6F7867,\n    0x6E7766,\n    0x6D7665,\n    0x6C7564,\n    0x6B7463,\n    0x6A7362,\n    0x6B7463,\n    0x6A7362,\n    0x6A7362,\n    0x697261,\n    0x687160,\n    0x67705F,\n    0x67705F,\n    0x666F5E,\n    0x687362,\n    0x687362,\n    0x677261,\n    0x677261,\n    0x667160,\n    0x65705F,\n    0x63705E,\n    0x63705E,\n    0x646F5F,\n    0x646F5F,\n    0x63705F,\n    0x657261,\n    0x657664,\n    0x677866,\n    0x667765,\n    0x667765,\n    0x647565,\n    0x627265,\n    0x627265,\n    0x5E6B62,\n    0x626F66,\n    0x56615D,\n    0x3E4945,\n    0x000903,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000D00,\n    0x000B00,\n    0x000C00,\n    0x000A00,\n    0x293426,\n    0x798174,\n    0x767C70,\n    0x7B7E73,\n    0x7C7F74,\n    0x7F8176,\n    0x808277,\n    0x818375,\n    0x828476,\n    0x858779,\n    0x87897B,\n    0x87897B,\n    0x86887A,\n    0x858779,\n    0x858779,\n    0x858779,\n    0x87897B,\n    0x898B7D,\n    0x8A8C7E,\n    0x87897B,\n    0x898B7D,\n    0x8D8F81,\n    0x8F9183,\n    0x909284,\n    0x909284,\n    0x909284,\n    0x919385,\n    0x8E9082,\n    0x8F9183,\n    0x8F9183,\n    0x8E9082,\n    0x8E9082,\n    0x8E9082,\n    0x8F9183,\n    0x909284,\n    0x8C8E80,\n    0x8C8E80,\n    0x8C8E80,\n    0x8B8D7F,\n    0x8B8D7F,\n    0x8A8C7E,\n    0x8A8C7E,\n    0x8A8C7E,\n    0x898A7C,\n    0x898A7C,\n    0x87897B,\n    0x888A7C,\n    0x898B7D,\n    0x898B7D,\n    0x888A7C,\n    0x86887A,\n    0x7D8172,\n    0x7D8172,\n    0x7C8071,\n    0x7C8071,\n    0x7B7F70,\n    0x797D6E,\n    0x787C6D,\n    0x787C6D,\n    0x757C6C,\n    0x747B6B,\n    0x737A6A,\n    0x717868,\n    0x6E7565,\n    0x6C7363,\n    0x6A7161,\n    0x697060,\n    0x6A7161,\n    0x697060,\n    0x686F5F,\n    0x676E5E,\n    0x666D5D,\n    0x656C5C,\n    0x646B5B,\n    0x636A5A,\n    0x5B6656,\n    0x5C6757,\n    0x5D6A59,\n    0x616E5D,\n    0x647360,\n    0x687764,\n    0x677866,\n    0x677866,\n    0x647666,\n    0x627466,\n    0x657568,\n    0x5D6D63,\n    0x626F66,\n    0x5B6861,\n    0x48534F,\n    0x010C04,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000D00,\n    0x000B00,\n    0x000C00,\n    0x000A00,\n    0x333E30,\n    0x798174,\n    0x757B6F,\n    0x76796E,\n    0x787B70,\n    0x7C7E73,\n    0x7E8075,\n    0x7E8072,\n    0x7E8072,\n    0x7E8072,\n    0x7F8173,\n    0x848678,\n    0x838577,\n    0x828476,\n    0x828476,\n    0x828476,\n    0x848678,\n    0x86887A,\n    0x87897B,\n    0x86887A,\n    0x898B7D,\n    0x8D8F81,\n    0x8F9183,\n    0x909284,\n    0x909284,\n    0x909284,\n    0x919385,\n    0x919385,\n    0x929486,\n    0x929486,\n    0x909284,\n    0x8F9183,\n    0x8F9183,\n    0x919385,\n    0x939587,\n    0x919385,\n    0x909284,\n    0x909284,\n    0x909284,\n    0x8F9183,\n    0x8F9183,\n    0x8E9082,\n    0x8E9082,\n    0x909183,\n    0x8E8F81,\n    0x8C8D7F,\n    0x8C8D7F,\n    0x8B8C7E,\n    0x8A8B7D,\n    0x88897B,\n    0x87887A,\n    0x888A7C,\n    0x888A7C,\n    0x87897B,\n    0x86887A,\n    0x838778,\n    0x838778,\n    0x828677,\n    0x828677,\n    0x808475,\n    0x7F8374,\n    0x7D8172,\n    0x7B7F70,\n    0x797D6E,\n    0x767A6B,\n    0x75796A,\n    0x747869,\n    0x767A6B,\n    0x75796A,\n    0x747869,\n    0x727667,\n    0x707465,\n    0x6E7263,\n    0x6D7162,\n    0x6C7061,\n    0x6C7465,\n    0x6B7364,\n    0x687362,\n    0x697463,\n    0x687764,\n    0x687764,\n    0x657663,\n    0x637461,\n    0x657865,\n    0x617363,\n    0x677868,\n    0x5F6F64,\n    0x5E6E64,\n    0x5D6C65,\n    0x4F5B57,\n    0x07140B,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000D00,\n    0x000B00,\n    0x000D00,\n    0x000A00,\n    0x3D483A,\n    0x7C8477,\n    0x777D71,\n    0x777A6F,\n    0x797C71,\n    0x7C7E73,\n    0x7D7F74,\n    0x7C7E70,\n    0x7A7C6E,\n    0x7A7C6E,\n    0x7A7C6E,\n    0x7B7D6F,\n    0x7B7D6F,\n    0x7B7D6F,\n    0x7C7E70,\n    0x7E8072,\n    0x808274,\n    0x828476,\n    0x838577,\n    0x87897B,\n    0x8A8C7E,\n    0x8D8F81,\n    0x909284,\n    0x909284,\n    0x909284,\n    0x909284,\n    0x919385,\n    0x8F9183,\n    0x909284,\n    0x909284,\n    0x8E9082,\n    0x8C8E80,\n    0x8B8D7F,\n    0x8E9082,\n    0x919385,\n    0x8F9183,\n    0x8E9082,\n    0x8E9082,\n    0x8D8F81,\n    0x8D8F81,\n    0x8C8E80,\n    0x8C8E80,\n    0x8C8E80,\n    0x8E8F81,\n    0x8C8D7F,\n    0x8B8C7E,\n    0x8A8B7D,\n    0x8B8C7E,\n    0x8B8C7E,\n    0x898B7D,\n    0x888A7C,\n    0x888A7C,\n    0x87897B,\n    0x858779,\n    0x848678,\n    0x818576,\n    0x818576,\n    0x808475,\n    0x808475,\n    0x7C8373,\n    0x7C8373,\n    0x7C8373,\n    0x7B8272,\n    0x7A8171,\n    0x798070,\n    0x7B7F70,\n    0x7A7E6F,\n    0x7C8071,\n    0x7B7F70,\n    0x7A7E6F,\n    0x797D6E,\n    0x787A6C,\n    0x77796B,\n    0x76786A,\n    0x747869,\n    0x767D6D,\n    0x747D6C,\n    0x707B6A,\n    0x6F7A69,\n    0x6D7A68,\n    0x6C7967,\n    0x677865,\n    0x657663,\n    0x677A67,\n    0x607262,\n    0x677969,\n    0x617367,\n    0x5E6E63,\n    0x5E6E64,\n    0x55645D,\n    0x0F1F15,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000C00,\n    0x000A00,\n    0x000D00,\n    0x000C00,\n    0x485345,\n    0x828A7D,\n    0x7D8377,\n    0x878A7F,\n    0x888B80,\n    0x8A8C81,\n    0x8A8C81,\n    0x888A7C,\n    0x888A7C,\n    0x898B7D,\n    0x8A8C7E,\n    0x86887A,\n    0x87897B,\n    0x888A7C,\n    0x898B7D,\n    0x8A8C7E,\n    0x8B8D7F,\n    0x8C8E80,\n    0x8C8E80,\n    0x888A7C,\n    0x8B8D7F,\n    0x8F9183,\n    0x919385,\n    0x919385,\n    0x919385,\n    0x929486,\n    0x929486,\n    0x8F9183,\n    0x919385,\n    0x909284,\n    0x8D8F81,\n    0x8A8C7E,\n    0x898B7D,\n    0x8C8E80,\n    0x909284,\n    0x848678,\n    0x848678,\n    0x848678,\n    0x838577,\n    0x838577,\n    0x828476,\n    0x828476,\n    0x818375,\n    0x898A7C,\n    0x87887A,\n    0x868779,\n    0x87887A,\n    0x87897B,\n    0x888A7C,\n    0x87897B,\n    0x87897B,\n    0x888C7D,\n    0x878B7C,\n    0x85897A,\n    0x838778,\n    0x828677,\n    0x818576,\n    0x818576,\n    0x818576,\n    0x7D8675,\n    0x7D8675,\n    0x7D8675,\n    0x7D8675,\n    0x7D8675,\n    0x7C8574,\n    0x7D8474,\n    0x7D8474,\n    0x767D6D,\n    0x767D6D,\n    0x787C6D,\n    0x787C6D,\n    0x777B6C,\n    0x777B6C,\n    0x787A6C,\n    0x787A6C,\n    0x737A6A,\n    0x727969,\n    0x717A69,\n    0x717A69,\n    0x6F7C68,\n    0x6F7C68,\n    0x6A7B68,\n    0x697A67,\n    0x6A7D6A,\n    0x5F7161,\n    0x687A6A,\n    0x65776B,\n    0x5F6F64,\n    0x5E6E64,\n    0x5B6A63,\n    0x1A2A20,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000C00,\n    0x000A00,\n    0x000E00,\n    0x000E00,\n    0x4F5A4C,\n    0x868E81,\n    0x82887C,\n    0x878A7F,\n    0x888B80,\n    0x898B80,\n    0x888A7F,\n    0x888A7C,\n    0x8A8C7E,\n    0x8D8F81,\n    0x909284,\n    0x8D8F81,\n    0x8D8F81,\n    0x8E9082,\n    0x8E9082,\n    0x8E9082,\n    0x8E9082,\n    0x8D8F81,\n    0x8C8E80,\n    0x898B7D,\n    0x8C8E80,\n    0x909284,\n    0x929486,\n    0x939587,\n    0x929486,\n    0x939587,\n    0x939587,\n    0x959789,\n    0x96988A,\n    0x96988A,\n    0x939587,\n    0x8F9183,\n    0x8E9082,\n    0x919385,\n    0x959789,\n    0x909284,\n    0x909284,\n    0x909284,\n    0x8F9183,\n    0x8F9183,\n    0x8E9082,\n    0x8E9082,\n    0x8D8F81,\n    0x8C8E80,\n    0x898B7D,\n    0x86887A,\n    0x848678,\n    0x828476,\n    0x818375,\n    0x7D8172,\n    0x7C8071,\n    0x7F8374,\n    0x7D8172,\n    0x7B7F70,\n    0x797D6E,\n    0x767D6D,\n    0x757C6C,\n    0x757C6C,\n    0x757C6C,\n    0x737E6D,\n    0x727D6C,\n    0x727D6C,\n    0x717C6B,\n    0x727B6A,\n    0x717A69,\n    0x707968,\n    0x707968,\n    0x727969,\n    0x727969,\n    0x75796A,\n    0x767A6B,\n    0x767A6B,\n    0x777B6C,\n    0x787C6D,\n    0x787C6D,\n    0x747B6B,\n    0x737A6A,\n    0x727B68,\n    0x727B68,\n    0x6F7C68,\n    0x6F7C68,\n    0x6A7C66,\n    0x697A67,\n    0x6C7F6B,\n    0x5E7060,\n    0x697B6B,\n    0x687A6E,\n    0x5E7064,\n    0x5D6E64,\n    0x5F6E67,\n    0x223228,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000E00,\n    0x000800,\n    0x001300,\n    0x000600,\n    0x000E00,\n    0x606B5B,\n    0x7C8475,\n    0x777D6F,\n    0x787C6E,\n    0x7B7F71,\n    0x818376,\n    0x86887B,\n    0x8A8C7F,\n    0x8C8E81,\n    0x8C8E81,\n    0x8B8D80,\n    0x8E9082,\n    0x8E9082,\n    0x8E9082,\n    0x8F9183,\n    0x8E9082,\n    0x8E9082,\n    0x8D8F81,\n    0x8C8E80,\n    0x8A8C7E,\n    0x8D8F81,\n    0x919385,\n    0x949688,\n    0x949688,\n    0x949688,\n    0x949688,\n    0x949688,\n    0x959789,\n    0x959789,\n    0x959789,\n    0x959789,\n    0x949688,\n    0x939587,\n    0x929486,\n    0x929486,\n    0x848678,\n    0x848678,\n    0x848678,\n    0x838577,\n    0x818375,\n    0x818375,\n    0x828476,\n    0x828476,\n    0x848678,\n    0x848678,\n    0x838577,\n    0x838577,\n    0x848678,\n    0x86887A,\n    0x858779,\n    0x828476,\n    0x858779,\n    0x86887A,\n    0x888A7C,\n    0x888A7C,\n    0x87897B,\n    0x858779,\n    0x828476,\n    0x808274,\n    0x838578,\n    0x838578,\n    0x828477,\n    0x808275,\n    0x7F8174,\n    0x7E8073,\n    0x7C7E71,\n    0x7C7E71,\n    0x76786B,\n    0x75776A,\n    0x747669,\n    0x737568,\n    0x717366,\n    0x707265,\n    0x6F7164,\n    0x6E7063,\n    0x6B7163,\n    0x6D7365,\n    0x6F7768,\n    0x727A6B,\n    0x707D6B,\n    0x707D6B,\n    0x6D7F69,\n    0x6C7E68,\n    0x6A7D69,\n    0x687B67,\n    0x677A67,\n    0x657865,\n    0x647666,\n    0x657769,\n    0x536356,\n    0x344437,\n    0x000900,\n    0x000F00,\n    0x000900,\n    0x000700,\n    0x000900,\n    0x000D00,\n    0x000900,\n    0x000700,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000800,\n    0x001200,\n    0x000700,\n    0x031100,\n    0x6D7868,\n    0x858D7E,\n    0x808678,\n    0x84887A,\n    0x868A7C,\n    0x898B7E,\n    0x8C8E81,\n    0x8E9083,\n    0x8F9184,\n    0x909285,\n    0x909285,\n    0x8F9183,\n    0x8F9183,\n    0x8F9183,\n    0x909284,\n    0x909284,\n    0x919385,\n    0x919385,\n    0x919385,\n    0x8A8C7E,\n    0x8D8F81,\n    0x919385,\n    0x949688,\n    0x949688,\n    0x949688,\n    0x949688,\n    0x949688,\n    0x959789,\n    0x959789,\n    0x959789,\n    0x959789,\n    0x949688,\n    0x939587,\n    0x939587,\n    0x929486,\n    0x929486,\n    0x929486,\n    0x929486,\n    0x929486,\n    0x919385,\n    0x909284,\n    0x909284,\n    0x919385,\n    0x8F9183,\n    0x8E9082,\n    0x8C8E80,\n    0x8A8C7E,\n    0x898B7D,\n    0x87897B,\n    0x858779,\n    0x828476,\n    0x828476,\n    0x818375,\n    0x7F8173,\n    0x7D7F71,\n    0x7C7E70,\n    0x7C7E70,\n    0x7D7F71,\n    0x7E8072,\n    0x797B6E,\n    0x797B6E,\n    0x787A6D,\n    0x76786B,\n    0x75776A,\n    0x737568,\n    0x727467,\n    0x727467,\n    0x797B6E,\n    0x797B6E,\n    0x787A6D,\n    0x76786B,\n    0x75776A,\n    0x737568,\n    0x727467,\n    0x727467,\n    0x6E7466,\n    0x6F7567,\n    0x71796A,\n    0x737B6C,\n    0x717E6C,\n    0x717E6C,\n    0x6D7F69,\n    0x6C7E68,\n    0x6B7E6A,\n    0x697C68,\n    0x697C69,\n    0x667966,\n    0x657666,\n    0x667669,\n    0x57675A,\n    0x3C4C3F,\n    0x000900,\n    0x000D00,\n    0x000A00,\n    0x000700,\n    0x000900,\n    0x000C00,\n    0x000900,\n    0x000700,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000C00,\n    0x000B00,\n    0x001100,\n    0x000900,\n    0x000E00,\n    0x737E6E,\n    0x828A7B,\n    0x7E8476,\n    0x868A7C,\n    0x868A7C,\n    0x86887B,\n    0x86887B,\n    0x87897C,\n    0x888A7D,\n    0x898B7E,\n    0x898B7E,\n    0x8B8D7F,\n    0x8A8C7E,\n    0x8A8C7E,\n    0x8B8D7F,\n    0x8C8E80,\n    0x8E9082,\n    0x909284,\n    0x919385,\n    0x8B8D7F,\n    0x8E9082,\n    0x929486,\n    0x959789,\n    0x959789,\n    0x959789,\n    0x959789,\n    0x959789,\n    0x96988A,\n    0x96988A,\n    0x96988A,\n    0x96988A,\n    0x959789,\n    0x949688,\n    0x949688,\n    0x939587,\n    0x848678,\n    0x858779,\n    0x858779,\n    0x858779,\n    0x858779,\n    0x858779,\n    0x848678,\n    0x838577,\n    0x848678,\n    0x848678,\n    0x86887A,\n    0x8A8C7E,\n    0x8E9082,\n    0x909284,\n    0x909284,\n    0x909284,\n    0x8F9183,\n    0x8D8F81,\n    0x8A8C7E,\n    0x87897B,\n    0x86887A,\n    0x86887A,\n    0x87897B,\n    0x87897B,\n    0x86887B,\n    0x85877A,\n    0x848679,\n    0x838578,\n    0x828477,\n    0x808275,\n    0x7F8174,\n    0x7F8174,\n    0x7E8073,\n    0x7D7F72,\n    0x7C7E71,\n    0x7B7D70,\n    0x7A7C6F,\n    0x787A6D,\n    0x77796C,\n    0x767A6C,\n    0x717769,\n    0x71796A,\n    0x717C6C,\n    0x737E6E,\n    0x727F6D,\n    0x727F6D,\n    0x6E806A,\n    0x6D7F69,\n    0x6B7E6A,\n    0x6A7D69,\n    0x6B7E6B,\n    0x687B68,\n    0x667767,\n    0x67776A,\n    0x5D6D60,\n    0x47574A,\n    0x000A00,\n    0x000B00,\n    0x000A00,\n    0x000800,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x001000,\n    0x000F00,\n    0x000A00,\n    0x021000,\n    0x7A8575,\n    0x81897A,\n    0x7D8375,\n    0x84887A,\n    0x84887A,\n    0x848679,\n    0x848679,\n    0x848679,\n    0x838578,\n    0x848679,\n    0x848679,\n    0x898B7D,\n    0x888A7C,\n    0x888A7C,\n    0x888A7C,\n    0x898B7D,\n    0x8B8D7F,\n    0x8E9082,\n    0x8F9183,\n    0x8C8E80,\n    0x8F9183,\n    0x939587,\n    0x959789,\n    0x96988A,\n    0x959789,\n    0x959789,\n    0x96988A,\n    0x96988A,\n    0x96988A,\n    0x97998B,\n    0x97998B,\n    0x96988A,\n    0x96988A,\n    0x959789,\n    0x959789,\n    0x959789,\n    0x959789,\n    0x959789,\n    0x96988A,\n    0x96988A,\n    0x96988A,\n    0x949688,\n    0x939587,\n    0x909485,\n    0x8E9283,\n    0x8E9283,\n    0x909485,\n    0x919586,\n    0x8F9384,\n    0x8D9182,\n    0x8D9182,\n    0x8F9384,\n    0x8F9384,\n    0x8E9283,\n    0x8D9182,\n    0x8C9081,\n    0x898D7E,\n    0x878B7C,\n    0x868A7B,\n    0x898B7D,\n    0x898B7D,\n    0x888A7C,\n    0x87897B,\n    0x86887A,\n    0x858779,\n    0x848678,\n    0x838577,\n    0x818375,\n    0x808274,\n    0x7F8173,\n    0x7E8072,\n    0x7D7F71,\n    0x7C7E70,\n    0x7B7D6F,\n    0x7A7E6F,\n    0x757B6D,\n    0x757D6E,\n    0x747F6F,\n    0x758070,\n    0x72816E,\n    0x72816E,\n    0x6E806A,\n    0x6E806A,\n    0x6B7E6A,\n    0x6B7E6A,\n    0x6D7E6C,\n    0x6A7B69,\n    0x657666,\n    0x67776A,\n    0x637164,\n    0x536154,\n    0x000E00,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000800,\n    0x000800,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000E00,\n    0x000D00,\n    0x000C00,\n    0x0C1A09,\n    0x859080,\n    0x889081,\n    0x868C7E,\n    0x8A8E80,\n    0x8A8E80,\n    0x8D8F82,\n    0x8E9083,\n    0x8E9083,\n    0x8D8F82,\n    0x8C8E81,\n    0x8C8E81,\n    0x8F9183,\n    0x8E9082,\n    0x8D8F81,\n    0x8D8F81,\n    0x8D8F81,\n    0x8F9183,\n    0x919385,\n    0x929486,\n    0x8C8E80,\n    0x909284,\n    0x949688,\n    0x96988A,\n    0x97998B,\n    0x96988A,\n    0x96988A,\n    0x96988A,\n    0x97998B,\n    0x97998B,\n    0x989A8C,\n    0x989A8C,\n    0x97998B,\n    0x97998B,\n    0x96988A,\n    0x96988A,\n    0x949688,\n    0x929486,\n    0x919385,\n    0x929486,\n    0x939587,\n    0x939587,\n    0x929486,\n    0x909284,\n    0x949889,\n    0x909485,\n    0x909485,\n    0x949889,\n    0x949889,\n    0x909485,\n    0x8D9182,\n    0x8D9182,\n    0x888C7D,\n    0x888C7D,\n    0x888C7D,\n    0x898D7E,\n    0x898D7E,\n    0x898D7E,\n    0x888C7D,\n    0x888C7D,\n    0x86887A,\n    0x86887A,\n    0x858779,\n    0x848678,\n    0x838577,\n    0x828476,\n    0x818375,\n    0x818375,\n    0x828476,\n    0x828476,\n    0x818375,\n    0x808274,\n    0x7F8173,\n    0x7E8072,\n    0x7D7F71,\n    0x7C8071,\n    0x788071,\n    0x768171,\n    0x758271,\n    0x758271,\n    0x73826F,\n    0x72816E,\n    0x6F816B,\n    0x6F816B,\n    0x6B7E6A,\n    0x6A7D69,\n    0x6D7E6C,\n    0x6B7C6A,\n    0x677566,\n    0x69776A,\n    0x677367,\n    0x5B675B,\n    0x051604,\n    0x000900,\n    0x000900,\n    0x000D00,\n    0x000800,\n    0x000700,\n    0x000B00,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000C00,\n    0x000D00,\n    0x000C00,\n    0x162413,\n    0x838E7E,\n    0x848C7D,\n    0x848A7C,\n    0x8A8E80,\n    0x8B8F81,\n    0x8E9083,\n    0x909285,\n    0x919386,\n    0x929487,\n    0x919386,\n    0x909285,\n    0x929486,\n    0x929486,\n    0x919385,\n    0x909284,\n    0x909284,\n    0x919385,\n    0x929486,\n    0x939587,\n    0x8D8F81,\n    0x909284,\n    0x949688,\n    0x97998B,\n    0x97998B,\n    0x97998B,\n    0x97998B,\n    0x97998B,\n    0x989A8C,\n    0x989A8C,\n    0x989A8C,\n    0x999B8D,\n    0x999B8D,\n    0x989A8C,\n    0x989A8C,\n    0x97998B,\n    0x858779,\n    0x838577,\n    0x808274,\n    0x808274,\n    0x828476,\n    0x828476,\n    0x818375,\n    0x7F8173,\n    0x727667,\n    0x6F7364,\n    0x717566,\n    0x787C6D,\n    0x7B7F70,\n    0x787C6D,\n    0x767A6B,\n    0x797D6E,\n    0x838778,\n    0x818576,\n    0x7E8273,\n    0x7D8172,\n    0x7F8374,\n    0x848879,\n    0x8A8E7F,\n    0x8D9182,\n    0x8A8C7E,\n    0x8A8C7E,\n    0x898B7D,\n    0x888A7C,\n    0x888A7C,\n    0x87897B,\n    0x86887A,\n    0x86887A,\n    0x838577,\n    0x828476,\n    0x828476,\n    0x818375,\n    0x808274,\n    0x7F8173,\n    0x7E8072,\n    0x7D8172,\n    0x7A8273,\n    0x778272,\n    0x768372,\n    0x768372,\n    0x728370,\n    0x71826F,\n    0x70826C,\n    0x70826C,\n    0x6E7F6C,\n    0x6B7C69,\n    0x6D7E6C,\n    0x6D7B6A,\n    0x687667,\n    0x6B776B,\n    0x697569,\n    0x5F6B5F,\n    0x10210F,\n    0x000A00,\n    0x000800,\n    0x000F00,\n    0x000800,\n    0x000700,\n    0x000C00,\n    0x000700,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000E00,\n    0x000A00,\n    0x000E00,\n    0x000B00,\n    0x202E1D,\n    0x7E8979,\n    0x7E8677,\n    0x7F8577,\n    0x868A7C,\n    0x868A7C,\n    0x888A7D,\n    0x8A8C7F,\n    0x8C8E81,\n    0x8D8F82,\n    0x8F9184,\n    0x8F9184,\n    0x909284,\n    0x909284,\n    0x909284,\n    0x919385,\n    0x919385,\n    0x919385,\n    0x919385,\n    0x929486,\n    0x8E9082,\n    0x919385,\n    0x959789,\n    0x97998B,\n    0x989A8C,\n    0x989A8C,\n    0x989A8C,\n    0x989A8C,\n    0x989A8C,\n    0x999B8D,\n    0x999B8D,\n    0x999B8D,\n    0x999B8D,\n    0x999B8D,\n    0x999B8D,\n    0x989A8C,\n    0x9C9E90,\n    0x989A8C,\n    0x949688,\n    0x939587,\n    0x959789,\n    0x96988A,\n    0x959789,\n    0x939587,\n    0x929989,\n    0x8D9484,\n    0x8C9383,\n    0x919888,\n    0x8F9686,\n    0x878E7E,\n    0x838A7A,\n    0x848B7B,\n    0x7F8676,\n    0x7D8474,\n    0x798070,\n    0x777E6E,\n    0x798070,\n    0x7D8474,\n    0x838A7A,\n    0x898D7E,\n    0x878B7A,\n    0x888B7A,\n    0x878A79,\n    0x878A79,\n    0x868978,\n    0x858877,\n    0x858877,\n    0x848776,\n    0x838675,\n    0x838675,\n    0x828574,\n    0x818473,\n    0x818473,\n    0x808372,\n    0x7F8271,\n    0x7E8273,\n    0x798473,\n    0x778473,\n    0x768473,\n    0x758372,\n    0x728370,\n    0x71826F,\n    0x70836D,\n    0x6F826C,\n    0x71826F,\n    0x6C7D6A,\n    0x6F7D6C,\n    0x6F7D6C,\n    0x6B7769,\n    0x6C786C,\n    0x6C766B,\n    0x616D61,\n    0x1C2A19,\n    0x000C00,\n    0x000700,\n    0x000F00,\n    0x000800,\n    0x000800,\n    0x000D00,\n    0x000700,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000E00,\n    0x000800,\n    0x001000,\n    0x000D00,\n    0x2B3928,\n    0x828D7D,\n    0x858D7E,\n    0x878D7F,\n    0x888C7E,\n    0x878B7D,\n    0x888A7D,\n    0x888A7D,\n    0x8A8C7F,\n    0x8D8F82,\n    0x909285,\n    0x929487,\n    0x909284,\n    0x909284,\n    0x919385,\n    0x939587,\n    0x939587,\n    0x939587,\n    0x939587,\n    0x939587,\n    0x8E9082,\n    0x919385,\n    0x959789,\n    0x989A8C,\n    0x989A8C,\n    0x989A8C,\n    0x989A8C,\n    0x989A8C,\n    0x999B8D,\n    0x999B8D,\n    0x999B8D,\n    0x9A9C8E,\n    0x9A9C8E,\n    0x9A9C8E,\n    0x999B8D,\n    0x999B8D,\n    0x989A8C,\n    0x939587,\n    0x8D8F81,\n    0x8C8E80,\n    0x8D8F81,\n    0x8F9183,\n    0x8E9082,\n    0x8D8F81,\n    0x8C9383,\n    0x878E7E,\n    0x899080,\n    0x929989,\n    0x949B8B,\n    0x8E9585,\n    0x8C9383,\n    0x8F9686,\n    0x8F9686,\n    0x8E9585,\n    0x8C9383,\n    0x8B9282,\n    0x8A9181,\n    0x8B9282,\n    0x8B9282,\n    0x8E9283,\n    0x898D7C,\n    0x8A8D7C,\n    0x8A8D7C,\n    0x898C7B,\n    0x888B7A,\n    0x888B7A,\n    0x878A79,\n    0x878A79,\n    0x838675,\n    0x838675,\n    0x838675,\n    0x828574,\n    0x818473,\n    0x808372,\n    0x808372,\n    0x7F8374,\n    0x798473,\n    0x778473,\n    0x768473,\n    0x758372,\n    0x728370,\n    0x71826F,\n    0x70836D,\n    0x70836D,\n    0x738471,\n    0x6D7E6B,\n    0x707E6D,\n    0x707E6D,\n    0x6D796B,\n    0x6E7A6E,\n    0x6D776C,\n    0x616D61,\n    0x22301F,\n    0x000E00,\n    0x000700,\n    0x000F00,\n    0x000800,\n    0x000800,\n    0x000E00,\n    0x000700,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000E00,\n    0x000C00,\n    0x364433,\n    0x838E80,\n    0x7F877A,\n    0x848A7E,\n    0x8C8F84,\n    0x8C8F84,\n    0x8E9085,\n    0x8E9085,\n    0x8F9183,\n    0x919385,\n    0x929486,\n    0x939587,\n    0x909284,\n    0x919385,\n    0x939587,\n    0x949688,\n    0x949688,\n    0x949688,\n    0x939587,\n    0x939587,\n    0x8D8F81,\n    0x949688,\n    0x999B8D,\n    0x9A9C8E,\n    0x999B8D,\n    0x9A9C8E,\n    0x9A9C8E,\n    0x999B8D,\n    0x9A9C8E,\n    0x9A9C8E,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x9A9C8E,\n    0x9A9C8E,\n    0x97998B,\n    0x97998B,\n    0x949688,\n    0x909284,\n    0x8F9183,\n    0x8F9183,\n    0x8D8F81,\n    0x898B7D,\n    0x85897A,\n    0x878B7C,\n    0x8B8F80,\n    0x8F9384,\n    0x929687,\n    0x939788,\n    0x929687,\n    0x929687,\n    0x919586,\n    0x919586,\n    0x919586,\n    0x8F9384,\n    0x8E9283,\n    0x8D9182,\n    0x8E9283,\n    0x909485,\n    0x8A8E7F,\n    0x898D7E,\n    0x898D7E,\n    0x888C7D,\n    0x878B7C,\n    0x878B7C,\n    0x868A7B,\n    0x868A7B,\n    0x848879,\n    0x838778,\n    0x838778,\n    0x828677,\n    0x818576,\n    0x808475,\n    0x808475,\n    0x7E8575,\n    0x788675,\n    0x768775,\n    0x758674,\n    0x748573,\n    0x748572,\n    0x738471,\n    0x73856F,\n    0x73856F,\n    0x728370,\n    0x70816E,\n    0x6F806E,\n    0x6E7F6D,\n    0x6D7E6E,\n    0x6A7A6D,\n    0x667669,\n    0x637368,\n    0x324237,\n    0x000C01,\n    0x000A00,\n    0x000700,\n    0x000F00,\n    0x000B00,\n    0x000700,\n    0x000C00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000D00,\n    0x000E00,\n    0x001200,\n    0x010F00,\n    0x3F4D3C,\n    0x869183,\n    0x838B7E,\n    0x888E82,\n    0x85887D,\n    0x85887D,\n    0x85877C,\n    0x84867B,\n    0x838577,\n    0x838577,\n    0x838577,\n    0x838577,\n    0x808274,\n    0x828476,\n    0x858779,\n    0x898B7D,\n    0x8E9082,\n    0x939587,\n    0x97998B,\n    0x999B8D,\n    0x8E9082,\n    0x959789,\n    0x9A9C8E,\n    0x9A9C8E,\n    0x999B8D,\n    0x9A9C8E,\n    0x9B9D8F,\n    0x9A9C8E,\n    0x9A9C8E,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x9A9C8E,\n    0x9D9F91,\n    0x9EA092,\n    0x9D9F91,\n    0x9B9D8F,\n    0x9A9C8E,\n    0x9A9C8E,\n    0x97998B,\n    0x929486,\n    0x929687,\n    0x949889,\n    0x95998A,\n    0x979B8C,\n    0x979B8C,\n    0x969A8B,\n    0x949889,\n    0x939788,\n    0x8F9384,\n    0x8F9384,\n    0x8F9384,\n    0x8E9283,\n    0x8E9283,\n    0x8D9182,\n    0x8C9081,\n    0x8B8F80,\n    0x8B8F80,\n    0x8B8F80,\n    0x8A8E7F,\n    0x898D7E,\n    0x888C7D,\n    0x878B7C,\n    0x878B7C,\n    0x868A7B,\n    0x888C7D,\n    0x878B7C,\n    0x878B7C,\n    0x868A7B,\n    0x85897A,\n    0x848879,\n    0x848879,\n    0x818878,\n    0x788675,\n    0x768775,\n    0x758674,\n    0x758674,\n    0x748572,\n    0x748572,\n    0x748670,\n    0x748670,\n    0x728370,\n    0x71826F,\n    0x6F806E,\n    0x6E7F6D,\n    0x6D7E6E,\n    0x6A7A6D,\n    0x67776A,\n    0x647469,\n    0x3D4D42,\n    0x000C01,\n    0x000B00,\n    0x000800,\n    0x000F00,\n    0x000A00,\n    0x000700,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000D00,\n    0x000D00,\n    0x001000,\n    0x000E00,\n    0x485645,\n    0x848F81,\n    0x848C7F,\n    0x878D81,\n    0x8C8F84,\n    0x8C8F84,\n    0x8E9085,\n    0x8F9186,\n    0x909284,\n    0x929486,\n    0x939587,\n    0x939587,\n    0x9A9C8E,\n    0x999B8D,\n    0x97998B,\n    0x949688,\n    0x939587,\n    0x939587,\n    0x939587,\n    0x939587,\n    0x8E9082,\n    0x959789,\n    0x9A9C8E,\n    0x9A9C8E,\n    0x9A9C8E,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x9A9C8E,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x9C9E90,\n    0x9C9E90,\n    0x9C9E90,\n    0x9C9E90,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x8F9183,\n    0x8F9183,\n    0x8C8E80,\n    0x888A7C,\n    0x87897B,\n    0x888A7C,\n    0x86887A,\n    0x838577,\n    0x8B8F80,\n    0x8B8F80,\n    0x8B8F80,\n    0x8A8E7F,\n    0x898D7E,\n    0x878B7C,\n    0x85897A,\n    0x848879,\n    0x929687,\n    0x909485,\n    0x8F9384,\n    0x909485,\n    0x919586,\n    0x919586,\n    0x8E9283,\n    0x8C9081,\n    0x8C9081,\n    0x8B8F80,\n    0x8A8E7F,\n    0x898D7E,\n    0x888C7D,\n    0x878B7C,\n    0x868A7B,\n    0x85897A,\n    0x848879,\n    0x848879,\n    0x838778,\n    0x828677,\n    0x818576,\n    0x818576,\n    0x808475,\n    0x7E8575,\n    0x798776,\n    0x778876,\n    0x768775,\n    0x768775,\n    0x768774,\n    0x768774,\n    0x768872,\n    0x768872,\n    0x738471,\n    0x728370,\n    0x70816F,\n    0x6F806E,\n    0x6E7F6F,\n    0x6B7B6E,\n    0x68786B,\n    0x65756A,\n    0x4C5C51,\n    0x000D02,\n    0x000A00,\n    0x000C00,\n    0x000D00,\n    0x000800,\n    0x000700,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000C00,\n    0x000B00,\n    0x000E00,\n    0x000E00,\n    0x546251,\n    0x828D7F,\n    0x858D80,\n    0x868C80,\n    0x84877C,\n    0x85887D,\n    0x888A7F,\n    0x8A8C81,\n    0x8D8F81,\n    0x8E9082,\n    0x909284,\n    0x919385,\n    0x929486,\n    0x929486,\n    0x929486,\n    0x939587,\n    0x959789,\n    0x96988A,\n    0x97998B,\n    0x989A8C,\n    0x8F9183,\n    0x96988A,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x9C9E90,\n    0x9C9E90,\n    0x9B9D8F,\n    0x9C9E90,\n    0x9C9E90,\n    0x9C9E90,\n    0x9D9F91,\n    0x9D9F91,\n    0x9C9E90,\n    0x9C9E90,\n    0x9C9E90,\n    0xA6A89A,\n    0xA3A597,\n    0x9C9E90,\n    0x959789,\n    0x949688,\n    0x97998B,\n    0x989A8C,\n    0x96988A,\n    0x969A8B,\n    0x969A8B,\n    0x969A8B,\n    0x95998A,\n    0x949889,\n    0x939788,\n    0x929687,\n    0x919586,\n    0x868A7B,\n    0x828677,\n    0x7F8374,\n    0x808475,\n    0x848879,\n    0x868A7B,\n    0x848879,\n    0x818576,\n    0x7F8374,\n    0x7E8273,\n    0x7D8172,\n    0x7C8071,\n    0x7A7E6F,\n    0x797D6E,\n    0x787C6D,\n    0x777B6C,\n    0x7F8374,\n    0x7F8374,\n    0x7E8273,\n    0x7D8172,\n    0x7C8071,\n    0x7C8071,\n    0x7B7F70,\n    0x798070,\n    0x768473,\n    0x738472,\n    0x738472,\n    0x738472,\n    0x738471,\n    0x738471,\n    0x748670,\n    0x748670,\n    0x748572,\n    0x738471,\n    0x718270,\n    0x718270,\n    0x6F8070,\n    0x6D7D70,\n    0x69796C,\n    0x66766B,\n    0x59695E,\n    0x000D02,\n    0x000900,\n    0x000E00,\n    0x000C00,\n    0x000700,\n    0x000A00,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000E00,\n    0x000C00,\n    0x001000,\n    0x021000,\n    0x647261,\n    0x838E80,\n    0x8A9285,\n    0x888E82,\n    0x8A8D82,\n    0x8B8E83,\n    0x8C8E83,\n    0x8D8F84,\n    0x8D8F81,\n    0x8D8F81,\n    0x8C8E80,\n    0x8C8E80,\n    0x86887A,\n    0x888A7C,\n    0x8D8F81,\n    0x929486,\n    0x96988A,\n    0x989A8C,\n    0x999B8D,\n    0x999B8D,\n    0x909284,\n    0x97998B,\n    0x9C9E90,\n    0x9C9E90,\n    0x9B9D8F,\n    0x9D9F91,\n    0x9D9F91,\n    0x9C9E90,\n    0x9C9E90,\n    0x9D9F91,\n    0x9D9F91,\n    0x9D9F91,\n    0x9D9F91,\n    0x9D9F91,\n    0x9D9F91,\n    0x9C9E90,\n    0x9A9C8E,\n    0x989A8C,\n    0x939587,\n    0x8E9082,\n    0x8D8F81,\n    0x909284,\n    0x919385,\n    0x8F9183,\n    0x8C9081,\n    0x8B8F80,\n    0x8B8F80,\n    0x8B8F80,\n    0x8A8E7F,\n    0x898D7E,\n    0x898D7E,\n    0x888C7D,\n    0x939788,\n    0x8E9283,\n    0x8A8E7F,\n    0x8B8F80,\n    0x8F9384,\n    0x939788,\n    0x939788,\n    0x929687,\n    0x919586,\n    0x909485,\n    0x8F9384,\n    0x8E9283,\n    0x8C9081,\n    0x8B8F80,\n    0x8A8E7F,\n    0x898D7E,\n    0x838778,\n    0x828677,\n    0x828677,\n    0x818576,\n    0x808475,\n    0x7F8374,\n    0x7F8374,\n    0x7D8474,\n    0x738170,\n    0x718270,\n    0x70816F,\n    0x70816F,\n    0x70816E,\n    0x71826F,\n    0x71836D,\n    0x71836D,\n    0x758673,\n    0x748572,\n    0x738472,\n    0x728371,\n    0x718272,\n    0x6F7F72,\n    0x6B7B6E,\n    0x68786D,\n    0x617166,\n    0x011106,\n    0x000900,\n    0x000C00,\n    0x000B00,\n    0x000800,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000E00,\n    0x000B00,\n    0x000E00,\n    0x010F00,\n    0x707E6D,\n    0x818C7E,\n    0x8B9386,\n    0x878D81,\n    0x8F9287,\n    0x909388,\n    0x93958A,\n    0x94968B,\n    0x959789,\n    0x959789,\n    0x949688,\n    0x949688,\n    0x929486,\n    0x949688,\n    0x97998B,\n    0x999B8D,\n    0x9A9C8E,\n    0x989A8C,\n    0x959789,\n    0x939587,\n    0x919385,\n    0x97998B,\n    0x9D9F91,\n    0x9D9F91,\n    0x9C9E90,\n    0x9D9F91,\n    0x9EA092,\n    0x9D9F91,\n    0x9D9F91,\n    0x9D9F91,\n    0x9EA092,\n    0x9EA092,\n    0x9EA092,\n    0x9EA092,\n    0x9D9F91,\n    0x9D9F91,\n    0x9B9D8F,\n    0x9C9E90,\n    0x9C9E90,\n    0x9A9C8E,\n    0x9B9D8F,\n    0x9EA092,\n    0x9C9E90,\n    0x989A8C,\n    0x979B8C,\n    0x979B8C,\n    0x979B8C,\n    0x969A8B,\n    0x95998A,\n    0x949889,\n    0x929687,\n    0x919586,\n    0x8D9182,\n    0x8A8E7F,\n    0x878B7C,\n    0x868A7B,\n    0x898D7E,\n    0x8C9081,\n    0x8D9182,\n    0x8D9182,\n    0x8C9081,\n    0x8C9081,\n    0x8B8F80,\n    0x8A8E7F,\n    0x898D7E,\n    0x878B7C,\n    0x878B7C,\n    0x868A7B,\n    0x888C7D,\n    0x878B7C,\n    0x878B7C,\n    0x868A7B,\n    0x85897A,\n    0x848879,\n    0x848879,\n    0x818878,\n    0x7A8877,\n    0x778876,\n    0x778876,\n    0x768775,\n    0x768774,\n    0x778875,\n    0x778973,\n    0x778973,\n    0x768774,\n    0x758673,\n    0x748573,\n    0x738472,\n    0x728373,\n    0x708073,\n    0x6D7D70,\n    0x6A7A6F,\n    0x647469,\n    0x0A1A0F,\n    0x000C00,\n    0x000800,\n    0x000B00,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000D00,\n    0x000900,\n    0x000D00,\n    0x010F00,\n    0x798776,\n    0x808B7D,\n    0x8B9386,\n    0x868C80,\n    0x82857A,\n    0x83867B,\n    0x87897E,\n    0x898B80,\n    0x8B8D7F,\n    0x8C8E80,\n    0x8C8E80,\n    0x8C8E80,\n    0x8B8D7F,\n    0x8D8F81,\n    0x919385,\n    0x959789,\n    0x97998B,\n    0x989A8C,\n    0x989A8C,\n    0x989A8C,\n    0x919385,\n    0x989A8C,\n    0x9D9F91,\n    0x9D9F91,\n    0x9D9F91,\n    0x9EA092,\n    0x9EA092,\n    0x9D9F91,\n    0x9EA092,\n    0x9EA092,\n    0x9EA092,\n    0x9FA193,\n    0x9FA193,\n    0x9EA092,\n    0x9EA092,\n    0x9EA092,\n    0xA0A294,\n    0xA0A294,\n    0x9EA092,\n    0x9B9D8F,\n    0x9C9E90,\n    0x9FA193,\n    0x9FA193,\n    0x9D9F91,\n    0x989C8D,\n    0x999D8E,\n    0x9A9E8F,\n    0x9A9E8F,\n    0x999D8E,\n    0x979B8C,\n    0x95998A,\n    0x939788,\n    0x95998A,\n    0x949889,\n    0x949889,\n    0x939788,\n    0x939788,\n    0x939788,\n    0x929687,\n    0x929687,\n    0x919586,\n    0x909485,\n    0x909485,\n    0x8F9384,\n    0x8E9283,\n    0x8D9182,\n    0x8C9081,\n    0x8C9081,\n    0x898D7E,\n    0x898D7E,\n    0x888C7D,\n    0x888C7D,\n    0x878B7C,\n    0x868A7B,\n    0x85897A,\n    0x838A7A,\n    0x808E7D,\n    0x7D8E7C,\n    0x7D8E7C,\n    0x7C8D7B,\n    0x7C8D7A,\n    0x7B8C79,\n    0x7C8E78,\n    0x7C8E78,\n    0x768774,\n    0x758673,\n    0x748573,\n    0x748573,\n    0x738474,\n    0x718174,\n    0x6E7E71,\n    0x6B7B70,\n    0x66766B,\n    0x16261B,\n    0x011202,\n    0x000700,\n    0x000C00,\n    0x000B00,\n    0x000700,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x001100,\n    0x000C00,\n    0x001000,\n    0x041201,\n    0x82907F,\n    0x838E80,\n    0x90988B,\n    0x898F83,\n    0x93968B,\n    0x94978C,\n    0x96988D,\n    0x97998E,\n    0x97998B,\n    0x959789,\n    0x949688,\n    0x939587,\n    0x959789,\n    0x96988A,\n    0x97998B,\n    0x989A8C,\n    0x999B8D,\n    0x9A9C8E,\n    0x9A9C8E,\n    0x9A9C8E,\n    0x929486,\n    0x989A8C,\n    0x9EA092,\n    0x9EA092,\n    0x9D9F91,\n    0x9EA092,\n    0x9FA193,\n    0x9D9F91,\n    0x9EA092,\n    0x9EA092,\n    0x9FA193,\n    0x9FA193,\n    0x9FA193,\n    0x9FA193,\n    0x9EA092,\n    0x9EA092,\n    0x949688,\n    0x909284,\n    0x87897B,\n    0x7F8173,\n    0x7E8072,\n    0x848678,\n    0x888A7C,\n    0x898B7D,\n    0x8F9384,\n    0x919586,\n    0x939788,\n    0x95998A,\n    0x95998A,\n    0x939788,\n    0x919586,\n    0x909485,\n    0x949889,\n    0x969A8B,\n    0x979B8C,\n    0x979B8C,\n    0x949889,\n    0x919586,\n    0x8F9384,\n    0x8E9283,\n    0x8F9384,\n    0x8F9384,\n    0x8E9283,\n    0x8E9283,\n    0x8D9182,\n    0x8C9081,\n    0x8C9081,\n    0x8B8F80,\n    0x8B8F80,\n    0x8B8F80,\n    0x8A8E7F,\n    0x898D7E,\n    0x898D7E,\n    0x888C7D,\n    0x878B7C,\n    0x858C7C,\n    0x7E8C7B,\n    0x7B8C7A,\n    0x7A8B79,\n    0x798A78,\n    0x798A77,\n    0x788976,\n    0x788A74,\n    0x788A74,\n    0x778875,\n    0x768774,\n    0x758674,\n    0x758674,\n    0x748575,\n    0x728275,\n    0x6E7E71,\n    0x6C7C71,\n    0x67776C,\n    0x1F2F24,\n    0x061707,\n    0x000700,\n    0x000E00,\n    0x000C00,\n    0x000700,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000E00,\n    0x000800,\n    0x031100,\n    0x0E1B0A,\n    0x838E7E,\n    0x888E80,\n    0x81877B,\n    0x85887D,\n    0x8B8D82,\n    0x8D8F84,\n    0x909189,\n    0x91928A,\n    0x92938B,\n    0x94958D,\n    0x949790,\n    0x969990,\n    0x8F9587,\n    0x929989,\n    0x929989,\n    0x919888,\n    0x95998A,\n    0x999D8E,\n    0x9A9E8F,\n    0x999D8E,\n    0x929687,\n    0x999D8E,\n    0x9FA193,\n    0x9EA092,\n    0x9EA092,\n    0x9FA193,\n    0xA0A294,\n    0x9FA193,\n    0xA1A395,\n    0xA1A395,\n    0xA1A395,\n    0xA1A395,\n    0xA1A395,\n    0xA1A395,\n    0xA1A395,\n    0xA1A395,\n    0x9C9E90,\n    0x9A9C8E,\n    0x989A8C,\n    0x96988A,\n    0x939587,\n    0x8F9183,\n    0x8B8D7F,\n    0x888A7C,\n    0x848879,\n    0x818576,\n    0x838778,\n    0x878B7C,\n    0x838778,\n    0x7C8071,\n    0x7E8273,\n    0x868A7B,\n    0x818576,\n    0x848879,\n    0x7D8172,\n    0x707465,\n    0x727667,\n    0x7F8374,\n    0x7E8273,\n    0x6F7666,\n    0x6F7A69,\n    0x75806F,\n    0x7B8473,\n    0x7E8273,\n    0x828476,\n    0x8A8B7D,\n    0x8E9082,\n    0x8E9283,\n    0x8B9282,\n    0x889180,\n    0x85907F,\n    0x868F7E,\n    0x868F7E,\n    0x898D7E,\n    0x8A8B7D,\n    0x888A7C,\n    0x818C7B,\n    0x7E8D7A,\n    0x7D8C79,\n    0x7C8B78,\n    0x7B8A77,\n    0x7B8A77,\n    0x7C8977,\n    0x7C8977,\n    0x7C8977,\n    0x7B8876,\n    0x798674,\n    0x798674,\n    0x788573,\n    0x778472,\n    0x74816F,\n    0x727F6D,\n    0x6B7C6A,\n    0x2F402E,\n    0x021301,\n    0x000900,\n    0x000900,\n    0x000700,\n    0x000D00,\n    0x000700,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000700,\n    0x021000,\n    0x162312,\n    0x889383,\n    0x8F9587,\n    0x8B9185,\n    0x909388,\n    0x8D8F84,\n    0x8E9085,\n    0x8E8F87,\n    0x8D8E86,\n    0x8B8C84,\n    0x8A8B83,\n    0x888B82,\n    0x898C81,\n    0x858B7D,\n    0x888F7F,\n    0x8A9181,\n    0x8A9181,\n    0x8E9283,\n    0x939788,\n    0x969A8B,\n    0x95998A,\n    0x939788,\n    0x999D8E,\n    0x9FA193,\n    0x9FA193,\n    0x9EA092,\n    0x9FA193,\n    0xA0A294,\n    0x9FA193,\n    0xA1A395,\n    0xA1A395,\n    0xA1A395,\n    0xA1A395,\n    0xA1A395,\n    0xA1A395,\n    0xA1A395,\n    0xA1A395,\n    0x9D9F91,\n    0x9C9E90,\n    0x9EA092,\n    0xA2A496,\n    0xA5A799,\n    0xA4A698,\n    0x9EA092,\n    0x989A8C,\n    0x9DA192,\n    0x9B9F90,\n    0x9DA192,\n    0xA1A596,\n    0x9FA394,\n    0x999D8E,\n    0x9B9F90,\n    0xA2A697,\n    0x969A8B,\n    0x999D8E,\n    0x95998A,\n    0x8F9384,\n    0x919586,\n    0x989C8D,\n    0x949889,\n    0x868D7D,\n    0x7D8877,\n    0x818C7B,\n    0x858E7D,\n    0x85897A,\n    0x87897B,\n    0x8C8D7F,\n    0x8E9283,\n    0x8D9484,\n    0x899281,\n    0x85907F,\n    0x82917E,\n    0x828F7D,\n    0x838E7D,\n    0x868D7D,\n    0x878B7C,\n    0x848B7B,\n    0x83907E,\n    0x7F907D,\n    0x81907D,\n    0x808F7C,\n    0x7F8E7B,\n    0x7F8E7B,\n    0x7E8D7A,\n    0x7E8D7A,\n    0x7B8A77,\n    0x7A8976,\n    0x798875,\n    0x788774,\n    0x788774,\n    0x768572,\n    0x73826F,\n    0x71806D,\n    0x6B7C6A,\n    0x3B4C3A,\n    0x000F00,\n    0x000B00,\n    0x000A00,\n    0x000900,\n    0x000C00,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x000A00,\n    0x021000,\n    0x202D1C,\n    0x879282,\n    0x8D9385,\n    0x888E80,\n    0x8E9284,\n    0x97998E,\n    0x989A8F,\n    0x9A9C91,\n    0x9A9C91,\n    0x9A9C91,\n    0x999B90,\n    0x999C93,\n    0x9A9D92,\n    0x979D8F,\n    0x99A090,\n    0x99A090,\n    0x969D8D,\n    0x979B8C,\n    0x9A9E8F,\n    0x9A9E8F,\n    0x989C8D,\n    0x939788,\n    0x9A9E8F,\n    0x9FA193,\n    0x9FA193,\n    0x9FA193,\n    0xA0A294,\n    0xA1A395,\n    0xA0A294,\n    0xA2A496,\n    0xA2A496,\n    0xA2A496,\n    0xA2A496,\n    0xA2A496,\n    0xA2A496,\n    0xA2A496,\n    0xA2A496,\n    0xA5A799,\n    0x9A9C8E,\n    0x8C8E80,\n    0x858779,\n    0x86887A,\n    0x8A8C7E,\n    0x8C8E80,\n    0x8B8D7F,\n    0x8B8F80,\n    0x898D7E,\n    0x8B8F80,\n    0x8F9384,\n    0x8D9182,\n    0x898D7E,\n    0x8B8F80,\n    0x919586,\n    0x969A8B,\n    0x95998A,\n    0x929687,\n    0x919586,\n    0x939788,\n    0x95998A,\n    0x919586,\n    0x899080,\n    0x8A9382,\n    0x8C9584,\n    0x8C9383,\n    0x8B8D7F,\n    0x8A8C7E,\n    0x8E8F81,\n    0x8E9283,\n    0x8D9484,\n    0x8A9584,\n    0x889583,\n    0x839481,\n    0x829380,\n    0x859481,\n    0x869381,\n    0x869180,\n    0x848F7E,\n    0x81907D,\n    0x7F907D,\n    0x7F907D,\n    0x7E8F7C,\n    0x7D8E7B,\n    0x7C8D7A,\n    0x7B8C79,\n    0x7A8B78,\n    0x7A8B78,\n    0x798A77,\n    0x788976,\n    0x778875,\n    0x778875,\n    0x758673,\n    0x728370,\n    0x70816E,\n    0x6B7C6A,\n    0x4D5E4C,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000B00,\n    0x000C00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000D00,\n    0x000C00,\n    0x010F00,\n    0x2C3928,\n    0x869181,\n    0x8A9082,\n    0x858B7D,\n    0x8C9082,\n    0x808275,\n    0x838578,\n    0x86887B,\n    0x888A7D,\n    0x898B80,\n    0x8A8C81,\n    0x8C8F84,\n    0x8D9085,\n    0x878E7E,\n    0x8A9181,\n    0x8C9383,\n    0x8D9484,\n    0x929687,\n    0x989C8D,\n    0x9B9F90,\n    0x9A9E8F,\n    0x949889,\n    0x9A9E8F,\n    0xA0A294,\n    0xA0A294,\n    0x9FA193,\n    0xA1A395,\n    0xA2A496,\n    0xA1A395,\n    0xA2A496,\n    0xA2A496,\n    0xA2A496,\n    0xA2A496,\n    0xA2A496,\n    0xA2A496,\n    0xA2A496,\n    0xA2A496,\n    0xA1A395,\n    0x9FA193,\n    0x9D9F91,\n    0x9FA193,\n    0xA1A395,\n    0xA1A395,\n    0x9C9E90,\n    0x989A8C,\n    0x95998A,\n    0x949889,\n    0x95998A,\n    0x979B8C,\n    0x969A8B,\n    0x929687,\n    0x949889,\n    0x989C8D,\n    0x8D9182,\n    0x878B7C,\n    0x828677,\n    0x838778,\n    0x85897A,\n    0x85897A,\n    0x848879,\n    0x85897A,\n    0x87907F,\n    0x878E7E,\n    0x858C7C,\n    0x86887A,\n    0x858779,\n    0x87897B,\n    0x888C7D,\n    0x87907F,\n    0x869381,\n    0x81927F,\n    0x7F927E,\n    0x7E917D,\n    0x7E917D,\n    0x81907D,\n    0x808F7C,\n    0x7F8E7B,\n    0x7E8F7C,\n    0x7D907C,\n    0x7E917D,\n    0x7D907C,\n    0x7D907C,\n    0x7B8E7A,\n    0x7A8D79,\n    0x798C78,\n    0x7A8D79,\n    0x798C78,\n    0x768C77,\n    0x758B76,\n    0x758B76,\n    0x738974,\n    0x708671,\n    0x70836F,\n    0x697C69,\n    0x5E6F5D,\n    0x000A00,\n    0x000C00,\n    0x000D00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000D00,\n    0x000D00,\n    0x3C4938,\n    0x8A9585,\n    0x8F9587,\n    0x8B9183,\n    0x939789,\n    0x989A8D,\n    0x9A9C8F,\n    0x9B9D90,\n    0x9B9D90,\n    0x9A9C8E,\n    0x9A9C8E,\n    0x9A9E8F,\n    0x9A9E8F,\n    0x909787,\n    0x929989,\n    0x939A8A,\n    0x919888,\n    0x95998A,\n    0x989C8D,\n    0x999D8E,\n    0x989C8D,\n    0x95998A,\n    0x9B9F90,\n    0xA1A395,\n    0xA1A395,\n    0xA0A294,\n    0xA2A496,\n    0xA2A496,\n    0xA2A496,\n    0xA3A597,\n    0xA3A597,\n    0xA3A597,\n    0xA3A597,\n    0xA3A597,\n    0xA3A597,\n    0xA3A597,\n    0xA3A597,\n    0xA1A395,\n    0xA2A496,\n    0xA2A496,\n    0xA1A395,\n    0x9FA193,\n    0x9D9F91,\n    0x9C9E90,\n    0x9C9E90,\n    0x9CA091,\n    0x9B9F90,\n    0x9B9F90,\n    0x9CA091,\n    0x9B9F90,\n    0x989C8D,\n    0x989C8D,\n    0x9A9E8F,\n    0xA0A495,\n    0x9A9E8F,\n    0x969A8B,\n    0x989C8D,\n    0x999D8E,\n    0x979B8C,\n    0x979B8C,\n    0x9A9E8F,\n    0x909988,\n    0x8F9686,\n    0x8E9283,\n    0x8F9183,\n    0x909183,\n    0x909183,\n    0x8F9384,\n    0x8E9585,\n    0x8A9785,\n    0x879683,\n    0x839682,\n    0x829581,\n    0x839481,\n    0x859481,\n    0x859280,\n    0x84917F,\n    0x82917E,\n    0x81927F,\n    0x81927F,\n    0x81927F,\n    0x80917E,\n    0x7F907D,\n    0x7D907C,\n    0x7D907C,\n    0x7B8E7A,\n    0x7A8D79,\n    0x778D78,\n    0x768C77,\n    0x768C77,\n    0x748A75,\n    0x708872,\n    0x6F8570,\n    0x6A7D6A,\n    0x677866,\n    0x001100,\n    0x000C00,\n    0x000C00,\n    0x000B00,\n    0x000800,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x001000,\n    0x000C00,\n    0x485544,\n    0x899484,\n    0x8C9284,\n    0x888E80,\n    0x919587,\n    0x959789,\n    0x96988A,\n    0x989A8C,\n    0x97998B,\n    0x96988A,\n    0x96988A,\n    0x959988,\n    0x969A89,\n    0x9DA494,\n    0x9EA595,\n    0x9DA494,\n    0x99A090,\n    0x9A9E8F,\n    0x9B9F90,\n    0x9B9F90,\n    0x989C8D,\n    0x95998A,\n    0x9CA091,\n    0xA2A496,\n    0xA2A496,\n    0xA1A395,\n    0xA2A496,\n    0xA3A597,\n    0xA2A496,\n    0xA3A597,\n    0xA3A597,\n    0xA3A597,\n    0xA3A597,\n    0xA3A597,\n    0xA3A597,\n    0xA3A597,\n    0xA3A597,\n    0xA7A99B,\n    0xA1A395,\n    0x959789,\n    0x898B7D,\n    0x828476,\n    0x848678,\n    0x8D8F81,\n    0x959789,\n    0x8F9384,\n    0x8E9283,\n    0x8E9283,\n    0x8D9182,\n    0x8C9081,\n    0x8B8F80,\n    0x8A8E7F,\n    0x8A8E7F,\n    0x8D9182,\n    0x8B8F80,\n    0x8C9081,\n    0x8E9283,\n    0x8F9384,\n    0x8C9081,\n    0x888C7D,\n    0x878B7C,\n    0x949D8C,\n    0x919888,\n    0x909485,\n    0x939486,\n    0x929385,\n    0x929083,\n    0x8E9082,\n    0x8E9283,\n    0x8B9483,\n    0x879281,\n    0x849380,\n    0x84917F,\n    0x84917F,\n    0x87907F,\n    0x868F7E,\n    0x858E7D,\n    0x828D7C,\n    0x818E7C,\n    0x7F8E7B,\n    0x7F8E7B,\n    0x7F8E7B,\n    0x7F8E7B,\n    0x7E8F7C,\n    0x7E8F7C,\n    0x7C8F7B,\n    0x7B8E7A,\n    0x7A8D79,\n    0x798C78,\n    0x778D78,\n    0x758B76,\n    0x728873,\n    0x728571,\n    0x6D806D,\n    0x687967,\n    0x0E1F0D,\n    0x000B00,\n    0x000A00,\n    0x000B00,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x011202,\n    0x000C00,\n    0x525F4E,\n    0x889383,\n    0x8A9082,\n    0x858C7C,\n    0x8F9384,\n    0x87897B,\n    0x898B7D,\n    0x8C8F7E,\n    0x8D907F,\n    0x8D907F,\n    0x8E9180,\n    0x8E9281,\n    0x909483,\n    0x818878,\n    0x858C7C,\n    0x888F7F,\n    0x899080,\n    0x909485,\n    0x969A8B,\n    0x9A9E8F,\n    0x9A9E8F,\n    0x969A8B,\n    0x9CA091,\n    0xA2A496,\n    0xA2A496,\n    0xA1A395,\n    0xA3A597,\n    0xA4A698,\n    0xA3A597,\n    0xA4A698,\n    0xA4A698,\n    0xA4A698,\n    0xA4A698,\n    0xA4A698,\n    0xA4A698,\n    0xA4A698,\n    0xA4A698,\n    0xA1A395,\n    0xA3A597,\n    0xA4A698,\n    0xA5A799,\n    0xA4A698,\n    0xA4A698,\n    0xA4A698,\n    0xA5A799,\n    0x9FA394,\n    0x9FA394,\n    0x9EA293,\n    0x9DA192,\n    0x9DA192,\n    0x9DA192,\n    0x9CA091,\n    0x9B9F90,\n    0x939788,\n    0x95998A,\n    0x969A8B,\n    0x95998A,\n    0x95998A,\n    0x95998A,\n    0x919586,\n    0x8D9182,\n    0x8A9382,\n    0x868D7D,\n    0x868A7B,\n    0x8A8B7D,\n    0x8A8B7D,\n    0x888679,\n    0x848577,\n    0x838577,\n    0x848879,\n    0x818878,\n    0x7C8776,\n    0x7D8675,\n    0x7E8776,\n    0x818576,\n    0x818274,\n    0x808173,\n    0x818A79,\n    0x7E8978,\n    0x7D8877,\n    0x7C8776,\n    0x7C8977,\n    0x7D8A78,\n    0x7E8D7A,\n    0x808F7C,\n    0x7E8F7C,\n    0x7D8E7B,\n    0x7B8E7A,\n    0x7A8D79,\n    0x7A8D79,\n    0x788B77,\n    0x738974,\n    0x738672,\n    0x718471,\n    0x657664,\n    0x1F301E,\n    0x000C00,\n    0x000A00,\n    0x000B00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000900,\n    0x001101,\n    0x000B00,\n    0x5A6756,\n    0x8D9888,\n    0x919789,\n    0x8E9585,\n    0x999D8E,\n    0x97998B,\n    0x999B8D,\n    0x9B9E8D,\n    0x9B9E8D,\n    0x9B9E8D,\n    0x9B9E8D,\n    0x9A9F8B,\n    0x9CA08F,\n    0x9BA290,\n    0x9CA393,\n    0x9BA292,\n    0x989F8F,\n    0x9A9E8F,\n    0x9CA091,\n    0x9CA091,\n    0x9A9E8F,\n    0x969A8B,\n    0x9DA192,\n    0xA3A597,\n    0xA3A597,\n    0xA2A496,\n    0xA3A597,\n    0xA4A698,\n    0xA3A597,\n    0xA4A698,\n    0xA4A698,\n    0xA4A698,\n    0xA4A698,\n    0xA4A698,\n    0xA4A698,\n    0xA4A698,\n    0xA4A698,\n    0xA2A496,\n    0x9EA092,\n    0x999B8D,\n    0x959789,\n    0x959789,\n    0x96988A,\n    0x96988A,\n    0x96988A,\n    0x9CA091,\n    0x9CA091,\n    0x9B9F90,\n    0x9B9F90,\n    0x9B9F90,\n    0x9CA091,\n    0x9CA091,\n    0x9A9E8F,\n    0x9CA091,\n    0x9EA293,\n    0x9CA091,\n    0x969A8B,\n    0x95998A,\n    0x999D8E,\n    0x9A9E8F,\n    0x969A8B,\n    0x949D8C,\n    0x919888,\n    0x929687,\n    0x98998B,\n    0x9B998C,\n    0x989488,\n    0x949285,\n    0x929385,\n    0x929486,\n    0x8F9384,\n    0x8B9282,\n    0x8D9182,\n    0x8E9082,\n    0x918F82,\n    0x918D81,\n    0x8F8D80,\n    0x868A7B,\n    0x818A79,\n    0x808978,\n    0x7F8877,\n    0x7E8978,\n    0x808B7A,\n    0x828F7D,\n    0x84917F,\n    0x808F7C,\n    0x7F8E7B,\n    0x7C8D7A,\n    0x7B8C79,\n    0x7A8D79,\n    0x788B77,\n    0x768975,\n    0x738672,\n    0x758674,\n    0x627361,\n    0x2A3B29,\n    0x000C00,\n    0x000A00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000E00,\n    0x000D00,\n    0x000D00,\n    0x657261,\n    0x889383,\n    0x848A7C,\n    0x848B7B,\n    0x888C7D,\n    0x8F9183,\n    0x8F9183,\n    0x919385,\n    0x929486,\n    0x939685,\n    0x949786,\n    0x949887,\n    0x949887,\n    0x9A9C8E,\n    0x9C9E90,\n    0x9D9F91,\n    0x9C9E90,\n    0x9C9E90,\n    0x9EA092,\n    0x9D9F91,\n    0x9A9C8E,\n    0x999B8D,\n    0x9FA193,\n    0xA3A597,\n    0xA2A496,\n    0xA2A496,\n    0xA3A597,\n    0xA4A698,\n    0xA3A597,\n    0xA3A597,\n    0xA4A698,\n    0xA4A698,\n    0xA4A698,\n    0xA4A698,\n    0xA5A799,\n    0xA5A799,\n    0xA5A799,\n    0xA5A799,\n    0xA4A698,\n    0xA1A395,\n    0x9EA092,\n    0x9A9C8E,\n    0x96988A,\n    0x939587,\n    0x919385,\n    0x95998A,\n    0x969A8B,\n    0x939788,\n    0x8E9283,\n    0x8D9182,\n    0x909485,\n    0x929687,\n    0x919586,\n    0x8A8E7F,\n    0x898D7E,\n    0x898D7E,\n    0x898D7E,\n    0x8A8E7F,\n    0x8A8E7F,\n    0x898D7E,\n    0x878B7C,\n    0x8F9183,\n    0x919385,\n    0x949688,\n    0x949688,\n    0x939587,\n    0x929486,\n    0x929486,\n    0x929486,\n    0x919385,\n    0x919385,\n    0x919385,\n    0x919385,\n    0x909284,\n    0x8E9082,\n    0x8D8F81,\n    0x8C8E80,\n    0x888E80,\n    0x898F81,\n    0x879282,\n    0x869181,\n    0x82907F,\n    0x818F7E,\n    0x80917F,\n    0x819280,\n    0x7D907D,\n    0x7D907D,\n    0x7D907D,\n    0x7C8F7C,\n    0x7B8E7B,\n    0x798C79,\n    0x788977,\n    0x778878,\n    0x708075,\n    0x6D7D73,\n    0x35453A,\n    0x000B00,\n    0x000F00,\n    0x000700,\n    0x000700,\n    0x000C00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000E00,\n    0x001000,\n    0x031102,\n    0x737F71,\n    0x8F9A8C,\n    0x8E9488,\n    0x8E9486,\n    0x979B8D,\n    0x96988B,\n    0x96988B,\n    0x96988B,\n    0x97998C,\n    0x96988A,\n    0x96988A,\n    0x95998A,\n    0x949889,\n    0x9D9F91,\n    0xA0A294,\n    0xA0A294,\n    0x9EA092,\n    0x9D9F91,\n    0x9FA193,\n    0x9D9F91,\n    0x9A9C8E,\n    0x999B8D,\n    0x9FA193,\n    0xA4A698,\n    0xA3A597,\n    0xA2A496,\n    0xA3A597,\n    0xA4A698,\n    0xA4A698,\n    0xA4A698,\n    0xA4A698,\n    0xA4A698,\n    0xA4A698,\n    0xA5A799,\n    0xA5A799,\n    0xA5A799,\n    0xA5A799,\n    0xA0A294,\n    0xA1A395,\n    0xA3A597,\n    0xA4A698,\n    0xA6A89A,\n    0xA7A99B,\n    0xA7A99B,\n    0xA7A99B,\n    0xA2A697,\n    0xA4A899,\n    0xA3A798,\n    0xA0A495,\n    0x9FA394,\n    0xA1A596,\n    0xA1A596,\n    0x9EA293,\n    0x9FA394,\n    0x9EA293,\n    0x9EA293,\n    0x9EA293,\n    0x9FA394,\n    0x9FA394,\n    0x9EA293,\n    0x9DA192,\n    0x97998B,\n    0x989A8C,\n    0x999B8D,\n    0x9A9C8E,\n    0x9A9C8E,\n    0x999B8D,\n    0x989A8C,\n    0x96988A,\n    0x919385,\n    0x919385,\n    0x909284,\n    0x909284,\n    0x909284,\n    0x8F9183,\n    0x8F9183,\n    0x8E9283,\n    0x8C9284,\n    0x8C9485,\n    0x8A9585,\n    0x889383,\n    0x849281,\n    0x82907F,\n    0x80917F,\n    0x80917F,\n    0x7D907D,\n    0x7D907D,\n    0x7D907D,\n    0x7C8F7C,\n    0x7C8D7B,\n    0x7A8B79,\n    0x7A8877,\n    0x798778,\n    0x728277,\n    0x6F7F75,\n    0x3E4E43,\n    0x000A00,\n    0x001000,\n    0x000700,\n    0x000A00,\n    0x000B00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000E01,\n    0x021003,\n    0x7E8A7E,\n    0x8D978C,\n    0x8F958B,\n    0x8B9187,\n    0x999C93,\n    0x9B9D92,\n    0x9B9D92,\n    0x9B9D92,\n    0x9B9D92,\n    0x9B9D90,\n    0x9A9C8F,\n    0x989C8E,\n    0x989C8E,\n    0x989A8C,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x9A9C8E,\n    0x9A9C8E,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x989A8C,\n    0x9A9C8E,\n    0xA0A294,\n    0xA4A698,\n    0xA3A597,\n    0xA2A496,\n    0xA4A698,\n    0xA5A799,\n    0xA4A698,\n    0xA4A698,\n    0xA4A698,\n    0xA5A799,\n    0xA5A799,\n    0xA5A799,\n    0xA5A799,\n    0xA6A89A,\n    0xA6A89A,\n    0xA9AB9D,\n    0xA8AA9C,\n    0xA5A799,\n    0xA2A496,\n    0x9D9F91,\n    0x999B8D,\n    0x96988A,\n    0x949688,\n    0x9A9E8F,\n    0x9EA293,\n    0xA0A495,\n    0x9EA293,\n    0x9EA293,\n    0x9EA293,\n    0x9CA091,\n    0x989C8D,\n    0x9CA091,\n    0x9B9F90,\n    0x999D8E,\n    0x999D8E,\n    0x999D8E,\n    0x989C8D,\n    0x969A8B,\n    0x95998A,\n    0x97998B,\n    0x959789,\n    0x949688,\n    0x959789,\n    0x97998B,\n    0x97998B,\n    0x949688,\n    0x919385,\n    0x929486,\n    0x919385,\n    0x909284,\n    0x909284,\n    0x909284,\n    0x909284,\n    0x919385,\n    0x919586,\n    0x868E7F,\n    0x859080,\n    0x849180,\n    0x83907F,\n    0x808E7D,\n    0x7F8D7C,\n    0x7D8E7C,\n    0x7E8F7D,\n    0x7F907E,\n    0x7F907E,\n    0x7F907E,\n    0x808E7D,\n    0x7F8D7C,\n    0x7E8B7A,\n    0x7C8978,\n    0x7B8779,\n    0x748479,\n    0x718177,\n    0x4C5C51,\n    0x000900,\n    0x001101,\n    0x000700,\n    0x000F00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000D02,\n    0x000D03,\n    0x849086,\n    0x889289,\n    0x8D928B,\n    0x83897F,\n    0x91948B,\n    0x8B8C84,\n    0x8C8D85,\n    0x8D8E86,\n    0x8D8E86,\n    0x8E9085,\n    0x8E9085,\n    0x8D9085,\n    0x8D9085,\n    0x919385,\n    0x949688,\n    0x96988A,\n    0x96988A,\n    0x989A8C,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x999B8D,\n    0x9B9D8F,\n    0xA1A395,\n    0xA5A799,\n    0xA4A698,\n    0xA3A597,\n    0xA5A799,\n    0xA6A89A,\n    0xA5A799,\n    0xA5A799,\n    0xA5A799,\n    0xA5A799,\n    0xA6A89A,\n    0xA6A89A,\n    0xA6A89A,\n    0xA6A89A,\n    0xA7A99B,\n    0xA8AA9C,\n    0xA7A99B,\n    0xA6A89A,\n    0xA4A698,\n    0xA2A496,\n    0xA0A294,\n    0x9EA092,\n    0x9D9F91,\n    0x949889,\n    0x979B8C,\n    0x999D8E,\n    0x989C8D,\n    0x989C8D,\n    0x999D8E,\n    0x979B8C,\n    0x939788,\n    0x969A8B,\n    0x949889,\n    0x919586,\n    0x8F9384,\n    0x8E9283,\n    0x8D9182,\n    0x8B8F80,\n    0x898D7E,\n    0x949688,\n    0x909284,\n    0x8E9082,\n    0x8F9183,\n    0x919385,\n    0x919385,\n    0x8D8F81,\n    0x898B7D,\n    0x909284,\n    0x8F9183,\n    0x8D8F81,\n    0x8C8E80,\n    0x8B8D7F,\n    0x8C8E80,\n    0x8D8F81,\n    0x8D9182,\n    0x889081,\n    0x889383,\n    0x889584,\n    0x889584,\n    0x869483,\n    0x869483,\n    0x869785,\n    0x879886,\n    0x80917F,\n    0x80917F,\n    0x818F7E,\n    0x818F7E,\n    0x808D7C,\n    0x7F8C7B,\n    0x7E8979,\n    0x7C887A,\n    0x78857B,\n    0x728278,\n    0x5A6A5F,\n    0x000B00,\n    0x001101,\n    0x000700,\n    0x001100,\n    0x000700,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000F02,\n    0x001005,\n    0x07140A,\n    0x8D998F,\n    0x8E988F,\n    0x949992,\n    0x8C9288,\n    0x94978E,\n    0x9A9B93,\n    0x9B9C94,\n    0x9C9D95,\n    0x9D9E96,\n    0x9EA095,\n    0x9EA095,\n    0x9DA095,\n    0x9DA095,\n    0x96988A,\n    0x999B8D,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x9C9E90,\n    0x9FA193,\n    0xA0A294,\n    0x9D9F91,\n    0x9B9D8F,\n    0xA1A395,\n    0xA6A89A,\n    0xA5A799,\n    0xA4A698,\n    0xA5A799,\n    0xA6A89A,\n    0xA6A89A,\n    0xA6A89A,\n    0xA6A89A,\n    0xA6A89A,\n    0xA7A99B,\n    0xA7A99B,\n    0xA7A99B,\n    0xA7A99B,\n    0xA7A99B,\n    0xA6A89A,\n    0xA6A89A,\n    0xA6A89A,\n    0xA6A89A,\n    0xA5A799,\n    0xA4A698,\n    0xA3A597,\n    0xA3A597,\n    0x9EA293,\n    0xA0A495,\n    0xA0A495,\n    0x9EA293,\n    0x9EA293,\n    0xA0A495,\n    0x9FA394,\n    0x9DA192,\n    0xA1A596,\n    0x9FA394,\n    0x9DA192,\n    0x9CA091,\n    0x9B9F90,\n    0x9B9F90,\n    0x9A9E8F,\n    0x989C8D,\n    0x999B8D,\n    0x959789,\n    0x929486,\n    0x929486,\n    0x949688,\n    0x949688,\n    0x919385,\n    0x8D8F81,\n    0x8F9183,\n    0x8E9082,\n    0x8B8D7F,\n    0x898B7D,\n    0x888A7C,\n    0x888A7C,\n    0x888A7C,\n    0x888C7D,\n    0x797F71,\n    0x798172,\n    0x788373,\n    0x798474,\n    0x778473,\n    0x778473,\n    0x788675,\n    0x798776,\n    0x80917F,\n    0x80917F,\n    0x82907F,\n    0x82907F,\n    0x818E7D,\n    0x7F8C7B,\n    0x7F8A7A,\n    0x7C887A,\n    0x78857B,\n    0x738379,\n    0x647469,\n    0x021207,\n    0x000F00,\n    0x000700,\n    0x001000,\n    0x000700,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000D00,\n    0x001003,\n    0x122013,\n    0x909C90,\n    0x929C91,\n    0x989E94,\n    0x999F95,\n    0x9B9E95,\n    0x9A9C91,\n    0x9A9C91,\n    0x9B9D92,\n    0x9C9E93,\n    0x9C9E91,\n    0x9C9E91,\n    0x9B9F91,\n    0x9B9F91,\n    0x9C9E90,\n    0x9FA193,\n    0xA0A294,\n    0x9EA092,\n    0x9EA092,\n    0xA0A294,\n    0x9FA193,\n    0x9D9F91,\n    0x9C9E90,\n    0xA2A496,\n    0xA6A89A,\n    0xA6A89A,\n    0xA5A799,\n    0xA6A89A,\n    0xA7A99B,\n    0xA7A99B,\n    0xA7A99B,\n    0xA7A99B,\n    0xA7A99B,\n    0xA7A99B,\n    0xA8AA9C,\n    0xA8AA9C,\n    0xA8AA9C,\n    0xA8AA9C,\n    0xABAD9F,\n    0xA9AB9D,\n    0xA6A89A,\n    0xA3A597,\n    0x9EA092,\n    0x9A9C8E,\n    0x97998B,\n    0x959789,\n    0x9DA192,\n    0x9EA293,\n    0x9DA192,\n    0x999D8E,\n    0x999D8E,\n    0x9CA091,\n    0x9CA091,\n    0x9B9F90,\n    0x9EA293,\n    0x9DA192,\n    0x9B9F90,\n    0x9CA091,\n    0x9DA192,\n    0x9FA394,\n    0x9FA394,\n    0x9FA394,\n    0x9EA092,\n    0x9C9E90,\n    0x999B8D,\n    0x989A8C,\n    0x999B8D,\n    0x999B8D,\n    0x96988A,\n    0x949688,\n    0x959789,\n    0x949688,\n    0x929486,\n    0x909284,\n    0x8E9082,\n    0x8D8F81,\n    0x8D8F81,\n    0x8D8F81,\n    0x8D9183,\n    0x8E9284,\n    0x8D9385,\n    0x8C9284,\n    0x879282,\n    0x869181,\n    0x859382,\n    0x869483,\n    0x819280,\n    0x819280,\n    0x819280,\n    0x80917F,\n    0x818F7E,\n    0x7F8D7C,\n    0x7E8B7A,\n    0x7D897B,\n    0x76867B,\n    0x738379,\n    0x6B7B70,\n    0x0D1D12,\n    0x000E00,\n    0x000700,\n    0x000C00,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000900,\n    0x011202,\n    0x1D2B1C,\n    0x8C988A,\n    0x8D988A,\n    0x8D9387,\n    0x989E90,\n    0x95998B,\n    0x9C9E91,\n    0x9D9F92,\n    0x9EA093,\n    0xA0A295,\n    0xA1A395,\n    0xA2A496,\n    0xA1A596,\n    0xA2A697,\n    0x9EA092,\n    0xA1A395,\n    0xA1A395,\n    0x9FA193,\n    0x9EA092,\n    0x9FA193,\n    0x9EA092,\n    0x9B9D8F,\n    0x9D9F91,\n    0xA3A597,\n    0xA7A99B,\n    0xA6A89A,\n    0xA5A799,\n    0xA7A99B,\n    0xA8AA9C,\n    0xA7A99B,\n    0xA7A99B,\n    0xA7A99B,\n    0xA8AA9C,\n    0xA8AA9C,\n    0xA8AA9C,\n    0xA8AA9C,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA8AA9C,\n    0xA8AA9C,\n    0xA8AA9C,\n    0xA7A99B,\n    0xA7A99B,\n    0xA6A89A,\n    0xA5A799,\n    0xA4A698,\n    0x999D8E,\n    0x9B9F90,\n    0x999D8E,\n    0x969A8B,\n    0x95998A,\n    0x979B8C,\n    0x989C8D,\n    0x969A8B,\n    0x979B8C,\n    0x95998A,\n    0x949889,\n    0x949889,\n    0x969A8B,\n    0x989C8D,\n    0x999D8E,\n    0x999D8E,\n    0x9EA092,\n    0x9D9F91,\n    0x9B9D8F,\n    0x9A9C8E,\n    0x999B8D,\n    0x989A8C,\n    0x97998B,\n    0x97998B,\n    0x989A8C,\n    0x989A8C,\n    0x97998B,\n    0x96988A,\n    0x949688,\n    0x939587,\n    0x929486,\n    0x929486,\n    0x919185,\n    0x929286,\n    0x919386,\n    0x8F9385,\n    0x8B9183,\n    0x899182,\n    0x879483,\n    0x889584,\n    0x829381,\n    0x829381,\n    0x829381,\n    0x819280,\n    0x80917F,\n    0x7E8F7D,\n    0x7C8D7B,\n    0x7B8C7C,\n    0x77877C,\n    0x738379,\n    0x6E7E73,\n    0x1A2A1F,\n    0x000E00,\n    0x000B00,\n    0x000900,\n    0x000B00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x061705,\n    0x283625,\n    0x8A9786,\n    0x859080,\n    0x7F8577,\n    0x909787,\n    0x8A8E7F,\n    0x909284,\n    0x919385,\n    0x949688,\n    0x97998B,\n    0x9A9D8C,\n    0x9C9F8E,\n    0x9DA190,\n    0x9DA190,\n    0x9EA092,\n    0xA1A395,\n    0xA2A496,\n    0xA0A294,\n    0xA0A294,\n    0xA2A496,\n    0xA1A395,\n    0x9FA193,\n    0x9D9F91,\n    0xA3A597,\n    0xA7A99B,\n    0xA7A99B,\n    0xA6A89A,\n    0xA7A99B,\n    0xA8AA9C,\n    0xA7A99B,\n    0xA8AA9C,\n    0xA8AA9C,\n    0xA8AA9C,\n    0xA8AA9C,\n    0xA8AA9C,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA8AA9C,\n    0xA7A99B,\n    0xA6A89A,\n    0xA5A799,\n    0xA4A698,\n    0xA5A99A,\n    0xA7AB9C,\n    0xA7AB9C,\n    0xA4A899,\n    0xA3A798,\n    0xA4A899,\n    0xA3A798,\n    0xA0A495,\n    0xA2A697,\n    0xA0A495,\n    0x9EA293,\n    0x9DA192,\n    0x9DA192,\n    0x9EA293,\n    0x9FA394,\n    0x9EA293,\n    0x9C9E90,\n    0x9D9F91,\n    0x9C9E90,\n    0x9A9C8E,\n    0x989A8C,\n    0x97998B,\n    0x97998B,\n    0x989A8C,\n    0x939587,\n    0x939587,\n    0x939587,\n    0x939587,\n    0x929486,\n    0x919385,\n    0x909284,\n    0x909183,\n    0x908E82,\n    0x938F84,\n    0x919185,\n    0x8F9184,\n    0x8E9284,\n    0x8A9283,\n    0x899484,\n    0x8A9786,\n    0x829381,\n    0x829381,\n    0x819481,\n    0x809380,\n    0x7D927F,\n    0x7B907D,\n    0x798E7B,\n    0x7A8C7C,\n    0x77897D,\n    0x74847A,\n    0x6F7F74,\n    0x233328,\n    0x000E00,\n    0x000E00,\n    0x000700,\n    0x000E00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000E01,\n    0x000800,\n    0x404E41,\n    0x8D998D,\n    0x8F998E,\n    0x8E948A,\n    0x959B91,\n    0x95988F,\n    0x999B90,\n    0x9A9C91,\n    0x9C9E93,\n    0x9B9D92,\n    0x999B90,\n    0x9A9C91,\n    0x9CA092,\n    0x9FA395,\n    0xA0A294,\n    0xA0A294,\n    0xA0A294,\n    0x9FA193,\n    0xA1A395,\n    0xA3A597,\n    0xA1A395,\n    0x9C9E90,\n    0x9EA092,\n    0xA3A597,\n    0xA6A89A,\n    0xA6A89A,\n    0xA6A89A,\n    0xA8AA9C,\n    0xA9AB9D,\n    0xA8AA9C,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xADAFA1,\n    0xA1A395,\n    0xA7A99B,\n    0x939587,\n    0x929486,\n    0x929486,\n    0x949688,\n    0x9EA092,\n    0x989A8C,\n    0x919385,\n    0x989A8C,\n    0x989A8C,\n    0x929486,\n    0x97998B,\n    0x959789,\n    0x999B8D,\n    0x9C9E90,\n    0x9B9D8F,\n    0x989A8C,\n    0x989A8C,\n    0x9C9E90,\n    0xA0A294,\n    0x9FA193,\n    0x9EA092,\n    0x9C9E90,\n    0x9B9D8F,\n    0x9A9C8E,\n    0x9A9C8E,\n    0x999B8D,\n    0x999B8D,\n    0x96988A,\n    0x96988A,\n    0x96988A,\n    0x959789,\n    0x949688,\n    0x939587,\n    0x939587,\n    0x929486,\n    0x8F9384,\n    0x8F9384,\n    0x8D9484,\n    0x8D9484,\n    0x8A9584,\n    0x899684,\n    0x889784,\n    0x859683,\n    0x829581,\n    0x829581,\n    0x7F9580,\n    0x7F9580,\n    0x7E947F,\n    0x7C927D,\n    0x7D907C,\n    0x7C8F7C,\n    0x798A78,\n    0x778878,\n    0x708171,\n    0x2E3F2F,\n    0x011202,\n    0x000900,\n    0x000700,\n    0x000F00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000C00,\n    0x000800,\n    0x445245,\n    0x8D998D,\n    0x909A8F,\n    0x91978D,\n    0x999F95,\n    0x999C93,\n    0x9C9E93,\n    0x9C9E93,\n    0x9B9D92,\n    0x9C9E93,\n    0x9D9F94,\n    0x9FA196,\n    0x9FA395,\n    0xA0A496,\n    0xA4A698,\n    0xA4A698,\n    0xA2A496,\n    0xA0A294,\n    0xA0A294,\n    0xA2A496,\n    0x9EA092,\n    0x989A8C,\n    0x9FA193,\n    0xA3A597,\n    0xA6A89A,\n    0xA6A89A,\n    0xA6A89A,\n    0xA8AA9C,\n    0xA9AB9D,\n    0xA8AA9C,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA6A89A,\n    0xA7A99B,\n    0xACAEA0,\n    0xA5A799,\n    0xB0B2A4,\n    0xA3A597,\n    0xA6A89A,\n    0xAAAC9E,\n    0xA3A597,\n    0xA9AB9D,\n    0xA7A99B,\n    0xA3A597,\n    0xA6A89A,\n    0xA6A89A,\n    0xA3A597,\n    0xA3A597,\n    0x9D9F91,\n    0x9D9F91,\n    0x9B9D8F,\n    0x97998B,\n    0x939587,\n    0x919385,\n    0x939587,\n    0x949688,\n    0x9C9E90,\n    0x9D9F91,\n    0x9D9F91,\n    0x9D9F91,\n    0x9C9E90,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x97998B,\n    0x97998B,\n    0x96988A,\n    0x959789,\n    0x949688,\n    0x949688,\n    0x939587,\n    0x939587,\n    0x909485,\n    0x909485,\n    0x8E9585,\n    0x8C9584,\n    0x8A9584,\n    0x899684,\n    0x869784,\n    0x869784,\n    0x829581,\n    0x829581,\n    0x809681,\n    0x7F9580,\n    0x80937F,\n    0x7F927E,\n    0x7D907C,\n    0x7D907D,\n    0x798A78,\n    0x788979,\n    0x728373,\n    0x3C4D3D,\n    0x001101,\n    0x000B00,\n    0x000800,\n    0x000D00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x021205,\n    0x000E03,\n    0x4E5C4F,\n    0x8A968A,\n    0x879186,\n    0x83897F,\n    0x888E84,\n    0x868980,\n    0x919388,\n    0x8F9186,\n    0x8D8F84,\n    0x8F9186,\n    0x93958A,\n    0x95978C,\n    0x94988A,\n    0x929688,\n    0x919385,\n    0x939587,\n    0x949688,\n    0x96988A,\n    0x9C9E90,\n    0xA2A496,\n    0xA1A395,\n    0x9EA092,\n    0x9FA193,\n    0xA4A698,\n    0xA7A99B,\n    0xA6A89A,\n    0xA6A89A,\n    0xA8AA9C,\n    0xA9AB9D,\n    0xA7A99B,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xAAAC9E,\n    0xABAD9F,\n    0xA6A89A,\n    0xAEB0A2,\n    0xA3A597,\n    0xA4A698,\n    0xA8AA9C,\n    0xA4A698,\n    0xA3A597,\n    0xA6A89A,\n    0xA6A89A,\n    0xA2A496,\n    0xA4A698,\n    0xA5A799,\n    0x9FA193,\n    0xA6A89A,\n    0xA5A799,\n    0xA2A496,\n    0xA0A294,\n    0x9EA092,\n    0x9FA193,\n    0xA0A294,\n    0xA1A395,\n    0x9C9E90,\n    0x9EA092,\n    0x9FA193,\n    0x9EA092,\n    0x9B9D8F,\n    0x999B8D,\n    0x999B8D,\n    0x9A9C8E,\n    0x97998B,\n    0x97998B,\n    0x96988A,\n    0x96988A,\n    0x959789,\n    0x949688,\n    0x949688,\n    0x939587,\n    0x919586,\n    0x919586,\n    0x8D9685,\n    0x8D9685,\n    0x8A9785,\n    0x899684,\n    0x869784,\n    0x869784,\n    0x839682,\n    0x839682,\n    0x829581,\n    0x829581,\n    0x819480,\n    0x7F927E,\n    0x7E917D,\n    0x7D907D,\n    0x7A8B79,\n    0x788979,\n    0x738474,\n    0x516252,\n    0x000F00,\n    0x000D00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000E01,\n    0x000E03,\n    0x5A685B,\n    0x8F9B8F,\n    0x909A8F,\n    0x90968C,\n    0x989E94,\n    0x989B92,\n    0x9EA095,\n    0x9D9F94,\n    0x9C9E93,\n    0x9EA095,\n    0xA0A297,\n    0xA1A398,\n    0xA0A496,\n    0x9FA395,\n    0xA0A294,\n    0xA1A395,\n    0xA0A294,\n    0x9FA193,\n    0xA0A294,\n    0xA3A597,\n    0xA0A294,\n    0x9B9D8F,\n    0xA0A294,\n    0xA4A698,\n    0xA7A99B,\n    0xA6A89A,\n    0xA6A89A,\n    0xA8AA9C,\n    0xA9AB9D,\n    0xA7A99B,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xACAEA0,\n    0xADAFA1,\n    0xAAAC9E,\n    0xA6A89A,\n    0xA8AA9C,\n    0x9EA092,\n    0x999B8D,\n    0x9D9F91,\n    0x979B8C,\n    0x919586,\n    0x969A8B,\n    0x999D8E,\n    0x909485,\n    0x939788,\n    0x989C8D,\n    0x8F9384,\n    0x929687,\n    0x939788,\n    0x949889,\n    0x949889,\n    0x939788,\n    0x939788,\n    0x969A8B,\n    0x989C8D,\n    0x959789,\n    0x97998B,\n    0x989A8C,\n    0x97998B,\n    0x949688,\n    0x949688,\n    0x96988A,\n    0x999B8D,\n    0x989A8C,\n    0x989A8C,\n    0x97998B,\n    0x97998B,\n    0x96988A,\n    0x959789,\n    0x949688,\n    0x949688,\n    0x909787,\n    0x909787,\n    0x8E9786,\n    0x8E9786,\n    0x8A9785,\n    0x8A9785,\n    0x879885,\n    0x869784,\n    0x849783,\n    0x839682,\n    0x839682,\n    0x829581,\n    0x829380,\n    0x81927F,\n    0x80917E,\n    0x7F907E,\n    0x7C8D7B,\n    0x798A7A,\n    0x738474,\n    0x637464,\n    0x000D00,\n    0x000E00,\n    0x000C00,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000C00,\n    0x001005,\n    0x657366,\n    0x8F9B8F,\n    0x909A8F,\n    0x91978D,\n    0x9AA096,\n    0x9B9E95,\n    0x9D9F94,\n    0x9EA095,\n    0xA0A297,\n    0xA0A297,\n    0x9EA095,\n    0x9EA095,\n    0x9EA294,\n    0x9FA395,\n    0xA1A395,\n    0xA1A395,\n    0xA0A294,\n    0x9FA193,\n    0xA1A395,\n    0xA3A597,\n    0xA0A294,\n    0x9B9D8F,\n    0xA0A294,\n    0xA5A799,\n    0xA8AA9C,\n    0xA7A99B,\n    0xA7A99B,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA7A99B,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA8AA9C,\n    0xABAD9F,\n    0xA8AA9C,\n    0xABAD9F,\n    0xAEB0A2,\n    0xAAAC9E,\n    0xA2A496,\n    0xA7A99B,\n    0xACB0A1,\n    0xA3A798,\n    0xA8AC9D,\n    0xAAAE9F,\n    0xA1A596,\n    0xA4A899,\n    0xAAAE9F,\n    0xA4A899,\n    0x9CA091,\n    0x9FA394,\n    0xA2A697,\n    0xA0A495,\n    0x9B9F90,\n    0x989C8D,\n    0x989C8D,\n    0x9A9E8F,\n    0x939587,\n    0x949688,\n    0x949688,\n    0x939587,\n    0x929486,\n    0x949688,\n    0x999B8D,\n    0x9D9F91,\n    0x999B8D,\n    0x999B8D,\n    0x989A8C,\n    0x97998B,\n    0x96988A,\n    0x96988A,\n    0x959789,\n    0x949889,\n    0x919888,\n    0x909988,\n    0x8D9887,\n    0x8D9887,\n    0x8A9986,\n    0x8A9986,\n    0x879885,\n    0x879885,\n    0x849783,\n    0x849783,\n    0x849783,\n    0x839682,\n    0x839481,\n    0x829380,\n    0x83927F,\n    0x82907F,\n    0x7F907E,\n    0x7B8C7C,\n    0x728373,\n    0x6E7F6F,\n    0x001000,\n    0x000D00,\n    0x000D00,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000E01,\n    0x041409,\n    0x6F7D70,\n    0x8B978B,\n    0x889287,\n    0x868C82,\n    0x8B9187,\n    0x8B8E85,\n    0x8E9085,\n    0x919388,\n    0x94968B,\n    0x93958A,\n    0x919388,\n    0x8F9186,\n    0x909486,\n    0x929688,\n    0x919385,\n    0x939587,\n    0x959789,\n    0x97998B,\n    0x9D9F91,\n    0xA2A496,\n    0xA2A496,\n    0x9EA092,\n    0xA1A395,\n    0xA6A89A,\n    0xA8AA9C,\n    0xA7A99B,\n    0xA7A99B,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA7A99B,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xA3A597,\n    0xA8AA9C,\n    0xA2A496,\n    0xABAD9F,\n    0xADAFA1,\n    0xAFB1A3,\n    0xA7A99B,\n    0xAEB0A2,\n    0xA9AD9E,\n    0xA4A899,\n    0xA5A99A,\n    0xA7AB9C,\n    0xA3A798,\n    0xA3A798,\n    0xA5A99A,\n    0xA4A899,\n    0xA3A798,\n    0xA4A899,\n    0xA5A99A,\n    0xA4A899,\n    0xA1A596,\n    0x9EA293,\n    0x9DA192,\n    0x9DA192,\n    0xA3A597,\n    0xA0A294,\n    0x9D9F91,\n    0x9A9C8E,\n    0x999B8D,\n    0x9A9C8E,\n    0x9C9E90,\n    0x9D9F91,\n    0x9A9C8E,\n    0x999B8D,\n    0x999B8D,\n    0x989A8C,\n    0x97998B,\n    0x97998B,\n    0x96988A,\n    0x95998A,\n    0x929989,\n    0x919A89,\n    0x8E9988,\n    0x8E9988,\n    0x8B9A87,\n    0x8A9986,\n    0x889986,\n    0x879885,\n    0x859884,\n    0x859884,\n    0x869784,\n    0x859683,\n    0x869582,\n    0x859481,\n    0x83927F,\n    0x839180,\n    0x80917F,\n    0x7D8E7E,\n    0x738474,\n    0x738474,\n    0x091A0A,\n    0x000C00,\n    0x000D00,\n    0x000800,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000A00,\n    0x041409,\n    0x79877A,\n    0x909C90,\n    0x909A8F,\n    0x93998F,\n    0x9BA197,\n    0x9DA097,\n    0x9C9E93,\n    0x9D9F94,\n    0x9FA196,\n    0xA0A297,\n    0xA1A398,\n    0xA1A398,\n    0xA0A496,\n    0xA0A496,\n    0xA5A799,\n    0xA5A799,\n    0xA3A597,\n    0xA1A395,\n    0xA2A496,\n    0xA3A597,\n    0x9FA193,\n    0x999B8D,\n    0xA1A395,\n    0xA6A89A,\n    0xA9AB9D,\n    0xA7A99B,\n    0xA7A99B,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA7A99B,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xA1A395,\n    0xA3A597,\n    0x97998B,\n    0x9EA092,\n    0x9B9D8F,\n    0x9FA193,\n    0x96988A,\n    0x9EA092,\n    0xA1A898,\n    0xA2A999,\n    0xA1A898,\n    0xA3AA9A,\n    0xA6AD9D,\n    0xA0A797,\n    0x9CA393,\n    0xA0A797,\n    0xA4AB9B,\n    0xA0A797,\n    0x9CA393,\n    0x9DA494,\n    0xA1A898,\n    0xA4AB9B,\n    0xA2A999,\n    0xA2A697,\n    0xA1A596,\n    0x9FA193,\n    0x9C9E90,\n    0x9C9E90,\n    0x9EA092,\n    0x9FA193,\n    0x9D9F91,\n    0x9A9C8E,\n    0x9A9C8E,\n    0x9A9C8E,\n    0x999B8D,\n    0x999B8D,\n    0x989A8C,\n    0x97998B,\n    0x96988A,\n    0x95998A,\n    0x929B8A,\n    0x909B8A,\n    0x8E9B89,\n    0x8D9A88,\n    0x8B9A87,\n    0x8A9986,\n    0x889986,\n    0x889986,\n    0x869985,\n    0x869985,\n    0x869784,\n    0x869784,\n    0x869582,\n    0x859481,\n    0x859280,\n    0x849180,\n    0x7F907E,\n    0x7F9080,\n    0x758676,\n    0x778878,\n    0x172818,\n    0x000E00,\n    0x000E00,\n    0x000700,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000F02,\n    0x09190E,\n    0x808E81,\n    0x919D91,\n    0x8E988D,\n    0x8F958B,\n    0x969C92,\n    0x979A91,\n    0x9C9E93,\n    0x9B9D92,\n    0x9B9D92,\n    0x9EA095,\n    0xA2A499,\n    0xA4A69B,\n    0xA2A698,\n    0xA0A496,\n    0xA1A395,\n    0xA2A496,\n    0xA1A395,\n    0xA0A294,\n    0xA2A496,\n    0xA5A799,\n    0xA2A496,\n    0x9D9F91,\n    0xA2A496,\n    0xA6A89A,\n    0xA9AB9D,\n    0xA8AA9C,\n    0xA7A99B,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA7A99B,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0x9EA092,\n    0x9EA092,\n    0x8C8E80,\n    0x909284,\n    0x8A8C7E,\n    0x8F9183,\n    0x858779,\n    0x8F9183,\n    0x7C8373,\n    0x838A7A,\n    0x818878,\n    0x848B7B,\n    0x8B9282,\n    0x818878,\n    0x777E6E,\n    0x7F8676,\n    0x8A9181,\n    0x7F8676,\n    0x767D6D,\n    0x777E6E,\n    0x7F8676,\n    0x848B7B,\n    0x818878,\n    0x7D8172,\n    0x868A7B,\n    0x87897B,\n    0x898B7D,\n    0x919385,\n    0x9B9D8F,\n    0xA0A294,\n    0x9FA193,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x9A9C8E,\n    0x9A9C8E,\n    0x999B8D,\n    0x989A8C,\n    0x97998B,\n    0x97998B,\n    0x969A8B,\n    0x929B8A,\n    0x909B8A,\n    0x8E9B89,\n    0x8E9B89,\n    0x8C9B88,\n    0x8B9A87,\n    0x889986,\n    0x889986,\n    0x869985,\n    0x869985,\n    0x879885,\n    0x869784,\n    0x879683,\n    0x859481,\n    0x859280,\n    0x859281,\n    0x7E8F7D,\n    0x809181,\n    0x778878,\n    0x798A7A,\n    0x223323,\n    0x000F00,\n    0x000E00,\n    0x000700,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000B00,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000C00,\n    0x000D00,\n    0x000900,\n    0x021303,\n    0x8E9C8F,\n    0x8C988C,\n    0x8C988E,\n    0x8B958C,\n    0x919891,\n    0x939A93,\n    0x929791,\n    0x90958F,\n    0x8F948D,\n    0x8F948D,\n    0x90988B,\n    0x90988B,\n    0x8E9687,\n    0x8D9385,\n    0x8F9384,\n    0x919385,\n    0x929486,\n    0x96988A,\n    0x9A9C8E,\n    0x9EA092,\n    0x9FA193,\n    0x9FA193,\n    0xA3A597,\n    0xA7A99B,\n    0xA9AB9D,\n    0xA8AA9C,\n    0xA7A99B,\n    0xA9AB9D,\n    0xAAAC9E,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xABAD9F,\n    0xABAD9F,\n    0xA8AA9C,\n    0xACAEA0,\n    0xADAFA1,\n    0xABAD9F,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xA9AB9D,\n    0xA6A89A,\n    0xACAEA0,\n    0xAAAC9E,\n    0xA6A89A,\n    0xA4A698,\n    0xA7A99B,\n    0xAAAC9E,\n    0xA8AA9C,\n    0xA3A597,\n    0xA5A799,\n    0xA3A597,\n    0xA1A395,\n    0xA0A294,\n    0xA0A294,\n    0x9FA193,\n    0x9D9F91,\n    0x9B9D8F,\n    0x939587,\n    0x8F9183,\n    0x8D8F81,\n    0x919385,\n    0x9A9C8E,\n    0x9FA193,\n    0x9D9F91,\n    0x9A9C8E,\n    0x999B8D,\n    0x999B8D,\n    0x999B8D,\n    0x999B8D,\n    0x999B8D,\n    0x989A8C,\n    0x97998B,\n    0x949B8B,\n    0x8F9C8A,\n    0x8C9D8A,\n    0x8C9D8A,\n    0x8C9D8A,\n    0x8B9C89,\n    0x8A9B88,\n    0x899A87,\n    0x899A87,\n    0x879885,\n    0x879885,\n    0x879885,\n    0x869784,\n    0x869784,\n    0x859683,\n    0x859683,\n    0x849583,\n    0x819282,\n    0x829285,\n    0x819184,\n    0x738376,\n    0x354538,\n    0x021205,\n    0x000700,\n    0x000E00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000B00,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000C00,\n    0x000D00,\n    0x051302,\n    0x142213,\n    0x96A296,\n    0x949E93,\n    0x939D94,\n    0x929991,\n    0x969B95,\n    0x989D97,\n    0x9EA09B,\n    0x9EA09B,\n    0x9FA299,\n    0xA0A39A,\n    0xA0A69A,\n    0xA1A79B,\n    0xA0A698,\n    0xA2A698,\n    0xA2A697,\n    0xA3A597,\n    0xA2A496,\n    0xA3A597,\n    0xA4A698,\n    0xA3A597,\n    0xA1A395,\n    0x9FA193,\n    0xA3A597,\n    0xA7A99B,\n    0xA9AB9D,\n    0xA8AA9C,\n    0xA8AA9C,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xABAD9F,\n    0xABAD9F,\n    0xABAD9F,\n    0xAAAC9E,\n    0xA6A89A,\n    0x9FA193,\n    0x999B8D,\n    0x9B9D8F,\n    0xA2A496,\n    0xA6A89A,\n    0xA6A89A,\n    0x9EA092,\n    0x9EA092,\n    0xA1A395,\n    0xA8AA9C,\n    0xAEB0A2,\n    0xB0B2A4,\n    0xADAFA1,\n    0xAAAC9E,\n    0xA7A99B,\n    0xA5A799,\n    0xA3A597,\n    0xA3A597,\n    0xA2A496,\n    0xA2A496,\n    0xA0A294,\n    0x9EA092,\n    0xA3A597,\n    0x9FA193,\n    0x9C9E90,\n    0x9D9F91,\n    0xA1A395,\n    0xA2A496,\n    0xA0A294,\n    0x9D9F91,\n    0x9D9F91,\n    0x9D9F91,\n    0x9D9F91,\n    0x9C9E90,\n    0x9B9D8F,\n    0x9A9C8E,\n    0x999B8D,\n    0x979B8C,\n    0x929F8D,\n    0x91A08D,\n    0x909F8C,\n    0x8F9E8B,\n    0x8B9C89,\n    0x8A9B88,\n    0x899A87,\n    0x889986,\n    0x879885,\n    0x879885,\n    0x879885,\n    0x869784,\n    0x869784,\n    0x859683,\n    0x849783,\n    0x849784,\n    0x819282,\n    0x819184,\n    0x809083,\n    0x758578,\n    0x425343,\n    0x001000,\n    0x000A00,\n    0x000F00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000B00,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000C00,\n    0x000C00,\n    0x000E00,\n    0x1A261A,\n    0x909A91,\n    0x8E958D,\n    0x8E958D,\n    0x8B9089,\n    0x92948F,\n    0x949691,\n    0x94958F,\n    0x969791,\n    0x989991,\n    0x999A92,\n    0x999C91,\n    0x999C91,\n    0x9A9E90,\n    0x9B9F91,\n    0x9FA193,\n    0x9FA193,\n    0xA1A395,\n    0xA3A597,\n    0xA4A698,\n    0xA4A698,\n    0xA1A395,\n    0x9FA193,\n    0xA3A597,\n    0xA7A99B,\n    0xA9AB9D,\n    0xA8AA9C,\n    0xA8AA9C,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xA9AB9D,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xABAD9F,\n    0xABAD9F,\n    0xABAD9F,\n    0xABAD9F,\n    0xA8AA9C,\n    0xA2A496,\n    0x9D9F91,\n    0x9EA092,\n    0x9EA092,\n    0x9A9C8E,\n    0x939587,\n    0x96988A,\n    0x949688,\n    0x989A8C,\n    0xA2A496,\n    0xA7A99B,\n    0xA5A799,\n    0xA2A496,\n    0xA3A597,\n    0xAAAC9E,\n    0xA8AA9C,\n    0xA7A99B,\n    0xA6A89A,\n    0xA7A99B,\n    0xA6A89A,\n    0xA5A799,\n    0xA3A597,\n    0xA3A597,\n    0xA1A395,\n    0x9EA092,\n    0x9C9E90,\n    0x9C9E90,\n    0x9B9D8F,\n    0x999B8D,\n    0x97998B,\n    0x9C9E90,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x999B8D,\n    0x989A8C,\n    0x97998B,\n    0x96988A,\n    0x949889,\n    0x8E9988,\n    0x8C9987,\n    0x8B9A87,\n    0x8B9A87,\n    0x8B9A87,\n    0x8C9B88,\n    0x8D9C89,\n    0x8E9D8A,\n    0x889986,\n    0x889986,\n    0x879885,\n    0x879885,\n    0x859884,\n    0x859884,\n    0x849783,\n    0x849784,\n    0x829383,\n    0x819184,\n    0x7E8F7F,\n    0x798A7A,\n    0x566757,\n    0x000C00,\n    0x001000,\n    0x000E00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000B00,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000C00,\n    0x000C00,\n    0x030F03,\n    0x2C362D,\n    0x929991,\n    0x91968F,\n    0x949993,\n    0x92948F,\n    0x9A9B96,\n    0x9C9D98,\n    0x979691,\n    0x9A9994,\n    0x9C9C94,\n    0x9C9C94,\n    0x9A9C8F,\n    0x999B8E,\n    0x9A9C8E,\n    0x9D9F91,\n    0x949688,\n    0x96988A,\n    0x9A9C8E,\n    0x9FA193,\n    0xA2A496,\n    0xA2A496,\n    0xA0A294,\n    0x9EA092,\n    0xA3A597,\n    0xA8AA9C,\n    0xAAAC9E,\n    0xA8AA9C,\n    0xA8AA9C,\n    0xAAAC9E,\n    0xABAD9F,\n    0xA9AB9D,\n    0xA9AD9E,\n    0xA9AD9E,\n    0xA9AD9E,\n    0xA9AD9E,\n    0xAAAE9F,\n    0xAAAE9F,\n    0xAAAE9F,\n    0xAAAE9F,\n    0xA6AA9B,\n    0xA7AB9C,\n    0xA8AC9D,\n    0xA8AC9D,\n    0xAAAE9F,\n    0xACB0A1,\n    0xA9AD9E,\n    0xA3A798,\n    0xABAFA0,\n    0xA4A899,\n    0xA4A899,\n    0xABAFA0,\n    0xADB1A2,\n    0xAAAE9F,\n    0xAAAE9F,\n    0xAEB2A3,\n    0xA3A798,\n    0xA2A697,\n    0xA1A596,\n    0xA1A596,\n    0xA1A596,\n    0xA1A596,\n    0xA0A495,\n    0x9FA394,\n    0xA4A698,\n    0xA4A698,\n    0xA3A597,\n    0xA1A395,\n    0x9FA193,\n    0x9EA092,\n    0x9FA193,\n    0x9FA193,\n    0x9C9E90,\n    0x9B9D8F,\n    0x9A9C8E,\n    0x999B8D,\n    0x989A8C,\n    0x97998B,\n    0x97998B,\n    0x95998A,\n    0x919A89,\n    0x8E9988,\n    0x8D9A88,\n    0x8C9987,\n    0x8D9A88,\n    0x8E9B89,\n    0x8E9D8A,\n    0x8E9D8A,\n    0x889986,\n    0x889986,\n    0x889986,\n    0x879885,\n    0x869985,\n    0x859884,\n    0x859884,\n    0x859885,\n    0x859684,\n    0x819282,\n    0x7D8E7E,\n    0x7C8D7D,\n    0x697A6A,\n    0x000B00,\n    0x021301,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000B00,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000C00,\n    0x000C00,\n    0x041004,\n    0x3D473E,\n    0x929992,\n    0x919690,\n    0x979C96,\n    0x949691,\n    0x9C9D98,\n    0x9D9E99,\n    0x9D9C97,\n    0xA09F9A,\n    0xA2A298,\n    0xA2A298,\n    0xA0A295,\n    0x9FA194,\n    0xA1A493,\n    0xA3A695,\n    0x9D9F91,\n    0x9EA092,\n    0xA1A395,\n    0xA4A698,\n    0xA6A89A,\n    0xA4A698,\n    0xA1A395,\n    0x9D9F91,\n    0xA4A698,\n    0xA8AA9C,\n    0xAAAC9E,\n    0xA9AB9D,\n    0xA8AA9C,\n    0xAAAC9E,\n    0xABAD9F,\n    0xA9AB9D,\n    0xA9AD9E,\n    0xA9AD9E,\n    0xA9AD9E,\n    0xAAAE9F,\n    0xAAAE9F,\n    0xAAAE9F,\n    0xAAAE9F,\n    0xABAFA0,\n    0xABAFA0,\n    0xAAAE9F,\n    0xA4A899,\n    0x9CA091,\n    0x989C8D,\n    0x9CA091,\n    0xA2A697,\n    0xA5A99A,\n    0xA6AA9B,\n    0xA0A495,\n    0x9FA394,\n    0xA3A798,\n    0xA4A899,\n    0xA1A596,\n    0xA2A697,\n    0xA7AB9C,\n    0xA6AA9B,\n    0xA5A99A,\n    0xA4A899,\n    0xA4A899,\n    0xA5A99A,\n    0xA5A99A,\n    0xA4A899,\n    0xA2A697,\n    0x9EA092,\n    0x9FA193,\n    0x9FA193,\n    0x9EA092,\n    0x9C9E90,\n    0x9C9E90,\n    0x9D9F91,\n    0x9FA193,\n    0x9C9E90,\n    0x9B9D8F,\n    0x9B9D8F,\n    0x9A9C8E,\n    0x999B8D,\n    0x999B8D,\n    0x999B8D,\n    0x999D8E,\n    0x989F8F,\n    0x969F8E,\n    0x939E8D,\n    0x919C8B,\n    0x909B8A,\n    0x8F9A89,\n    0x8D9A88,\n    0x8D9A88,\n    0x8B9A87,\n    0x8B9A87,\n    0x889986,\n    0x889986,\n    0x869985,\n    0x869985,\n    0x859884,\n    0x859885,\n    0x879886,\n    0x819282,\n    0x7E8F7F,\n    0x7E8F7F,\n    0x768775,\n    0x000F00,\n    0x001100,\n    0x000700,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000B00,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000C00,\n    0x000C00,\n    0x000B01,\n    0x465149,\n    0x8A948C,\n    0x8B928B,\n    0x919793,\n    0x8B908C,\n    0x939590,\n    0x92948F,\n    0x93948E,\n    0x959690,\n    0x97998E,\n    0x999B90,\n    0x999D8E,\n    0x9A9E8F,\n    0x9B9F8E,\n    0x9CA08F,\n    0x9EA092,\n    0x9FA193,\n    0xA2A496,\n    0xA4A698,\n    0xA6A89A,\n    0xA4A698,\n    0xA0A294,\n    0x9D9F91,\n    0xA4A698,\n    0xA8AA9C,\n    0xAAAC9E,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xABAD9F,\n    0xABAD9F,\n    0xAAAC9E,\n    0xA9AD9E,\n    0xAAAE9F,\n    0xAAAE9F,\n    0xAAAE9F,\n    0xAAAE9F,\n    0xABAFA0,\n    0xABAFA0,\n    0xABAFA0,\n    0xAAAE9F,\n    0xACB0A1,\n    0xA9AD9E,\n    0x9FA394,\n    0x979B8C,\n    0x979B8C,\n    0x9A9E8F,\n    0x9CA091,\n    0x9A9E8F,\n    0x9A9E8F,\n    0x9B9F90,\n    0x9A9E8F,\n    0x999D8E,\n    0x979B8C,\n    0x95998A,\n    0x949889,\n    0x949889,\n    0x939788,\n    0x929687,\n    0x929687,\n    0x939788,\n    0x939788,\n    0x929687,\n    0x909485,\n    0x959789,\n    0x959789,\n    0x959789,\n    0x939587,\n    0x919385,\n    0x919385,\n    0x919385,\n    0x929486,\n    0x939587,\n    0x929486,\n    0x919385,\n    0x909284,\n    0x909284,\n    0x919385,\n    0x919385,\n    0x929486,\n    0x8F9686,\n    0x909787,\n    0x909988,\n    0x919A89,\n    0x909B8A,\n    0x909B8A,\n    0x8F9C8A,\n    0x8F9C8A,\n    0x8B9A87,\n    0x8B9A87,\n    0x899A87,\n    0x889986,\n    0x879A86,\n    0x869985,\n    0x869985,\n    0x869985,\n    0x889987,\n    0x819280,\n    0x819280,\n    0x80917F,\n    0x7C8D7B,\n    0x0B1C0A,\n    0x000F00,\n    0x000800,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000B00,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000C00,\n    0x000D00,\n    0x031006,\n    0x556259,\n    0x8E9993,\n    0x8F9893,\n    0x97A09B,\n    0x919793,\n    0x999E98,\n    0x969B95,\n    0x979A93,\n    0x979A93,\n    0x989B90,\n    0x9A9D92,\n    0x9BA292,\n    0x9CA393,\n    0x9CA48F,\n    0x9EA291,\n    0x999D8C,\n    0x9B9D8F,\n    0x9EA092,\n    0xA1A395,\n    0xA3A597,\n    0xA3A597,\n    0xA0A294,\n    0x9EA092,\n    0xA4A698,\n    0xA8AA9C,\n    0xAAAC9E,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xABAD9F,\n    0xABAD9F,\n    0xAAAC9E,\n    0xA8AF9F,\n    0xA8AF9F,\n    0xA8AF9F,\n    0xA8AF9F,\n    0xA8AF9F,\n    0xA9B0A0,\n    0xA9B0A0,\n    0xA9B0A0,\n    0xA0A797,\n    0xA5AC9C,\n    0xA9B0A0,\n    0xA8AF9F,\n    0xA7AE9E,\n    0xA9B0A0,\n    0xAAB1A1,\n    0xA9B0A0,\n    0xA4AB9B,\n    0xA9B0A0,\n    0xA9B0A0,\n    0xA3AA9A,\n    0xA2A999,\n    0xA6AD9D,\n    0xA6AD9D,\n    0xA1A898,\n    0xA4AB9B,\n    0xA3AA9A,\n    0xA1A898,\n    0xA1A898,\n    0xA2A999,\n    0xA2A999,\n    0xA0A797,\n    0xA1A596,\n    0x9EA293,\n    0x9EA092,\n    0x9C9E90,\n    0x9A9C8E,\n    0x999B8D,\n    0x989A8C,\n    0x97998B,\n    0x96988A,\n    0x929486,\n    0x919385,\n    0x8F9183,\n    0x8E9082,\n    0x8D8F81,\n    0x8D8F81,\n    0x8E9082,\n    0x8F9183,\n    0x888F7F,\n    0x8A9181,\n    0x8D9484,\n    0x909787,\n    0x929B8A,\n    0x939C8B,\n    0x919C8B,\n    0x919C8B,\n    0x8C9B88,\n    0x8C9B88,\n    0x899A87,\n    0x899A87,\n    0x879A86,\n    0x879A86,\n    0x849A85,\n    0x869985,\n    0x879A87,\n    0x80917F,\n    0x849583,\n    0x819280,\n    0x7F907E,\n    0x1A2B19,\n    0x000E00,\n    0x000C00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000B00,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000C00,\n    0x000D00,\n    0x000F04,\n    0x586760,\n    0x8D9A93,\n    0x919C96,\n    0x9AA59F,\n    0x949D98,\n    0x9DA49D,\n    0x9AA19A,\n    0xA0A59E,\n    0x9EA39C,\n    0x9DA397,\n    0x9EA496,\n    0xA0A998,\n    0xA1AA97,\n    0x9FA893,\n    0x9EA593,\n    0xA2A695,\n    0xA3A597,\n    0xA3A597,\n    0xA4A698,\n    0xA5A799,\n    0xA4A698,\n    0xA1A395,\n    0x9EA092,\n    0xA4A698,\n    0xA8AA9C,\n    0xABAD9F,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xABAD9F,\n    0xABAD9F,\n    0xAAAC9E,\n    0xA8AF9F,\n    0xA8AF9F,\n    0xA8AF9F,\n    0xA8AF9F,\n    0xA9B0A0,\n    0xA9B0A0,\n    0xA9B0A0,\n    0xA9B0A0,\n    0xABB2A2,\n    0xA8AF9F,\n    0x9FA696,\n    0x959C8C,\n    0x919888,\n    0x939A8A,\n    0x959C8C,\n    0x949B8B,\n    0x929989,\n    0x99A090,\n    0x979E8E,\n    0x8F9686,\n    0x929989,\n    0xA0A797,\n    0xA8AF9F,\n    0xA6AD9D,\n    0xA6AD9D,\n    0xA4AB9B,\n    0xA3AA9A,\n    0xA2A999,\n    0xA3AA9A,\n    0xA3AA9A,\n    0xA1A898,\n    0xA2A697,\n    0xA5A99A,\n    0xA3A597,\n    0xA1A395,\n    0xA0A294,\n    0xA0A294,\n    0xA0A294,\n    0x9EA092,\n    0x9C9E90,\n    0xA0A294,\n    0x9EA092,\n    0x9C9E90,\n    0x9A9C8E,\n    0x989A8C,\n    0x989A8C,\n    0x999B8D,\n    0x999B8D,\n    0x949889,\n    0x95998A,\n    0x969D8D,\n    0x979E8E,\n    0x959E8D,\n    0x939C8B,\n    0x8E9988,\n    0x8D9887,\n    0x8C9B88,\n    0x8C9B88,\n    0x899A87,\n    0x899A87,\n    0x879A86,\n    0x879A86,\n    0x849A85,\n    0x869985,\n    0x869986,\n    0x7F907E,\n    0x869785,\n    0x829381,\n    0x7F907E,\n    0x263725,\n    0x000E00,\n    0x001000,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000B00,\n    0x000D00,\n    0x000E00,\n    0x0C1510,\n    0x696F6F,\n    0x8F9591,\n    0x898E8A,\n    0x848982,\n    0x91948D,\n    0x84877C,\n    0x909388,\n    0x989A8C,\n    0x959789,\n    0x929687,\n    0x939788,\n    0x939B8C,\n    0x969E8F,\n    0x969E91,\n    0x949C8F,\n    0x97A08F,\n    0x9DA695,\n    0xA1A898,\n    0x9FA696,\n    0xA0A495,\n    0xA2A496,\n    0xA0A294,\n    0x9E9F91,\n    0xA6A799,\n    0xA8A99B,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AD9E,\n    0xABAD9F,\n    0xAAAC9E,\n    0xABAC9E,\n    0xABAD9F,\n    0xABAD9F,\n    0xABAFA0,\n    0xABAFA0,\n    0xA9B2A1,\n    0xA9B2A1,\n    0xA9B2A1,\n    0xA9B2A1,\n    0xA8AF9F,\n    0xA6AD9D,\n    0xA8AC9D,\n    0xABAFA0,\n    0xABAD9F,\n    0xA8AA9C,\n    0xA8AB9A,\n    0xA9AC9B,\n    0xA9AC9B,\n    0xAAAD9C,\n    0xABAE9D,\n    0xABAE9D,\n    0xAAAD9C,\n    0xA9AC9B,\n    0xA7AA99,\n    0xA7AA99,\n    0xA6A998,\n    0xA6A998,\n    0xA5A897,\n    0xA5A897,\n    0xA5A897,\n    0xA5A897,\n    0xA2A697,\n    0xA1A596,\n    0x9FA394,\n    0x9EA293,\n    0x9EA293,\n    0x9EA293,\n    0x9DA192,\n    0x9CA091,\n    0x9DA192,\n    0x9CA091,\n    0x9A9E8F,\n    0x989C8D,\n    0x989C8D,\n    0x989C8D,\n    0x9A9E8F,\n    0x9B9F90,\n    0x95998A,\n    0x969A8B,\n    0x949D8C,\n    0x919C8B,\n    0x8F9C8A,\n    0x8B9C89,\n    0x8B9E8A,\n    0x8AA08B,\n    0x889E89,\n    0x889E89,\n    0x8A9D89,\n    0x8B9C89,\n    0x8D9C89,\n    0x8E9988,\n    0x8D9887,\n    0x8D9887,\n    0x8A9986,\n    0x839481,\n    0x889986,\n    0x869784,\n    0x829380,\n    0x344532,\n    0x051603,\n    0x000900,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000B00,\n    0x000D00,\n    0x000E00,\n    0x000B04,\n    0x6E7877,\n    0x949D98,\n    0x979D99,\n    0x9AA199,\n    0xA0A59E,\n    0x95988D,\n    0x9C9F94,\n    0xA0A295,\n    0x9FA194,\n    0x9CA092,\n    0x9B9F91,\n    0x999F91,\n    0x999F91,\n    0x989E92,\n    0x979D91,\n    0x9DA695,\n    0xA0A998,\n    0xA3AA9A,\n    0xA2A999,\n    0xA3A798,\n    0xA4A698,\n    0xA1A395,\n    0x9D9E90,\n    0xA6A799,\n    0xA8A99B,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AB9D,\n    0xA9AD9E,\n    0xAAAE9F,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xABAD9F,\n    0xABAD9F,\n    0xA9B0A0,\n    0xAAB1A1,\n    0xA9B2A1,\n    0xA9B2A1,\n    0xA4AD9C,\n    0xA4AD9C,\n    0xA4AB9B,\n    0xA2A999,\n    0xA6AA9B,\n    0xAAAE9F,\n    0xACAEA0,\n    0xAAAC9E,\n    0xA7AA99,\n    0xAAAD9C,\n    0xACAF9E,\n    0xABAE9D,\n    0xA8AB9A,\n    0xA6A998,\n    0xA7AA99,\n    0xA8AB9A,\n    0xA8AB9A,\n    0xA7AA99,\n    0xA7AA99,\n    0xA7AA99,\n    0xA6A998,\n    0xA6A998,\n    0xA5A897,\n    0xA5A897,\n    0xA3A798,\n    0xA1A596,\n    0xA0A495,\n    0x9FA394,\n    0xA0A495,\n    0xA1A596,\n    0xA0A495,\n    0x9FA394,\n    0x9CA091,\n    0x9CA091,\n    0x9B9F90,\n    0x9A9E8F,\n    0x9A9E8F,\n    0x999D8E,\n    0x999D8E,\n    0x999D8E,\n    0x999B8D,\n    0x979B8C,\n    0x949B8B,\n    0x909B8A,\n    0x8F9C8A,\n    0x8E9D8A,\n    0x8A9D89,\n    0x8A9D89,\n    0x889E89,\n    0x889E89,\n    0x8A9D89,\n    0x8B9C89,\n    0x8D9C89,\n    0x8D9A88,\n    0x8E9988,\n    0x8C9987,\n    0x899885,\n    0x849582,\n    0x889986,\n    0x869784,\n    0x839481,\n    0x435441,\n    0x021300,\n    0x000D00,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000B00,\n    0x000D00,\n    0x000F00,\n    0x011009,\n    0x818D8B,\n    0x909C98,\n    0x8F9895,\n    0x97A199,\n    0x99A099,\n    0x9AA096,\n    0xA1A49B,\n    0x9C9F94,\n    0x9FA196,\n    0xA0A295,\n    0xA1A396,\n    0x9FA395,\n    0x9FA395,\n    0xA0A496,\n    0xA1A597,\n    0x9CA594,\n    0x9EA796,\n    0x9FA696,\n    0xA0A797,\n    0xA4A899,\n    0xA5A799,\n    0xA1A395,\n    0x9D9E90,\n    0xA7A89A,\n    0xA8A99B,\n    0xA9AB9D,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAE9F,\n    0xABAFA0,\n    0xABAD9F,\n    0xABAD9F,\n    0xAAAE9F,\n    0xABAFA0,\n    0xA9B0A0,\n    0xAAB1A1,\n    0xA9B2A1,\n    0xA9B2A1,\n    0xA4AD9C,\n    0xA2AB9A,\n    0x9CA393,\n    0x949B8B,\n    0x929687,\n    0x929687,\n    0x909284,\n    0x8C8E80,\n    0x96988A,\n    0x9A9C8E,\n    0x9D9F91,\n    0x9B9D8F,\n    0x97998B,\n    0x959789,\n    0x96988A,\n    0x999B8D,\n    0x989A8C,\n    0x989A8C,\n    0x989A8C,\n    0x97998B,\n    0x96988A,\n    0x96988A,\n    0x959789,\n    0x959789,\n    0x989C8D,\n    0x969A8B,\n    0x95998A,\n    0x95998A,\n    0x969A8B,\n    0x979B8C,\n    0x979B8C,\n    0x969A8B,\n    0x9A9E8F,\n    0x9B9F90,\n    0x9CA091,\n    0x9CA091,\n    0x9B9F90,\n    0x9A9E8F,\n    0x999D8E,\n    0x989C8D,\n    0x9B9D8F,\n    0x989A8C,\n    0x939A8A,\n    0x929B8A,\n    0x929D8C,\n    0x93A08E,\n    0x90A18E,\n    0x8FA08D,\n    0x8A9D89,\n    0x8A9D89,\n    0x8B9C89,\n    0x8C9D8A,\n    0x8D9C89,\n    0x8D9C89,\n    0x8D9A88,\n    0x8D9A88,\n    0x889986,\n    0x869784,\n    0x889986,\n    0x869784,\n    0x859683,\n    0x5A6B58,\n    0x000D00,\n    0x001100,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000D00,\n    0x000F00,\n    0x001006,\n    0x889993,\n    0x85948F,\n    0x818D89,\n    0x8A978E,\n    0x869088,\n    0x929991,\n    0x969992,\n    0x8E9188,\n    0x93948C,\n    0x97998E,\n    0x989A8F,\n    0x97998C,\n    0x97998C,\n    0x999B8E,\n    0x9A9E90,\n    0x979E8E,\n    0x969F8E,\n    0x989F8F,\n    0x9BA292,\n    0xA2A697,\n    0xA5A799,\n    0xA1A395,\n    0x9C9D8F,\n    0xA7A89A,\n    0xA9AA9C,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAC9E,\n    0xAAAE9F,\n    0xABAFA0,\n    0xAAAE9F,\n    0xAAAE9F,\n    0xA9B0A0,\n    0xA9B0A0,\n    0xA8B1A0,\n    0xA9B2A1,\n    0xA7B2A1,\n    0xA7B2A1,\n    0xACB5A4,\n    0xABB4A3,\n    0xA9B0A0,\n    0xA6AD9D,\n    0xA9AD9E,\n    0xAEB2A3,\n    0xB1B3A5,\n    0xB0B2A4,\n    0xA2A697,\n    0xA5A99A,\n    0xA7AB9C,\n    0xA7AB9C,\n    0xA6AA9B,\n    0xA5A99A,\n    0xA5A99A,\n    0xA7AB9C,\n    0xA3A798,\n    0xA2A697,\n    0xA2A697,\n    0xA1A596,\n    0xA0A495,\n    0xA0A495,\n    0x9FA394,\n    0x9FA394,\n    0x989C8D,\n    0x979B8C,\n    0x95998A,\n    0x95998A,\n    0x969A8B,\n    0x969A8B,\n    0x95998A,\n    0x949889,\n    0x888C7D,\n    0x888C7D,\n    0x888C7D,\n    0x888C7D,\n    0x878B7C,\n    0x868A7B,\n    0x85897A,\n    0x85897A,\n    0x8D8F81,\n    0x898B7D,\n    0x838A7A,\n    0x858C7C,\n    0x879281,\n    0x8B9685,\n    0x8A9986,\n    0x889784,\n    0x8B9C89,\n    0x8B9C89,\n    0x8C9D8A,\n    0x8C9D8A,\n    0x8E9D8A,\n    0x8E9D8A,\n    0x8D9C89,\n    0x8D9C89,\n    0x899A87,\n    0x899A87,\n    0x899A87,\n    0x859683,\n    0x869784,\n    0x6F806D,\n    0x000A00,\n    0x011200,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000D00,\n    0x000F00,\n    0x001409,\n    0x92A39D,\n    0x8FA09A,\n    0x939F9B,\n    0x9DAAA3,\n    0x939C97,\n    0x9BA59D,\n    0x999E98,\n    0x979C95,\n    0x9C9F98,\n    0x9FA098,\n    0x9FA098,\n    0x9C9E91,\n    0x9A9C8F,\n    0x999D8F,\n    0x9A9E90,\n    0x969F8E,\n    0x949D8C,\n    0x969D8D,\n    0x9BA292,\n    0xA3A798,\n    0xA4A698,\n    0xA0A294,\n    0x9E9F91,\n    0xA8A99B,\n    0xAAAB9D,\n    0xAAAC9E,\n    0xABAD9F,\n    0xABAD9F,\n    0xABAD9F,\n    0xABAFA0,\n    0xACB0A1,\n    0xA9B0A0,\n    0xA9B0A0,\n    0xA8B1A0,\n    0xA8B1A0,\n    0xA6B1A0,\n    0xA7B2A1,\n    0xA7B2A1,\n    0xA7B2A1,\n    0xA7B2A1,\n    0xA6AF9E,\n    0x9EA796,\n    0x969D8D,\n    0x949889,\n    0x939788,\n    0x929486,\n    0x8E9082,\n    0x9DA192,\n    0x9CA091,\n    0x9B9F90,\n    0x9CA091,\n    0x9EA293,\n    0x9EA293,\n    0x9CA091,\n    0x9A9E8F,\n    0xA4A899,\n    0xA4A899,\n    0xA3A798,\n    0xA2A697,\n    0xA2A697,\n    0xA1A596,\n    0xA0A495,\n    0xA0A495,\n    0xA4A899,\n    0xA2A697,\n    0xA0A495,\n    0x9FA394,\n    0x9FA394,\n    0x9FA394,\n    0x9DA192,\n    0x9CA091,\n    0xA0A495,\n    0x9EA293,\n    0x9DA192,\n    0x9B9F90,\n    0x9B9F90,\n    0x9B9F90,\n    0x9CA091,\n    0x9DA192,\n    0x9A9C8E,\n    0x96988A,\n    0x919586,\n    0x939788,\n    0x959E8D,\n    0x99A291,\n    0x96A391,\n    0x95A290,\n    0x8D9C89,\n    0x8E9D8A,\n    0x8C9D8A,\n    0x8C9D8A,\n    0x8D9E8B,\n    0x8C9D8A,\n    0x8C9D8A,\n    0x8C9D8A,\n    0x8A9B88,\n    0x8B9C89,\n    0x8A9B88,\n    0x859683,\n    0x879885,\n    0x7D8E7B,\n    0x000E00,\n    0x001100,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000C00,\n    0x000B00,\n    0x000C00,\n    0x000E00,\n    0x001000,\n    0x13241A,\n    0x93A49E,\n    0x909F9A,\n    0x929E9A,\n    0x98A4A0,\n    0x929B98,\n    0x9DA6A1,\n    0x9BA19D,\n    0x9DA29C,\n    0x9FA49E,\n    0xA2A59C,\n    0xA2A59C,\n    0xA0A698,\n    0xA0A698,\n    0xA0A797,\n    0xA1A898,\n    0x9BA493,\n    0x99A291,\n    0x9CA393,\n    0xA0A797,\n    0xA5A99A,\n    0xA4A698,\n    0xA1A395,\n    0xA0A193,\n    0xA8A99B,\n    0xAAAB9D,\n    0xABAD9F,\n    0xABAD9F,\n    0xABAD9F,\n    0xABAD9F,\n    0xABAFA0,\n    0xACB0A1,\n    0xA9B2A1,\n    0xA9B2A1,\n    0xA7B2A1,\n    0xA7B2A1,\n    0xA6B3A1,\n    0xA6B3A1,\n    0xA6B3A1,\n    0xA6B3A1,\n    0xA8B3A2,\n    0xAAB3A2,\n    0xA7B09F,\n    0xA6AD9D,\n    0xAAAE9F,\n    0xAFB1A3,\n    0xB1B3A5,\n    0xB0B1A3,\n    0xA8AC9E,\n    0xA4A89A,\n    0xA2A698,\n    0xA3A799,\n    0xA6AA9C,\n    0xA7AB9D,\n    0xA3A799,\n    0x9EA294,\n    0x9B9F91,\n    0x9A9E90,\n    0x9A9E90,\n    0x999D8F,\n    0x989C8E,\n    0x979B8D,\n    0x969A8C,\n    0x969A8C,\n    0x909485,\n    0x8E9283,\n    0x8C9081,\n    0x8B8F80,\n    0x8A8E7F,\n    0x898D7E,\n    0x888C7D,\n    0x868A7B,\n    0x8B8F80,\n    0x8A8E7F,\n    0x878B7C,\n    0x85897A,\n    0x85897A,\n    0x868A7B,\n    0x878B7C,\n    0x888C7D,\n    0x919385,\n    0x8E9082,\n    0x8B8D7F,\n    0x8A8C7E,\n    0x899080,\n    0x8A9181,\n    0x899281,\n    0x889180,\n    0x8E9B89,\n    0x8F9C8A,\n    0x8E9D8A,\n    0x8F9E8B,\n    0x8D9E8B,\n    0x8D9E8B,\n    0x8C9F8B,\n    0x8C9F8B,\n    0x8C9D8A,\n    0x8B9C89,\n    0x8B9C89,\n    0x869784,\n    0x899A87,\n    0x839481,\n    0x091A07,\n    0x001000,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000C00,\n    0x000B00,\n    0x000C00,\n    0x000E00,\n    0x001000,\n    0x1E2E23,\n    0x889790,\n    0x86928E,\n    0x838E8A,\n    0x828D89,\n    0x828B88,\n    0x929896,\n    0x929896,\n    0x929793,\n    0x919692,\n    0x919890,\n    0x939A92,\n    0x969E91,\n    0x98A093,\n    0x98A392,\n    0x98A392,\n    0x9BA493,\n    0x9AA392,\n    0x9DA494,\n    0xA2A999,\n    0xA5A99A,\n    0xA2A496,\n    0xA0A294,\n    0xA2A395,\n    0xA9AA9C,\n    0xAAAB9D,\n    0xABAD9F,\n    0xACAEA0,\n    0xACAEA0,\n    0xACAEA0,\n    0xACB0A1,\n    0xABB2A2,\n    0xA9B2A1,\n    0xA7B2A1,\n    0xA6B3A1,\n    0xA6B3A1,\n    0xA6B3A1,\n    0xA6B3A1,\n    0xA6B3A1,\n    0xA6B3A1,\n    0xA7B2A1,\n    0xA8B1A0,\n    0xA3AC9B,\n    0xA0A495,\n    0x9DA192,\n    0x9EA092,\n    0x9C9D8F,\n    0x97998B,\n    0xA6AA9C,\n    0xA2A89A,\n    0xA2A89A,\n    0xA4AA9C,\n    0xA7AD9F,\n    0xA7AD9F,\n    0xA5AB9D,\n    0xA3A99B,\n    0xA8AEA0,\n    0xA7AD9F,\n    0xA6AC9E,\n    0xA5AB9D,\n    0xA4AA9C,\n    0xA3A99B,\n    0xA2A89A,\n    0xA2A89A,\n    0xA5A99A,\n    0xA3A798,\n    0xA1A596,\n    0xA0A495,\n    0xA0A495,\n    0xA0A495,\n    0x9EA293,\n    0x9DA192,\n    0x9FA394,\n    0x9EA293,\n    0x9DA192,\n    0x9CA091,\n    0x9CA091,\n    0x9CA091,\n    0x9CA091,\n    0x9D9F91,\n    0x97998B,\n    0x97988A,\n    0x949688,\n    0x939587,\n    0x919586,\n    0x909485,\n    0x8D9484,\n    0x8C9383,\n    0x909B8A,\n    0x909B8A,\n    0x8F9E8B,\n    0x8F9E8B,\n    0x8DA08C,\n    0x8DA08C,\n    0x8C9F8B,\n    0x8C9F8B,\n    0x8C9D8A,\n    0x8A9B88,\n    0x8C9D8A,\n    0x879885,\n    0x8C9D8A,\n    0x869784,\n    0x1B2C19,\n    0x001100,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x000D00,\n    0x000C00,\n    0x000B00,\n    0x000C00,\n    0x000E00,\n    0x001000,\n    0x2C392F,\n    0x8E9B94,\n    0x97A29E,\n    0x9AA3A0,\n    0x97A09F,\n    0x989E9E,\n    0x9EA4A4,\n    0x9BA1A1,\n    0x9BA19D,\n    0x999F9B,\n    0x969D95,\n    0x979E96,\n    0x96A294,\n    0x98A496,\n    0x97A492,\n    0x97A291,\n    0x939E8D,\n    0x959E8D,\n    0x9AA191,\n    0xA0A797,\n    0xA3A798,\n    0xA0A294,\n    0x9FA193,\n    0xA3A496,\n    0xA9AA9C,\n    0xABAC9E,\n    0xABAD9F,\n    0xACAEA0,\n    0xACAEA0,\n    0xACAEA0,\n    0xACB0A1,\n    0xABB2A2,\n    0xA7B2A1,\n    0xA6B3A1,\n    0xA6B3A1,\n    0xA6B3A1,\n    0xA6B3A1,\n    0xA6B3A1,\n    0xA6B3A1,\n    0xA6B3A1,\n    0xA7B2A1,\n    0xA9B2A1,\n    0xA7B09F,\n    0xA6AA9B,\n    0xA5A99A,\n    0xA8AA9C,\n    0xA7A89A,\n    0xA2A496,\n    0x9CA092,\n    0x9CA294,\n    0x9FA597,\n    0xA2A89A,\n    0xA5AB9D,\n    0xA7AD9F,\n    0xA8AEA0,\n    0xA9AFA1,\n    0xA6AC9E,\n    0xA5AB9D,\n    0xA4AA9C,\n    0xA3A99B,\n    0xA2A89A,\n    0xA1A799,\n    0xA0A698,\n    0xA0A698,\n    0xA3A798,\n    0xA2A697,\n    0xA0A495,\n    0x9FA394,\n    0xA0A495,\n    0xA0A495,\n    0x9FA394,\n    0x9EA293,\n    0x9CA091,\n    0x9CA091,\n    0x9DA192,\n    0x9DA192,\n    0x9CA091,\n    0x9B9F90,\n    0x9A9E8F,\n    0x9A9C8E,\n    0x9A9C8E,\n    0x9B9C8E,\n    0x9B9D8F,\n    0x9A9C8E,\n    0x979B8C,\n    0x95998A,\n    0x939A8A,\n    0x949B8B,\n    0x909B8A,\n    0x909B8A,\n    0x8F9E8B,\n    0x8F9E8B,\n    0x8DA08C,\n    0x8DA08C,\n    0x8BA18C,\n    0x8DA08C,\n    0x8B9E8A,\n    0x899A87,\n    0x8D9E8B,\n    0x899A87,\n    0x8FA08D,\n    0x869784,\n    0x273825,\n    0x011200,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000E00,\n    0x001101,\n    0x37443A,\n    0x8F9C95,\n    0x96A19B,\n    0x95A09A,\n    0x97A29A,\n    0x97A29A,\n    0x96A298,\n    0x9DA99F,\n    0x99A398,\n    0x9BA59A,\n    0x9DA89A,\n    0x9FAA9C,\n    0xA0AB9B,\n    0xA0AB9B,\n    0xA2AB9A,\n    0x9FAA99,\n    0x9AA796,\n    0x9CA998,\n    0x9EAB9A,\n    0xA2AA9B,\n    0xA2AA9B,\n    0xA3A799,\n    0xA1A597,\n    0xA1A396,\n    0xABAB9F,\n    0xACACA0,\n    0xADADA1,\n    0xAEAEA2,\n    0xAEAEA2,\n    0xAEAEA2,\n    0xADAFA2,\n    0xACB0A2,\n    0xA7B2A1,\n    0xA7B4A2,\n    0xA6B5A2,\n    0xA6B5A2,\n    0xA6B5A2,\n    0xA6B5A2,\n    0xA4B5A3,\n    0xA3B4A2,\n    0xA4B5A3,\n    0xA8B6A5,\n    0x9FAD9E,\n    0xA3AFA1,\n    0xA4AFA1,\n    0xA1AC9E,\n    0xACB4A7,\n    0xABB1A5,\n    0xAAB1A1,\n    0xACB0A1,\n    0xABB2A2,\n    0xACB3A3,\n    0xA8AF9F,\n    0xA4AB9B,\n    0xA5AE9D,\n    0xABB4A3,\n    0xA6B1A0,\n    0xA4AF9E,\n    0xA3AE9D,\n    0xA4AF9E,\n    0xA1AE9C,\n    0x9DAA98,\n    0x9CA997,\n    0x9DAA98,\n    0x9BAA95,\n    0x99A893,\n    0x99A692,\n    0x9AA793,\n    0x9DA995,\n    0x9DA995,\n    0x9DA693,\n    0x9AA390,\n    0x9BA290,\n    0x9DA190,\n    0x9CA08F,\n    0x9C9F8E,\n    0x9D9E8E,\n    0x9D9E8E,\n    0x9D9E8E,\n    0x9D9E8E,\n    0x9A9B8D,\n    0x9A9B8D,\n    0x999B8D,\n    0x999B8D,\n    0x959C8C,\n    0x969D8D,\n    0x969F8E,\n    0x97A08F,\n    0x909D8B,\n    0x909D8B,\n    0x8D9E8B,\n    0x8D9E8B,\n    0x8C9F8B,\n    0x8C9F8B,\n    0x8AA08B,\n    0x8C9F8B,\n    0x8C9F8B,\n    0x90A18E,\n    0x889986,\n    0x8C9D8A,\n    0x90A18E,\n    0x81927F,\n    0x425340,\n    0x000D00,\n    0x000E00,\n    0x000C00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000E00,\n    0x001101,\n    0x404D44,\n    0x8E9A96,\n    0x8C9793,\n    0x88938F,\n    0x8A958F,\n    0x8B9690,\n    0x8A958D,\n    0x8F9A92,\n    0x949E95,\n    0x949E95,\n    0x949F91,\n    0x939E90,\n    0x939E90,\n    0x939E90,\n    0x959D8E,\n    0x949F8F,\n    0x9EAB9A,\n    0x9DAB9A,\n    0x9EAB9A,\n    0x9FAA9A,\n    0x9EA999,\n    0xA0A698,\n    0xA0A698,\n    0xA2A497,\n    0xABADA0,\n    0xACACA0,\n    0xADADA1,\n    0xAEAEA2,\n    0xAEAEA2,\n    0xAEAEA2,\n    0xADAFA2,\n    0xACB0A2,\n    0xA7B2A1,\n    0xA7B4A2,\n    0xA6B5A2,\n    0xA6B5A2,\n    0xA6B5A2,\n    0xA6B5A2,\n    0xA4B5A3,\n    0xA3B4A2,\n    0x9BAC9A,\n    0xA3B1A0,\n    0xA1AFA0,\n    0xACB8AA,\n    0xB0BBAD,\n    0xAAB5A7,\n    0xAFB7AA,\n    0xA7AFA2,\n    0xA3AA9A,\n    0xA4AB9B,\n    0xA6AD9D,\n    0xA8AF9F,\n    0xA8B1A0,\n    0xA7B09F,\n    0xA2AD9C,\n    0xA0AB9A,\n    0xA1AC9B,\n    0x9FAA99,\n    0x9FAC9A,\n    0xA2AF9D,\n    0xA2B19E,\n    0xA0AF9C,\n    0xA0AF9C,\n    0xA2B19E,\n    0xA2B19C,\n    0x9FAE99,\n    0x9CAB96,\n    0x9AA994,\n    0x9AA793,\n    0x99A692,\n    0x99A591,\n    0x98A490,\n    0x9AA692,\n    0x99A591,\n    0x9AA390,\n    0x99A28F,\n    0x99A08E,\n    0x989F8D,\n    0x989F8D,\n    0x989F8D,\n    0x989F8F,\n    0x989F8F,\n    0x989F8F,\n    0x979E8E,\n    0x959E8D,\n    0x949D8C,\n    0x919E8C,\n    0x919E8C,\n    0x909F8C,\n    0x909F8C,\n    0x8E9F8C,\n    0x8E9F8C,\n    0x8DA08C,\n    0x8DA08C,\n    0x8BA18C,\n    0x8DA08C,\n    0x8EA18D,\n    0x8FA08D,\n    0x8A9B88,\n    0x8B9C89,\n    0x8E9F8C,\n    0x859683,\n    0x4F604D,\n    0x000F00,\n    0x000E00,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000C00,\n    0x000F00,\n    0x001101,\n    0x4B5851,\n    0x919D9B,\n    0x919B9A,\n    0x959F9E,\n    0x9AA5A1,\n    0x98A39F,\n    0x929D97,\n    0x919C96,\n    0x9CA69E,\n    0x9AA49C,\n    0x99A39A,\n    0x97A198,\n    0x97A196,\n    0x97A196,\n    0x9BA396,\n    0x99A496,\n    0x9FAC9B,\n    0x9EAC9B,\n    0x9EAB9A,\n    0x9EA999,\n    0x9DA898,\n    0xA0A698,\n    0xA0A698,\n    0xA2A698,\n    0xABADA0,\n    0xABADA0,\n    0xADADA1,\n    0xAEAEA2,\n    0xADAFA2,\n    0xAEB0A3,\n    0xAEB0A3,\n    0xACB0A2,\n    0xA8B3A2,\n    0xA7B4A2,\n    0xA6B5A2,\n    0xA7B6A3,\n    0xA7B6A3,\n    0xA6B5A2,\n    0xA4B5A3,\n    0xA4B5A3,\n    0x94A593,\n    0x97A594,\n    0x8D9B8C,\n    0x929E90,\n    0x96A193,\n    0x949F91,\n    0x9CA497,\n    0x959D90,\n    0xA1AA99,\n    0xA2AB9A,\n    0xA0A998,\n    0x9FA897,\n    0xA2AD9C,\n    0xA6B1A0,\n    0xA0AD9B,\n    0x96A391,\n    0x9AA795,\n    0x98A593,\n    0x98A794,\n    0x9BAA97,\n    0x9AAB98,\n    0x98A996,\n    0x98A996,\n    0x9AAB98,\n    0x94A592,\n    0x96A794,\n    0x99AA97,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9DAC99,\n    0x9DAC99,\n    0x9BAA97,\n    0x9AA996,\n    0x98A794,\n    0x97A693,\n    0x95A491,\n    0x94A390,\n    0x94A390,\n    0x93A28F,\n    0x95A491,\n    0x95A491,\n    0x95A491,\n    0x94A390,\n    0x94A390,\n    0x93A28F,\n    0x8FA08D,\n    0x8FA08D,\n    0x8E9F8C,\n    0x8E9F8C,\n    0x8E9F8C,\n    0x8E9F8C,\n    0x8DA08C,\n    0x8DA08C,\n    0x8DA08C,\n    0x8DA08C,\n    0x90A18E,\n    0x8D9E8B,\n    0x8C9D8A,\n    0x8C9D8A,\n    0x8B9C89,\n    0x8A9B88,\n    0x61725F,\n    0x001100,\n    0x000E00,\n    0x000D00,\n    0x000B00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000900,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x000F00,\n    0x011202,\n    0x596561,\n    0x94A0A0,\n    0x919B9C,\n    0x99A3A4,\n    0x9CA6A5,\n    0x9CA6A5,\n    0x99A4A0,\n    0x98A39F,\n    0x9EA7A2,\n    0x9DA6A1,\n    0x9DA79E,\n    0x9CA69D,\n    0x9DA79E,\n    0x9EA89F,\n    0xA1A99E,\n    0xA0AA9F,\n    0x9BA998,\n    0x9CAA99,\n    0x9CAA99,\n    0x9EA999,\n    0x9EA999,\n    0xA0A698,\n    0xA0A698,\n    0xA1A597,\n    0xABADA0,\n    0xABADA0,\n    0xACAEA1,\n    0xADAFA2,\n    0xAEB0A3,\n    0xAEB0A3,\n    0xAEB0A3,\n    0xADB1A3,\n    0xA8B3A2,\n    0xA7B4A2,\n    0xA7B6A3,\n    0xA7B6A3,\n    0xA7B6A3,\n    0xA7B6A3,\n    0xA4B5A3,\n    0xA4B5A3,\n    0x9AAB99,\n    0x9AA897,\n    0x8B998A,\n    0x8C988A,\n    0x909B8D,\n    0x919C8E,\n    0x9AA295,\n    0x929A8D,\n    0x8E9687,\n    0x8E9687,\n    0x859080,\n    0x7D8878,\n    0x808B7B,\n    0x8A9585,\n    0x879483,\n    0x7C8978,\n    0x7E8C7B,\n    0x7C8A79,\n    0x798A78,\n    0x7A8B79,\n    0x788977,\n    0x748573,\n    0x728572,\n    0x748573,\n    0x7F907D,\n    0x899885,\n    0x90A18E,\n    0x97A895,\n    0x98A996,\n    0x96A794,\n    0x93A692,\n    0x93A692,\n    0x94AA95,\n    0x93A994,\n    0x92A893,\n    0x91A792,\n    0x8FA791,\n    0x8EA690,\n    0x8DA58F,\n    0x8DA58F,\n    0x8EA48F,\n    0x8EA48F,\n    0x8EA48F,\n    0x8FA590,\n    0x91A490,\n    0x91A490,\n    0x8FA28E,\n    0x8EA18D,\n    0x8EA18D,\n    0x8EA18D,\n    0x8EA18D,\n    0x8EA18D,\n    0x8FA08D,\n    0x8FA08D,\n    0x8FA08D,\n    0x8FA08D,\n    0x90A18E,\n    0x8B9C89,\n    0x8FA08D,\n    0x8D9E8B,\n    0x8A9B88,\n    0x8D9E8B,\n    0x71826F,\n    0x001100,\n    0x000F00,\n    0x000D00,\n    0x000B00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000D00,\n    0x001000,\n    0x021303,\n    0x687470,\n    0x94A0A0,\n    0x879192,\n    0x8A9495,\n    0x889291,\n    0x899392,\n    0x919C98,\n    0x96A19D,\n    0x939C97,\n    0x949D98,\n    0x959F96,\n    0x96A097,\n    0x96A097,\n    0x96A097,\n    0x98A095,\n    0x959F94,\n    0x97A594,\n    0x97A896,\n    0x9CAA99,\n    0x9FAC9B,\n    0x9FAC9B,\n    0xA1A99A,\n    0x9EA697,\n    0xA0A496,\n    0xAAAEA0,\n    0xACAEA1,\n    0xADAFA2,\n    0xADAFA2,\n    0xAEB0A3,\n    0xAEB0A3,\n    0xADB1A3,\n    0xABB1A3,\n    0xA8B3A2,\n    0xA7B4A2,\n    0xA7B6A3,\n    0xA7B6A3,\n    0xA7B6A3,\n    0xA7B6A3,\n    0xA4B5A3,\n    0xA4B5A3,\n    0xA3B4A2,\n    0xA9B7A6,\n    0xA2B0A1,\n    0xA8B4A6,\n    0xAEB9AB,\n    0xADB8AA,\n    0xB0B8AB,\n    0xA3AB9E,\n    0xABB3A4,\n    0xAEB6A7,\n    0xA9B1A2,\n    0xA0A899,\n    0x9FAA9A,\n    0xA8B3A3,\n    0xA7B4A3,\n    0x9FAC9B,\n    0xA2AF9E,\n    0x9FAC9B,\n    0x9DAB9A,\n    0x9EAC9B,\n    0x9BAC9A,\n    0x97A896,\n    0x95A694,\n    0x96A795,\n    0x909F8C,\n    0x96A592,\n    0x9DAC99,\n    0xA0AF9C,\n    0x9CAD9A,\n    0x98A996,\n    0x94A793,\n    0x93A692,\n    0x92A893,\n    0x92A893,\n    0x90A892,\n    0x8FA791,\n    0x8FA791,\n    0x8FA791,\n    0x8EA791,\n    0x8EA791,\n    0x8DA58F,\n    0x8CA48E,\n    0x8BA38D,\n    0x8CA48E,\n    0x8EA48F,\n    0x8EA48F,\n    0x8CA28D,\n    0x8AA08B,\n    0x8FA28E,\n    0x8FA28E,\n    0x8FA28E,\n    0x8FA28E,\n    0x90A18E,\n    0x90A18E,\n    0x90A18E,\n    0x90A18E,\n    0x8E9F8C,\n    0x8B9C89,\n    0x91A28F,\n    0x8FA08D,\n    0x8C9D8A,\n    0x8E9F8C,\n    0x7C8D7A,\n    0x021300,\n    0x000F00,\n    0x000D00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000D00,\n    0x001100,\n    0x021303,\n    0x6F7C75,\n    0x95A19F,\n    0x8D9796,\n    0x98A2A1,\n    0x95A09C,\n    0x929D99,\n    0x96A19B,\n    0x97A29C,\n    0x959F97,\n    0x96A098,\n    0x97A198,\n    0x98A299,\n    0x97A196,\n    0x96A095,\n    0x969E91,\n    0x939E90,\n    0x96A493,\n    0x96A795,\n    0x9CAA99,\n    0xA0AD9C,\n    0xA1AE9D,\n    0xA2AA9B,\n    0x9EA697,\n    0x9DA395,\n    0xABAFA1,\n    0xABAFA1,\n    0xADAFA2,\n    0xAEB0A3,\n    0xADB1A3,\n    0xADB1A3,\n    0xADB1A3,\n    0xABB1A3,\n    0xA8B3A2,\n    0xA8B5A3,\n    0xA7B6A3,\n    0xA7B6A3,\n    0xA7B6A3,\n    0xA7B6A3,\n    0xA5B6A4,\n    0xA4B5A3,\n    0xA2B3A1,\n    0xA8B6A5,\n    0x9EAC9D,\n    0x9FAB9D,\n    0xA3AEA0,\n    0xA3AEA0,\n    0xA9B1A4,\n    0x9EA699,\n    0x9FA599,\n    0xA5AB9F,\n    0xA8AEA2,\n    0xA5AB9F,\n    0xA4AC9F,\n    0xA8B0A3,\n    0xA7AFA2,\n    0xA2AA9D,\n    0xA2AD9F,\n    0xA0AB9D,\n    0xA0AC9E,\n    0xA3AFA1,\n    0xA3B1A2,\n    0xA1AFA0,\n    0xA1AFA0,\n    0xA3B1A2,\n    0xA1AE9D,\n    0xA1AE9D,\n    0x9FAC9B,\n    0x9DAA99,\n    0x9BA897,\n    0x9BA897,\n    0x9BA998,\n    0x9CAA99,\n    0x98A997,\n    0x98A997,\n    0x97A896,\n    0x97A896,\n    0x95A895,\n    0x95A895,\n    0x96A996,\n    0x96A996,\n    0x94AA95,\n    0x91A792,\n    0x8EA48F,\n    0x8EA48F,\n    0x92A591,\n    0x92A591,\n    0x91A490,\n    0x8FA28E,\n    0x90A38F,\n    0x90A38F,\n    0x90A38F,\n    0x90A38F,\n    0x91A28F,\n    0x91A28F,\n    0x91A28F,\n    0x91A28F,\n    0x8D9E8B,\n    0x8E9F8C,\n    0x92A390,\n    0x8E9F8C,\n    0x90A18E,\n    0x8C9D8A,\n    0x849582,\n    0x0C1D0A,\n    0x000F00,\n    0x000D00,\n    0x000C00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x000B00,\n    0x000C00,\n    0x000E00,\n    0x001100,\n    0x031404,\n    0x78857C,\n    0x98A4A0,\n    0x919C98,\n    0xA4AFAB,\n    0xA3AEA8,\n    0x9EA9A3,\n    0x9DA8A0,\n    0x97A29A,\n    0x9EA89F,\n    0x9EA89F,\n    0x9EA99B,\n    0x9EA99B,\n    0x9EA99B,\n    0x9EA99B,\n    0x9FA798,\n    0x9DA898,\n    0x98A997,\n    0x9AAB99,\n    0x9DAE9C,\n    0xA1AE9D,\n    0xA1AE9D,\n    0xA2AA9B,\n    0x9FA798,\n    0x9EA496,\n    0xABAFA1,\n    0xABAFA1,\n    0xACB0A2,\n    0xADB1A3,\n    0xADB1A3,\n    0xAEB2A4,\n    0xAEB2A4,\n    0xABB1A3,\n    0xA9B4A3,\n    0xA8B5A3,\n    0xA7B6A3,\n    0xA8B7A4,\n    0xA8B7A4,\n    0xA7B6A3,\n    0xA5B6A4,\n    0xA5B6A4,\n    0x9FB09E,\n    0xA4B2A1,\n    0x94A293,\n    0x8E9A8C,\n    0x8E998B,\n    0x919C8E,\n    0x9CA497,\n    0x969C90,\n    0x8E9186,\n    0x929489,\n    0x96988D,\n    0x999B90,\n    0x999C91,\n    0x999C91,\n    0x969C90,\n    0x949A8E,\n    0x939B8E,\n    0x91998C,\n    0x929A8D,\n    0x959D90,\n    0x939E90,\n    0x919C8E,\n    0x919C8E,\n    0x939E90,\n    0x99A192,\n    0x959D8E,\n    0x8E9989,\n    0x8B9686,\n    0x8C9787,\n    0x8F9A8A,\n    0x929D8D,\n    0x949F8F,\n    0x98A393,\n    0x97A292,\n    0x96A191,\n    0x95A090,\n    0x94A190,\n    0x93A08F,\n    0x93A08F,\n    0x93A08F,\n    0x92A390,\n    0x8FA08D,\n    0x8C9D8A,\n    0x8D9E8B,\n    0x91A28F,\n    0x94A592,\n    0x94A592,\n    0x93A491,\n    0x91A28F,\n    0x91A28F,\n    0x91A28F,\n    0x91A28F,\n    0x91A28F,\n    0x91A28F,\n    0x90A38F,\n    0x90A38F,\n    0x8E9F8C,\n    0x91A28F,\n    0x91A28F,\n    0x8B9C89,\n    0x94A592,\n    0x8B9C89,\n    0x8B9C89,\n    0x1B2C19,\n    0x000F00,\n    0x000E00,\n    0x000C00,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x000B00,\n    0x000C00,\n    0x000E00,\n    0x001100,\n    0x031404,\n    0x869389,\n    0x96A39C,\n    0x7F8A84,\n    0x8B9690,\n    0x8A958D,\n    0x8B968E,\n    0x919D93,\n    0x8E9A90,\n    0x9AA499,\n    0x9AA499,\n    0x99A496,\n    0x99A496,\n    0x9AA595,\n    0x9CA797,\n    0xA1AA99,\n    0xA0AB9A,\n    0x9EAF9D,\n    0x9DB09D,\n    0x9EAF9D,\n    0xA0AE9D,\n    0xA0AD9C,\n    0xA1A99A,\n    0x9FA798,\n    0x9FA597,\n    0xABAFA1,\n    0xABAFA1,\n    0xACB0A2,\n    0xADB1A3,\n    0xADB1A3,\n    0xAEB2A4,\n    0xACB2A4,\n    0xABB3A4,\n    0xA9B4A3,\n    0xA8B5A3,\n    0xA7B6A3,\n    0xA8B7A4,\n    0xA8B7A4,\n    0xA7B6A3,\n    0xA5B6A4,\n    0xA5B6A4,\n    0xA2B3A1,\n    0xADBBAA,\n    0xA7B5A6,\n    0xA6B2A4,\n    0xA6B1A3,\n    0xA6B1A3,\n    0xADB5A8,\n    0xA4AA9E,\n    0xABADA2,\n    0xA9A99F,\n    0xA8A89E,\n    0xACACA2,\n    0xADAFA4,\n    0xACAEA3,\n    0xABAEA3,\n    0xADB0A5,\n    0xA7ADA1,\n    0xA4AA9E,\n    0xA3A99D,\n    0xA4AA9E,\n    0xA2AA9D,\n    0x9EA699,\n    0x9CA497,\n    0x9DA598,\n    0x9DA596,\n    0x98A091,\n    0x939B8C,\n    0x909889,\n    0x91998A,\n    0x939B8C,\n    0x949A8C,\n    0x93998B,\n    0x8F9587,\n    0x8E9486,\n    0x8D9385,\n    0x8B9183,\n    0x8A9082,\n    0x898F81,\n    0x898F81,\n    0x878F80,\n    0x889382,\n    0x84917F,\n    0x828F7D,\n    0x859280,\n    0x8A9986,\n    0x909F8C,\n    0x93A28F,\n    0x93A28F,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x91A490,\n    0x91A490,\n    0x8E9F8C,\n    0x93A491,\n    0x90A18E,\n    0x899A87,\n    0x96A794,\n    0x8A9B88,\n    0x8FA08D,\n    0x273825,\n    0x000F00,\n    0x000E00,\n    0x000C00,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000B00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000900,\n    0x000F00,\n    0x000700,\n    0x001100,\n    0x000900,\n    0x000C00,\n    0x001003,\n    0x08180E,\n    0x90A096,\n    0x909F98,\n    0x929F98,\n    0x939E98,\n    0x939E96,\n    0x949E96,\n    0x969D96,\n    0x969D96,\n    0x979E97,\n    0x979E97,\n    0x969D95,\n    0x959C94,\n    0x929C93,\n    0x939D94,\n    0x96A298,\n    0x98A59B,\n    0x9DAE9E,\n    0x9FB1A1,\n    0x9CAE9E,\n    0x9DAE9E,\n    0xA1B2A2,\n    0x9FAB9D,\n    0x9BA897,\n    0xA1AC9C,\n    0xA9B1A2,\n    0xAAB0A2,\n    0xAAB1A1,\n    0xAEB0A2,\n    0xAEB0A2,\n    0xAFB0A2,\n    0xAFB0A2,\n    0xAEB2A3,\n    0xA8B5A1,\n    0xA5B7A1,\n    0xA5B7A1,\n    0xA5B7A1,\n    0xA5B6A3,\n    0xA5B6A3,\n    0xA7B6A3,\n    0xA7B6A3,\n    0xA5B4A1,\n    0xAAB9A6,\n    0xAFBCAB,\n    0xADBAA9,\n    0xA6B3A2,\n    0xA2AF9E,\n    0xA4B1A0,\n    0xA9B4A4,\n    0xA9B1A2,\n    0xA9AFA1,\n    0xA8AEA0,\n    0xA9AFA1,\n    0xABB1A3,\n    0xABB1A3,\n    0xA9AFA1,\n    0xA7AD9F,\n    0xA7AD9F,\n    0xA5AB9D,\n    0xA3A99B,\n    0xA2A89A,\n    0xA4AA9C,\n    0xA6AC9E,\n    0xA7AD9F,\n    0xA9AD9F,\n    0xA6AA9C,\n    0xA7A99C,\n    0xA6A89B,\n    0xA5A79A,\n    0xA4A699,\n    0xA3A598,\n    0xA2A698,\n    0xA1A597,\n    0x9FA395,\n    0x9EA294,\n    0x9BA193,\n    0x9BA193,\n    0x9BA193,\n    0x9BA193,\n    0x999F91,\n    0x979F90,\n    0x95A491,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x91A28F,\n    0x91A28F,\n    0x91A28F,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x91A28F,\n    0x94A592,\n    0x8C9D8A,\n    0x96A794,\n    0x8FA08D,\n    0x91A28F,\n    0x8C9D8A,\n    0x3E4F3C,\n    0x000D00,\n    0x000D00,\n    0x000D00,\n    0x000C00,\n    0x000C00,\n    0x000C00,\n    0x000A00,\n    0x000700,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000900,\n    0x000E00,\n    0x000700,\n    0x001100,\n    0x000900,\n    0x000D00,\n    0x001003,\n    0x0E1E14,\n    0x91A197,\n    0x92A19A,\n    0x95A29B,\n    0x98A39D,\n    0x9AA59D,\n    0x9DA79F,\n    0xA0A7A0,\n    0xA1A8A1,\n    0xA0A7A0,\n    0xA0A7A0,\n    0xA0A79F,\n    0x9EA59D,\n    0x9CA69D,\n    0x9DA79E,\n    0xA0ACA2,\n    0xA2AFA5,\n    0x9DAE9E,\n    0x9FB1A1,\n    0x9DAE9E,\n    0x9DAE9E,\n    0xA3B1A2,\n    0x9EAC9D,\n    0x9BA897,\n    0xA0AD9C,\n    0xA7B2A2,\n    0xA7B2A2,\n    0xAAB3A2,\n    0xAAB3A2,\n    0xABB2A2,\n    0xABB2A2,\n    0xADB1A2,\n    0xACB3A3,\n    0xA7B6A1,\n    0xA5B7A1,\n    0xA5B7A1,\n    0xA5B7A1,\n    0xA5B6A3,\n    0xA5B6A3,\n    0xA7B6A3,\n    0xA7B6A3,\n    0x9FAE9B,\n    0x9DAC99,\n    0x99A695,\n    0x909D8C,\n    0x8A9786,\n    0x8B9887,\n    0x929F8E,\n    0x99A494,\n    0x9BA394,\n    0x989E90,\n    0x959B8D,\n    0x959B8D,\n    0x979D8F,\n    0x979D8F,\n    0x959B8D,\n    0x92988A,\n    0x9EA496,\n    0x9DA395,\n    0x9BA193,\n    0x9BA193,\n    0x9BA193,\n    0x9BA193,\n    0x9AA092,\n    0x989E90,\n    0x9B9F91,\n    0x9CA092,\n    0x9EA294,\n    0xA0A496,\n    0x9FA597,\n    0x9EA496,\n    0x9DA395,\n    0x9DA395,\n    0xA1A799,\n    0xA0A698,\n    0x9EA697,\n    0x9FA798,\n    0x9FA798,\n    0x9FA798,\n    0x9EA697,\n    0x9AA595,\n    0x95A491,\n    0x93A491,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x91A28F,\n    0x91A28F,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x90A18E,\n    0x94A592,\n    0x8E9F8C,\n    0x96A794,\n    0x8FA08D,\n    0x91A28F,\n    0x8D9E8B,\n    0x485946,\n    0x001000,\n    0x001000,\n    0x000E00,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000900,\n    0x000D00,\n    0x000700,\n    0x001000,\n    0x000900,\n    0x000D00,\n    0x001003,\n    0x18281E,\n    0x90A096,\n    0x909F98,\n    0x929F98,\n    0x949F99,\n    0x949F97,\n    0x959F97,\n    0x979E97,\n    0x989F98,\n    0x9EA59E,\n    0x9EA59E,\n    0x9EA59D,\n    0x9DA49C,\n    0x9BA59C,\n    0x9CA69D,\n    0x9FABA1,\n    0xA1ADA3,\n    0x9DAE9E,\n    0x9FB0A0,\n    0x9DAE9E,\n    0x9DAE9E,\n    0xA1B2A2,\n    0x9CAD9D,\n    0x9AA897,\n    0xA0AE9D,\n    0xA5B3A2,\n    0xA6B4A3,\n    0xA7B4A2,\n    0xA7B4A2,\n    0xA7B4A2,\n    0xA7B4A2,\n    0xA8B5A3,\n    0xA8B5A3,\n    0xA6B8A2,\n    0xA6B8A2,\n    0xA6B8A2,\n    0xA6B8A2,\n    0xA6B7A4,\n    0xA6B7A4,\n    0xA8B7A4,\n    0xA8B7A4,\n    0xADBCA9,\n    0xACBBA8,\n    0xACB9A8,\n    0xA9B6A5,\n    0xA7B4A3,\n    0xA7B4A3,\n    0xA9B6A5,\n    0xACB7A7,\n    0xA9B4A4,\n    0xA8B0A1,\n    0xA4AC9D,\n    0xA4AC9D,\n    0xA6AE9F,\n    0xA6AE9F,\n    0xA4AC9D,\n    0xA1A99A,\n    0x9CA495,\n    0x9BA394,\n    0x9BA394,\n    0x9BA394,\n    0x9BA394,\n    0x9AA293,\n    0x98A091,\n    0x959D8E,\n    0x99A192,\n    0x9BA394,\n    0x9EA697,\n    0xA1A99A,\n    0xA3AB9C,\n    0xA3AB9C,\n    0x9FAA9A,\n    0x9EA999,\n    0x9BA696,\n    0x9AA595,\n    0x97A493,\n    0x97A493,\n    0x98A594,\n    0x97A493,\n    0x95A291,\n    0x93A08F,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x90A18E,\n    0x94A592,\n    0x90A18E,\n    0x96A794,\n    0x8E9F8C,\n    0x91A28F,\n    0x90A18E,\n    0x586956,\n    0x021300,\n    0x001100,\n    0x000F00,\n    0x000C00,\n    0x000A00,\n    0x000900,\n    0x000A00,\n    0x000C00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000C00,\n    0x000800,\n    0x000F00,\n    0x000A00,\n    0x000E01,\n    0x011104,\n    0x26362C,\n    0x91A197,\n    0x91A099,\n    0x929F98,\n    0x939E98,\n    0x929D95,\n    0x939D95,\n    0x959C95,\n    0x949B94,\n    0x949B94,\n    0x959C95,\n    0x959C94,\n    0x949B93,\n    0x929C93,\n    0x949E95,\n    0x96A298,\n    0x99A59B,\n    0x9DAE9E,\n    0x9FB0A0,\n    0x9DAE9E,\n    0x9EAF9F,\n    0xA2B3A3,\n    0x9DAE9E,\n    0x99AA98,\n    0x9EAF9D,\n    0xA4B5A3,\n    0xA4B5A3,\n    0xA3B6A2,\n    0xA3B6A2,\n    0xA4B7A3,\n    0xA4B7A3,\n    0xA4B7A3,\n    0xA4B7A3,\n    0xA6B8A2,\n    0xA6B8A2,\n    0xA6B8A2,\n    0xA6B8A2,\n    0xA6B7A4,\n    0xA6B7A4,\n    0xA8B7A4,\n    0xA8B7A4,\n    0xA5B4A1,\n    0xA4B3A0,\n    0xA5B2A1,\n    0xA6B3A2,\n    0xA6B3A2,\n    0xA5B2A1,\n    0xA4B1A0,\n    0xA3AE9E,\n    0xA7B2A2,\n    0xA9B1A2,\n    0xAAB2A3,\n    0xABB3A4,\n    0xAAB2A3,\n    0xAAB2A3,\n    0xA9B1A2,\n    0xA9B1A2,\n    0xA7AFA0,\n    0xA6AE9F,\n    0xA6AE9F,\n    0xA7AFA0,\n    0xA8B0A1,\n    0xA8B0A1,\n    0xA7AFA0,\n    0xA6AE9F,\n    0x9AA796,\n    0x9BA897,\n    0x9CA998,\n    0x9EAB9A,\n    0x9EAB9A,\n    0x9DAA99,\n    0x9CA998,\n    0x9BA897,\n    0x9DAB9A,\n    0x9CAA99,\n    0x9BA998,\n    0x9BA998,\n    0x9BA998,\n    0x9AA897,\n    0x96A795,\n    0x94A593,\n    0x94A592,\n    0x94A592,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x92A390,\n    0x90A18E,\n    0x94A592,\n    0x93A491,\n    0x95A693,\n    0x8E9F8C,\n    0x91A28F,\n    0x92A390,\n    0x6B7C69,\n    0x021300,\n    0x001000,\n    0x000E00,\n    0x000D00,\n    0x000A00,\n    0x000800,\n    0x000900,\n    0x000C00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000900,\n    0x000E00,\n    0x000B00,\n    0x000E01,\n    0x011104,\n    0x35453B,\n    0x94A49A,\n    0x95A49D,\n    0x98A59E,\n    0x9AA59F,\n    0x9CA79F,\n    0x9FA9A1,\n    0xA2A9A2,\n    0xA2A9A2,\n    0xA0A7A0,\n    0xA1A8A1,\n    0xA2A9A1,\n    0xA2A9A1,\n    0xA0AAA1,\n    0xA1ABA2,\n    0xA3AFA5,\n    0xA5B1A7,\n    0x9FAD9E,\n    0xA1AFA0,\n    0x9DAE9E,\n    0x9EAF9F,\n    0xA2B3A3,\n    0x9DAE9E,\n    0x99AA98,\n    0x9FB09E,\n    0xA3B6A3,\n    0xA3B6A3,\n    0xA3B6A2,\n    0xA3B6A2,\n    0xA2B8A3,\n    0xA2B8A3,\n    0xA2B8A3,\n    0xA4B7A3,\n    0xA5B8A2,\n    0xA6B8A2,\n    0xA6B8A2,\n    0xA6B8A2,\n    0xA6B7A4,\n    0xA6B7A4,\n    0xA8B7A4,\n    0xA8B7A4,\n    0xA5B4A1,\n    0x9EAD9A,\n    0x96A392,\n    0x8F9C8B,\n    0x8E9B8A,\n    0x909D8C,\n    0x93A08F,\n    0x94A190,\n    0x939E8E,\n    0x99A494,\n    0x9EA999,\n    0x9EA999,\n    0x9AA595,\n    0x96A191,\n    0x97A292,\n    0x99A494,\n    0x9FAA9A,\n    0x9DA898,\n    0x9AA595,\n    0x9AA595,\n    0x9BA696,\n    0x9CA797,\n    0x9DA898,\n    0x9CA797,\n    0xA1AE9D,\n    0xA0AD9C,\n    0x9FAC9B,\n    0x9EAB9A,\n    0x9DAB9A,\n    0x9CAA99,\n    0x9DAB9A,\n    0x9DAB9A,\n    0x94A593,\n    0x93A492,\n    0x93A492,\n    0x95A694,\n    0x97A896,\n    0x97A896,\n    0x96A795,\n    0x95A694,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x91A28F,\n    0x93A491,\n    0x94A592,\n    0x95A693,\n    0x8E9F8C,\n    0x91A28F,\n    0x93A491,\n    0x7C8D7A,\n    0x031401,\n    0x000F00,\n    0x000C00,\n    0x000D00,\n    0x000C00,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000900,\n    0x000A00,\n    0x000D00,\n    0x000C00,\n    0x000F02,\n    0x011104,\n    0x435349,\n    0x92A298,\n    0x93A29B,\n    0x95A29B,\n    0x97A29C,\n    0x98A39B,\n    0x99A39B,\n    0x9CA39C,\n    0x9CA39C,\n    0x9FA69F,\n    0xA0A7A0,\n    0xA1A8A0,\n    0xA1A8A0,\n    0x9FA9A0,\n    0xA0AAA1,\n    0xA1ADA3,\n    0xA3AFA5,\n    0x9FAD9E,\n    0xA1AFA0,\n    0x9DAE9E,\n    0x9EAF9F,\n    0xA2B3A3,\n    0x9EAF9F,\n    0x9AAB99,\n    0xA0B19F,\n    0xA4B5A3,\n    0xA4B5A3,\n    0xA4B7A3,\n    0xA4B7A3,\n    0xA4B7A3,\n    0xA4B7A3,\n    0xA4B7A3,\n    0xA5B8A4,\n    0xA6B8A2,\n    0xA6B8A2,\n    0xA6B8A2,\n    0xA6B8A2,\n    0xA6B7A4,\n    0xA6B7A4,\n    0xA8B7A4,\n    0xA8B7A4,\n    0xADBCA9,\n    0xAAB9A6,\n    0xA6B3A2,\n    0xA3B09F,\n    0xA1AE9D,\n    0xA1AE9D,\n    0xA2AF9E,\n    0xA2AF9E,\n    0x9BA897,\n    0xA0AD9C,\n    0xA5B2A1,\n    0xA4B1A0,\n    0x9EAB9A,\n    0x9AA796,\n    0x9AA796,\n    0x9CA998,\n    0x9AA796,\n    0x97A493,\n    0x94A190,\n    0x929F8E,\n    0x919E8D,\n    0x929F8E,\n    0x929F8E,\n    0x929F8E,\n    0x8E9B8A,\n    0x8D9A89,\n    0x8B9887,\n    0x8A9786,\n    0x899786,\n    0x8A9887,\n    0x8C9A89,\n    0x8D9B8A,\n    0x8C9A89,\n    0x8C9A89,\n    0x8B9C8A,\n    0x8E9F8D,\n    0x91A290,\n    0x93A492,\n    0x94A593,\n    0x93A492,\n    0x95A693,\n    0x95A693,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x92A390,\n    0x93A491,\n    0x95A693,\n    0x94A592,\n    0x8FA08D,\n    0x92A390,\n    0x92A390,\n    0x889986,\n    0x091A07,\n    0x001100,\n    0x000A00,\n    0x000C00,\n    0x000E00,\n    0x000A00,\n    0x000800,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000900,\n    0x000A00,\n    0x000C00,\n    0x000C00,\n    0x000F02,\n    0x011104,\n    0x4E5E54,\n    0x91A197,\n    0x909F98,\n    0x929F98,\n    0x929D97,\n    0x929D95,\n    0x929C94,\n    0x949B94,\n    0x939A93,\n    0x919891,\n    0x929992,\n    0x939A92,\n    0x939A92,\n    0x909A91,\n    0x919B92,\n    0x919D93,\n    0x939F95,\n    0x9DAE9E,\n    0x9FB0A0,\n    0x9DAE9E,\n    0x9EAF9F,\n    0xA3B4A4,\n    0x9EAF9F,\n    0x9CAA99,\n    0xA2B09F,\n    0xA6B4A3,\n    0xA7B5A4,\n    0xA7B6A3,\n    0xA7B6A3,\n    0xA7B6A3,\n    0xA7B6A3,\n    0xA8B7A4,\n    0xA8B7A4,\n    0xA7B9A3,\n    0xA7B9A3,\n    0xA7B9A3,\n    0xA7B9A3,\n    0xA7B8A5,\n    0xA7B8A5,\n    0xA9B8A5,\n    0xA9B8A5,\n    0xA1B09D,\n    0xA5B4A1,\n    0xAAB7A6,\n    0xADBAA9,\n    0xADBAA9,\n    0xAAB7A6,\n    0xA7B4A3,\n    0xA4B1A0,\n    0xA8B5A4,\n    0xA9B6A5,\n    0xAAB7A6,\n    0xA8B5A4,\n    0xA6B3A2,\n    0xA4B1A0,\n    0xA4B1A0,\n    0xA5B2A1,\n    0xA9B6A5,\n    0xA7B4A3,\n    0xA4B1A0,\n    0xA3B09F,\n    0xA2AF9E,\n    0xA2AF9E,\n    0xA1AE9D,\n    0xA0AD9C,\n    0x9FAC9B,\n    0x9FAC9B,\n    0x9EAB9A,\n    0x9EAB9A,\n    0x9DAA99,\n    0x9EAB9A,\n    0x9FAC9B,\n    0x9FAC9B,\n    0x97A594,\n    0x96A493,\n    0x97A594,\n    0x99A796,\n    0x99AA98,\n    0x9BAC9A,\n    0x9AAB99,\n    0x99AA98,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x94A592,\n    0x92A390,\n    0x96A794,\n    0x93A491,\n    0x91A28F,\n    0x93A491,\n    0x90A18E,\n    0x8FA08D,\n    0x152613,\n    0x051603,\n    0x000A00,\n    0x000A00,\n    0x000D00,\n    0x000B00,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x000800,\n    0x000B00,\n    0x000B00,\n    0x000C00,\n    0x001003,\n    0x011104,\n    0x536359,\n    0x95A59B,\n    0x95A49D,\n    0x98A59E,\n    0x9AA59F,\n    0x9CA79F,\n    0x9EA8A0,\n    0xA1A8A1,\n    0xA1A8A1,\n    0xA2A9A2,\n    0xA3AAA3,\n    0xA4ABA3,\n    0xA4ABA3,\n    0xA1ABA2,\n    0xA1ABA2,\n    0xA2AEA4,\n    0xA3AFA5,\n    0x9DAE9E,\n    0x9FB0A0,\n    0x9DAE9E,\n    0x9EAF9F,\n    0xA5B3A4,\n    0xA0AE9F,\n    0x9DAB9A,\n    0xA2B09F,\n    0xA7B4A3,\n    0xA8B5A4,\n    0xA8B5A3,\n    0xA8B5A3,\n    0xA9B4A3,\n    0xAAB5A4,\n    0xAAB5A4,\n    0xA9B6A4,\n    0xA9B8A3,\n    0xA7B9A3,\n    0xA7B9A3,\n    0xA7B9A3,\n    0xA7B8A5,\n    0xA7B8A5,\n    0xA9B8A5,\n    0xA9B8A5,\n    0xACBBA8,\n    0xABBAA7,\n    0xABB8A7,\n    0xA8B5A4,\n    0xA6B3A2,\n    0xA6B3A2,\n    0xA8B5A4,\n    0xABB8A7,\n    0xABB9A8,\n    0xA7B5A4,\n    0xA4B2A1,\n    0xA3B1A0,\n    0xA6B4A3,\n    0xA8B6A5,\n    0xA8B6A5,\n    0xA7B5A4,\n    0xA3B1A0,\n    0xA2B09F,\n    0xA2B09F,\n    0xA3B1A0,\n    0xA3B1A0,\n    0xA3B1A0,\n    0xA1AF9E,\n    0xA0AD9C,\n    0xA0AD9C,\n    0xA1AC9C,\n    0xA1AC9C,\n    0xA1AC9C,\n    0x9FAC9B,\n    0x9EAB9A,\n    0x9CA998,\n    0x9CA998,\n    0x9EAB9A,\n    0x9DAA99,\n    0x9BA998,\n    0x9BA998,\n    0x9BA998,\n    0x9AA897,\n    0x98A695,\n    0x96A493,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x95A693,\n    0x92A390,\n    0x96A794,\n    0x93A491,\n    0x92A390,\n    0x93A491,\n    0x8FA08D,\n    0x92A390,\n    0x1F301D,\n    0x0A1B08,\n    0x000A00,\n    0x000900,\n    0x000C00,\n    0x000B00,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000C00,\n    0x000B00,\n    0x000800,\n    0x000E00,\n    0x000B00,\n    0x000B00,\n    0x011106,\n    0x041409,\n    0x5F6F65,\n    0x99A69F,\n    0x96A39C,\n    0x96A39C,\n    0x99A69F,\n    0x9AA79E,\n    0x9AA79E,\n    0x9CA79F,\n    0x9FAAA2,\n    0x9CA89E,\n    0x9DA99F,\n    0x9FAB9F,\n    0xA1ADA1,\n    0xA4AFA1,\n    0xA4AFA1,\n    0xA4AFA1,\n    0xA3AFA1,\n    0xA1B09D,\n    0xA0B19E,\n    0xA1B29F,\n    0xA1B29F,\n    0xA0B19E,\n    0xA0B19E,\n    0xA0B19E,\n    0xA1B29F,\n    0xA5B6A3,\n    0xA5B6A3,\n    0xA6B7A4,\n    0xA6B7A4,\n    0xA6B7A4,\n    0xA6B7A4,\n    0xA7B8A5,\n    0xA7B8A5,\n    0xA5B8A5,\n    0xA5B8A5,\n    0xA5B8A5,\n    0xA6B9A6,\n    0xA7B8A6,\n    0xA7B8A6,\n    0xA7B8A6,\n    0xA8B9A7,\n    0xA8B9A7,\n    0xA8B9A7,\n    0xA9B7A6,\n    0xA6B4A3,\n    0xA1AF9E,\n    0x9AA897,\n    0x94A291,\n    0x919D8F,\n    0x8B978B,\n    0x919B92,\n    0x959F96,\n    0x949E95,\n    0x949E93,\n    0x96A095,\n    0x94A094,\n    0x929E92,\n    0x98A498,\n    0x95A195,\n    0x919D8F,\n    0x8E9A8C,\n    0x909E8F,\n    0x94A293,\n    0x93A192,\n    0x8F9D8C,\n    0x8C9F8B,\n    0x90A38D,\n    0x97AA94,\n    0x9DB09A,\n    0x9FB29C,\n    0x9EB19B,\n    0x9AAD97,\n    0x98AB95,\n    0x98AB95,\n    0x97AA94,\n    0x97AA94,\n    0x97AA94,\n    0x98AB95,\n    0x98AB95,\n    0x96A993,\n    0x95A892,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x92A390,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x91A28F,\n    0x90A18E,\n    0x90A18E,\n    0x334431,\n    0x021300,\n    0x001100,\n    0x000700,\n    0x000C00,\n    0x000B00,\n    0x000700,\n    0x000B00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000C00,\n    0x000A00,\n    0x000A00,\n    0x000D00,\n    0x000B00,\n    0x000E01,\n    0x001005,\n    0x041409,\n    0x6A7A70,\n    0x8D9A93,\n    0x8A9790,\n    0x89968F,\n    0x8C9992,\n    0x8D9A93,\n    0x8C9992,\n    0x8F9A92,\n    0x929D95,\n    0x8D9890,\n    0x8E9991,\n    0x8F9B91,\n    0x8F9B91,\n    0x919B92,\n    0x909A91,\n    0x909A8F,\n    0x8E9A8C,\n    0x9BA998,\n    0x9BAC99,\n    0x9EAF9C,\n    0x9FB09D,\n    0xA0B19E,\n    0xA1B29F,\n    0xA3B4A1,\n    0xA4B5A2,\n    0xA5B6A3,\n    0xA6B7A4,\n    0xA6B7A4,\n    0xA6B7A4,\n    0xA6B7A4,\n    0xA7B8A5,\n    0xA7B8A5,\n    0xA7B8A5,\n    0xA5B8A5,\n    0xA5B8A5,\n    0xA6B9A6,\n    0xA6B9A6,\n    0xA7B8A6,\n    0xA7B8A6,\n    0xA8B9A7,\n    0xA8B9A7,\n    0xA5B6A4,\n    0xA5B6A4,\n    0xA8B6A5,\n    0xA8B6A5,\n    0xAAB8A7,\n    0xABB9A8,\n    0xADBBAA,\n    0xAFBBAD,\n    0xA9B5A9,\n    0xADB7AE,\n    0xADB9AF,\n    0xAAB6AC,\n    0xA8B4A8,\n    0xA9B5A9,\n    0xA8B4A8,\n    0xA6B2A6,\n    0xA7B5A6,\n    0xA6B4A5,\n    0xA2B0A1,\n    0x9EAC9D,\n    0x9DAB9C,\n    0x9EAC9D,\n    0x99AA9A,\n    0x94A593,\n    0x96A995,\n    0x97AA94,\n    0x99AC96,\n    0x9AAD97,\n    0x9BAE98,\n    0x9BAE98,\n    0x9BAE98,\n    0x9BAE98,\n    0x99AC96,\n    0x9AAD97,\n    0x9BAE98,\n    0x99AC96,\n    0x97AA94,\n    0x96A993,\n    0x95A892,\n    0x96A993,\n    0x97A895,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x92A390,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x93A491,\n    0x92A390,\n    0x90A18E,\n    0x90A18E,\n    0x41523F,\n    0x021300,\n    0x001000,\n    0x000900,\n    0x000C00,\n    0x000A00,\n    0x000800,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000C00,\n    0x000900,\n    0x000C00,\n    0x000B00,\n    0x000A00,\n    0x021205,\n    0x000E03,\n    0x041409,\n    0x7A8A80,\n    0x9DAAA3,\n    0x9AA7A0,\n    0x99A69F,\n    0x9BA8A1,\n    0x9BA8A1,\n    0x9BA8A1,\n    0x9EA9A3,\n    0xA2ADA7,\n    0x9FAAA4,\n    0x9FAAA4,\n    0xA0ABA5,\n    0xA0ABA5,\n    0xA1AAA5,\n    0xA0A9A4,\n    0xA0A9A4,\n    0x9EA9A1,\n    0xA1AF9E,\n    0xA1B29F,\n    0xA2B3A0,\n    0xA3B4A1,\n    0xA2B3A0,\n    0xA2B3A0,\n    0xA3B4A1,\n    0xA4B5A2,\n    0xA6B7A4,\n    0xA6B7A4,\n    0xA6B7A4,\n    0xA6B7A4,\n    0xA6B7A4,\n    0xA7B8A5,\n    0xA7B8A5,\n    0xA7B8A5,\n    0xA6B9A6,\n    0xA6B9A6,\n    0xA6B9A6,\n    0xA6B9A6,\n    0xA8B9A7,\n    0xA8B9A7,\n    0xA8B9A7,\n    0xA8B9A7,\n    0xA9BAA8,\n    0xA8B9A7,\n    0xA9B7A6,\n    0xA8B6A5,\n    0xA7B5A4,\n    0xA6B4A3,\n    0xA6B4A3,\n    0xA6B4A5,\n    0xA2AEA0,\n    0xA5B1A5,\n    0xA5B3A6,\n    0xA2B0A3,\n    0xA1AFA2,\n    0xA4B2A5,\n    0xA6B4A7,\n    0xA5B3A6,\n    0xA0B1A1,\n    0xA2B3A3,\n    0xA2B3A3,\n    0xA0B1A1,\n    0xA0B19F,\n    0xA3B4A2,\n    0xA2B3A1,\n    0xA0B19F,\n    0xA0B19E,\n    0x9FB09D,\n    0x9FB09D,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9BAC99,\n    0x9DAE9B,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9AAB98,\n    0x98A996,\n    0x98A996,\n    0x99AA97,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x93A491,\n    0x93A491,\n    0x94A592,\n    0x94A592,\n    0x93A491,\n    0x92A390,\n    0x91A28F,\n    0x90A18E,\n    0x566754,\n    0x011200,\n    0x000E00,\n    0x000E00,\n    0x000B00,\n    0x000800,\n    0x000B00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000C00,\n    0x000900,\n    0x000E00,\n    0x000B00,\n    0x000900,\n    0x031306,\n    0x000B00,\n    0x031308,\n    0x889790,\n    0x9CA9A2,\n    0x99A5A1,\n    0x97A39F,\n    0x99A5A1,\n    0x99A5A1,\n    0x99A5A1,\n    0x9DA8A4,\n    0xA1ACA8,\n    0xA2ADA9,\n    0xA2ADA9,\n    0xA3AEAA,\n    0xA4AFAB,\n    0xA5AEAB,\n    0xA6AFAC,\n    0xA6AFAC,\n    0xA5B0AA,\n    0xA1AFA0,\n    0xA1B2A0,\n    0xA2B3A1,\n    0xA3B4A2,\n    0xA2B3A1,\n    0xA2B3A1,\n    0xA3B4A2,\n    0xA4B5A3,\n    0xA6B7A5,\n    0xA6B7A5,\n    0xA6B7A5,\n    0xA6B7A5,\n    0xA7B8A6,\n    0xA7B8A6,\n    0xA7B8A6,\n    0xA7B8A6,\n    0xA6B9A6,\n    0xA6B9A6,\n    0xA7BAA7,\n    0xA7BAA7,\n    0xA8B9A7,\n    0xA8B9A7,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xABB9A8,\n    0xA9B7A6,\n    0xA5B3A2,\n    0x9FAD9C,\n    0x98A695,\n    0x95A394,\n    0x93A192,\n    0x95A396,\n    0x96A497,\n    0x93A194,\n    0x93A194,\n    0x97A598,\n    0x98A999,\n    0x98A999,\n    0x91A292,\n    0x95A696,\n    0x96A996,\n    0x95A895,\n    0x97AA97,\n    0x9CAF9C,\n    0xA0B3A0,\n    0xA0B3A0,\n    0x9EAF9C,\n    0x9FB09D,\n    0xA0B19E,\n    0xA1B29F,\n    0xA0B19E,\n    0x9DAE9B,\n    0x9AAB98,\n    0x98A996,\n    0x99AA97,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x98A996,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x93A491,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x94A592,\n    0x93A491,\n    0x91A28F,\n    0x91A28F,\n    0x6A7B68,\n    0x001100,\n    0x000A00,\n    0x011200,\n    0x000900,\n    0x000700,\n    0x000E00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000C00,\n    0x000A00,\n    0x000E00,\n    0x000B00,\n    0x000900,\n    0x011104,\n    0x000A00,\n    0x06160B,\n    0x8F9E97,\n    0x8F9C95,\n    0x8C9894,\n    0x8B9793,\n    0x8C9894,\n    0x8D9995,\n    0x8D9995,\n    0x909B97,\n    0x949F9B,\n    0x95A09C,\n    0x95A09C,\n    0x96A19D,\n    0x96A19D,\n    0x98A19E,\n    0x99A29F,\n    0x99A29F,\n    0x99A49E,\n    0x95A394,\n    0x96A795,\n    0x9AAB99,\n    0x9DAE9C,\n    0x9FB09E,\n    0xA2B3A1,\n    0xA5B6A4,\n    0xA7B8A6,\n    0xA6B7A5,\n    0xA6B7A5,\n    0xA6B7A5,\n    0xA7B8A6,\n    0xA7B8A6,\n    0xA7B8A6,\n    0xA7B8A6,\n    0xA8B9A7,\n    0xA7BAA7,\n    0xA7BAA7,\n    0xA7BAA7,\n    0xA7BAA7,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xA3B4A2,\n    0xA5B6A4,\n    0xAAB8A7,\n    0xACBAA9,\n    0xACBAA9,\n    0xA9B7A6,\n    0xA6B4A3,\n    0xA4B2A3,\n    0xA4B0A2,\n    0xA6B2A6,\n    0xA4B2A3,\n    0xA0AE9F,\n    0x9EAC9D,\n    0x9FAD9E,\n    0xA0AE9F,\n    0x9FAD9E,\n    0x9AAB99,\n    0x9CAD9B,\n    0x9BAC9A,\n    0x98A997,\n    0x98A997,\n    0x9CAD9B,\n    0x9FB29E,\n    0x9FB29E,\n    0x9DAE9B,\n    0x9EAF9C,\n    0x9FB09D,\n    0xA0B19E,\n    0x9FB09D,\n    0x9DAE9B,\n    0x9AAB98,\n    0x99AA97,\n    0x9BAC99,\n    0x99AA97,\n    0x97A895,\n    0x98A996,\n    0x9AAB98,\n    0x9AAB98,\n    0x97A895,\n    0x95A693,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x94A592,\n    0x94A592,\n    0x95A693,\n    0x95A693,\n    0x94A592,\n    0x93A491,\n    0x92A390,\n    0x91A28F,\n    0x7A8B78,\n    0x021300,\n    0x000800,\n    0x011200,\n    0x000900,\n    0x000700,\n    0x001000,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000C00,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000A00,\n    0x000E01,\n    0x000B00,\n    0x0E1E13,\n    0x93A29B,\n    0x99A5A1,\n    0x97A3A1,\n    0x97A3A1,\n    0x9AA6A4,\n    0x9BA7A3,\n    0x9BA7A3,\n    0x9DA8A4,\n    0xA0ABA7,\n    0x9FAAA4,\n    0x9EA9A3,\n    0x9EA9A1,\n    0x9DA8A0,\n    0x9EA89F,\n    0x9EA89F,\n    0x9FA9A0,\n    0x9EAAA0,\n    0x99A798,\n    0x99AA9A,\n    0x9CAD9D,\n    0x9EAF9F,\n    0xA0B1A1,\n    0xA2B3A3,\n    0xA4B5A5,\n    0xA6B7A7,\n    0xA6B7A7,\n    0xA7B8A8,\n    0xA7B8A8,\n    0xA7B8A8,\n    0xA7B8A8,\n    0xA8B9A9,\n    0xA8B9A9,\n    0xA8B9A9,\n    0xA7BAA7,\n    0xA7BAA7,\n    0xA8BBA8,\n    0xA8BBA8,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xAABBA9,\n    0xAABBA9,\n    0xA8B9A7,\n    0xA7B8A6,\n    0xA9B7A6,\n    0xA8B6A5,\n    0xA8B6A5,\n    0xA9B7A6,\n    0xA9B7A6,\n    0xAAB7A6,\n    0xA8B4A6,\n    0xADB8AA,\n    0xAEB9AB,\n    0xABB6A8,\n    0xA8B4A6,\n    0xA9B5A7,\n    0xA9B6A5,\n    0xA7B4A3,\n    0xA9B6A5,\n    0xAAB7A6,\n    0xA7B5A4,\n    0xA4B2A1,\n    0xA4B3A0,\n    0xA8B7A4,\n    0xA9B8A5,\n    0xA8B7A4,\n    0xA5B3A2,\n    0xA4B2A1,\n    0xA2B09F,\n    0xA0AE9D,\n    0xA0AE9D,\n    0xA1AF9E,\n    0xA2B09F,\n    0xA3B1A0,\n    0xA2B09F,\n    0xA0AE9D,\n    0x9FAD9C,\n    0x9EAC9B,\n    0x9FAD9C,\n    0x9EAC9B,\n    0x9BA998,\n    0x99A796,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x94A592,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x95A693,\n    0x94A592,\n    0x92A390,\n    0x92A390,\n    0x849582,\n    0x091A07,\n    0x000900,\n    0x001100,\n    0x000A00,\n    0x000700,\n    0x001000,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000C00,\n    0x000B00,\n    0x000900,\n    0x000E00,\n    0x000C00,\n    0x000B00,\n    0x001005,\n    0x19291E,\n    0x96A59E,\n    0x9BA7A5,\n    0x9AA6A6,\n    0x9BA7A7,\n    0x9FABAB,\n    0xA1ADA9,\n    0xA0ACA8,\n    0xA1ACA6,\n    0xA4AFA9,\n    0xA3AFA5,\n    0xA3AFA5,\n    0xA2AEA0,\n    0xA1AD9F,\n    0xA3AE9E,\n    0xA3AE9E,\n    0xA4AF9F,\n    0xA4B1A0,\n    0xA3B1A2,\n    0xA2B3A3,\n    0xA4B5A5,\n    0xA4B5A5,\n    0xA3B4A4,\n    0xA2B3A3,\n    0xA3B4A4,\n    0xA4B5A5,\n    0xA7B8A8,\n    0xA7B8A8,\n    0xA7B8A8,\n    0xA7B8A8,\n    0xA7B8A8,\n    0xA8B9A9,\n    0xA8B9A9,\n    0xA8B9A9,\n    0xA8BBA8,\n    0xA8BBA8,\n    0xA8BBA8,\n    0xA8BBA8,\n    0xAABBA9,\n    0xAABBA9,\n    0xAABBA9,\n    0xAABBA9,\n    0xADBEAC,\n    0xACBDAB,\n    0xAAB8A7,\n    0xA7B5A4,\n    0xA3B1A0,\n    0xA0AE9D,\n    0x9EAC9B,\n    0x9EAB9A,\n    0x9AA597,\n    0xA2AA9D,\n    0xA6AEA1,\n    0xA5ADA0,\n    0xA5AD9E,\n    0xA6AE9F,\n    0xA3AE9E,\n    0xA1AC9C,\n    0xA2AD9D,\n    0xA3AE9E,\n    0xA2AD9C,\n    0xA2AD9C,\n    0xA3B09E,\n    0xA6B3A1,\n    0xA4B19F,\n    0xA0AD9B,\n    0x9FAD9C,\n    0x9EAC9B,\n    0x9DAB9A,\n    0x9CAA99,\n    0x9CAA99,\n    0x9DAB9A,\n    0x9EAC9B,\n    0x9EAC9B,\n    0x97A594,\n    0x9BA998,\n    0x9DAB9A,\n    0x9CAA99,\n    0x99A796,\n    0x98A695,\n    0x9AA897,\n    0x9CAA99,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x95A693,\n    0x95A693,\n    0x96A794,\n    0x96A794,\n    0x95A693,\n    0x94A592,\n    0x93A491,\n    0x92A390,\n    0x8C9D8A,\n    0x142512,\n    0x000D00,\n    0x000F00,\n    0x000B00,\n    0x000800,\n    0x000D00,\n    0x000B00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000C00,\n    0x000C00,\n    0x000C00,\n    0x000B00,\n    0x000700,\n    0x000F00,\n    0x000E00,\n    0x000900,\n    0x041409,\n    0x213126,\n    0x97A69F,\n    0x8E9A9A,\n    0x8E999B,\n    0x909C9C,\n    0x95A1A1,\n    0x97A39F,\n    0x96A29E,\n    0x97A29A,\n    0x99A49C,\n    0x9CA89C,\n    0x9CA89C,\n    0x9CA998,\n    0x9DAA99,\n    0x9FAB97,\n    0xA1AD99,\n    0xA3AF99,\n    0xA4B19D,\n    0xA0AE9D,\n    0xA0B1A1,\n    0xA2B3A3,\n    0xA3B4A4,\n    0xA3B4A4,\n    0xA4B5A5,\n    0xA5B6A6,\n    0xA6B7A7,\n    0xA7B8A8,\n    0xA7B8A8,\n    0xA7B8A8,\n    0xA7B8A8,\n    0xA8B9A9,\n    0xA8B9A9,\n    0xA8B9A9,\n    0xA8B9A9,\n    0xA8BBA8,\n    0xA8BBA8,\n    0xA8BBA8,\n    0xA8BBA8,\n    0xAABBA9,\n    0xAABBA9,\n    0xAABBA9,\n    0xAABBA9,\n    0xA8B9A7,\n    0xAABBA9,\n    0xADBBAA,\n    0xADBBAA,\n    0xAAB8A7,\n    0xA6B4A3,\n    0xA2B09F,\n    0xA0AD9C,\n    0x9CA497,\n    0xA3A99D,\n    0xA7ADA1,\n    0xA6ACA0,\n    0xA4AA9C,\n    0xA2A89A,\n    0x9DA596,\n    0x99A192,\n    0x959D8E,\n    0x969E8F,\n    0x959E8D,\n    0x959E8D,\n    0x96A190,\n    0x96A190,\n    0x909B8A,\n    0x889382,\n    0x8D9B8A,\n    0x8F9D8C,\n    0x92A08F,\n    0x94A291,\n    0x94A291,\n    0x92A08F,\n    0x8F9D8C,\n    0x8C9A89,\n    0x82907F,\n    0x8B9988,\n    0x92A08F,\n    0x92A08F,\n    0x8C9A89,\n    0x8B9988,\n    0x92A08F,\n    0x99A796,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x95A693,\n    0x95A693,\n    0x96A794,\n    0x96A794,\n    0x95A693,\n    0x94A592,\n    0x93A491,\n    0x92A390,\n    0x91A28F,\n    0x1C2D1A,\n    0x001100,\n    0x000F00,\n    0x000D00,\n    0x000900,\n    0x000C00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x001000,\n    0x000900,\n    0x001000,\n    0x000E00,\n    0x000A00,\n    0x35443D,\n    0x94A39C,\n    0x93A097,\n    0x95A299,\n    0x95A299,\n    0x95A29B,\n    0x95A19D,\n    0x96A29E,\n    0x96A09F,\n    0x959F9E,\n    0x98A39F,\n    0x97A29E,\n    0x95A09A,\n    0x949F99,\n    0x949E95,\n    0x949E95,\n    0x949F91,\n    0x94A092,\n    0x919F90,\n    0x94A595,\n    0x9BAC9C,\n    0x9FB0A0,\n    0xA1B2A0,\n    0xA2B3A1,\n    0xA4B5A3,\n    0xA6B7A5,\n    0xA7B8A6,\n    0xA7B8A6,\n    0xA7B8A5,\n    0xA8B9A6,\n    0xA9BAA7,\n    0xA9BAA7,\n    0xAABBA8,\n    0xAABBA8,\n    0xA6BCA5,\n    0xA6BCA5,\n    0xA7BDA6,\n    0xA7BDA6,\n    0xA9BCA8,\n    0xA9BCA8,\n    0xA9BCA8,\n    0xA8BBA7,\n    0xA8BBA7,\n    0xABBEAA,\n    0xAEBFAD,\n    0xAABBA9,\n    0xA7B8A6,\n    0xA7B8A6,\n    0xA7B8A6,\n    0xA8B6A5,\n    0xAAB8A7,\n    0xA6B3A2,\n    0xA5B2A1,\n    0xA8B5A4,\n    0xA9B6A5,\n    0xA8B5A4,\n    0xA7B4A3,\n    0xA9B6A5,\n    0xA8B5A4,\n    0xADBAA9,\n    0xA3B09F,\n    0xABB8A7,\n    0xA5B2A1,\n    0xA8B5A4,\n    0x9DAA99,\n    0xA6B3A2,\n    0x9DAE9B,\n    0x9EAF9C,\n    0x9FB09D,\n    0xA0B19E,\n    0xA0B19E,\n    0x9FB09D,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x98A996,\n    0x97A895,\n    0x96A794,\n    0x95A693,\n    0x95A693,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x96A892,\n    0x96A892,\n    0x96A892,\n    0x96A892,\n    0x95A791,\n    0x94A690,\n    0x93A58F,\n    0x92A48E,\n    0x849680,\n    0x3C4E38,\n    0x000B00,\n    0x011300,\n    0x000D00,\n    0x000800,\n    0x000F00,\n    0x000E00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000E00,\n    0x000800,\n    0x001000,\n    0x000E00,\n    0x000C01,\n    0x3C4B44,\n    0x96A5A0,\n    0x9CA9A0,\n    0x9DAAA1,\n    0x9EABA4,\n    0x9FACA5,\n    0xA1ADA9,\n    0xA2AEAA,\n    0xA4AFAB,\n    0xA4AFAB,\n    0xA4AFAB,\n    0xA3AEAA,\n    0xA3AEA8,\n    0xA3AEA8,\n    0xA5AFA6,\n    0xA6B0A7,\n    0xA6B0A5,\n    0xA6B2A6,\n    0xA0AE9F,\n    0xA1B2A2,\n    0xA5B6A6,\n    0xA5B6A6,\n    0xA4B5A3,\n    0xA2B3A1,\n    0xA2B3A1,\n    0xA3B4A2,\n    0xA7B8A6,\n    0xA7B8A6,\n    0xA8B9A6,\n    0xA8B9A6,\n    0xA9BAA7,\n    0xA9BAA7,\n    0xAABBA8,\n    0xAABBA8,\n    0xA7BDA6,\n    0xA7BDA6,\n    0xA7BDA6,\n    0xA7BDA6,\n    0xA9BCA8,\n    0xA9BCA8,\n    0xA8BBA7,\n    0xA8BBA7,\n    0xA7B8A5,\n    0xA7B8A5,\n    0xA8B9A7,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xAABBA9,\n    0xADBEAC,\n    0xB3C1B0,\n    0xAAB8A7,\n    0xABB8A7,\n    0xABB8A7,\n    0xACB9A8,\n    0xADBAA9,\n    0xADBAA9,\n    0xADBAA9,\n    0xACB9A8,\n    0xA4B1A0,\n    0xA7B4A3,\n    0x9FAC9B,\n    0xA3B09F,\n    0xA4B1A0,\n    0xA6B3A2,\n    0xA2AF9E,\n    0xACB9A8,\n    0xA4B5A2,\n    0xA2B3A0,\n    0xA0B19E,\n    0x9DAE9B,\n    0x9CAD9A,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9CAD9A,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x96A892,\n    0x96A892,\n    0x96A892,\n    0x96A892,\n    0x95A791,\n    0x94A690,\n    0x93A58F,\n    0x92A48E,\n    0x899B85,\n    0x455741,\n    0x000D00,\n    0x011300,\n    0x000E00,\n    0x000800,\n    0x000E00,\n    0x000C00,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000C00,\n    0x000800,\n    0x000F00,\n    0x000E00,\n    0x000F04,\n    0x485750,\n    0x97A6A1,\n    0x96A39A,\n    0x96A39A,\n    0x98A59E,\n    0x9AA7A0,\n    0x9BA7A3,\n    0x9CA8A4,\n    0x9DA8A4,\n    0x9EA9A5,\n    0x9FAAA4,\n    0xA0ABA5,\n    0xA1ACA4,\n    0xA2ADA5,\n    0xA3ADA4,\n    0xA4AEA5,\n    0xA4AEA3,\n    0xA3AFA3,\n    0x9EAC9D,\n    0x9FB0A0,\n    0xA3B4A4,\n    0xA4B5A5,\n    0xA3B4A4,\n    0xA2B3A3,\n    0xA4B5A3,\n    0xA6B7A5,\n    0xA7B8A6,\n    0xA8B9A7,\n    0xA8B9A7,\n    0xA8B9A7,\n    0xA9BAA7,\n    0xA9BAA7,\n    0xAABBA8,\n    0xAABBA8,\n    0xA9BCA6,\n    0xA9BCA6,\n    0xAABDA7,\n    0xA9BCA6,\n    0xA9BCA8,\n    0xA8BBA7,\n    0xA8BBA7,\n    0xA7BAA6,\n    0xADBEAB,\n    0xA8B9A6,\n    0xA5B6A4,\n    0xA6B7A5,\n    0xA5B3A2,\n    0xA1AF9E,\n    0xA4B2A1,\n    0xAAB8A7,\n    0xA7B4A3,\n    0xAAB7A6,\n    0xA8B5A4,\n    0xA2AF9E,\n    0xA1AE9D,\n    0xA7B4A3,\n    0xAAB7A6,\n    0xA8B5A4,\n    0xACB9A8,\n    0xACB9A8,\n    0xABB8A7,\n    0xA7B4A3,\n    0xAEBBAA,\n    0xA5B2A1,\n    0xA4B1A0,\n    0xA8B5A4,\n    0xA0B19E,\n    0xA0B19E,\n    0xA1B29F,\n    0xA2B3A0,\n    0xA2B3A0,\n    0xA2B3A0,\n    0xA1B29F,\n    0xA1B29F,\n    0xA0B19E,\n    0x9FB09D,\n    0x9FB09D,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9CAD9A,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x97A895,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x95A693,\n    0x94A592,\n    0x93A491,\n    0x92A390,\n    0x8FA08D,\n    0x536451,\n    0x000E00,\n    0x001100,\n    0x000D00,\n    0x000900,\n    0x000C00,\n    0x000A00,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000C00,\n    0x000B00,\n    0x000900,\n    0x000F00,\n    0x000E00,\n    0x001005,\n    0x55645D,\n    0x97A6A1,\n    0x8D9A93,\n    0x8C9992,\n    0x8D9A93,\n    0x8F9C95,\n    0x909D96,\n    0x8E9B94,\n    0x8F9A94,\n    0x919C96,\n    0x929D97,\n    0x929D97,\n    0x939E96,\n    0x949F97,\n    0x959F96,\n    0x949E95,\n    0x939D94,\n    0x919D93,\n    0x9AA89B,\n    0x9BAB9E,\n    0x9FB0A0,\n    0xA1B2A2,\n    0xA1B2A2,\n    0xA3B4A4,\n    0xA6B7A7,\n    0xAABBAB,\n    0xA8B9A7,\n    0xA8B9A7,\n    0xA8B9A7,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xAABBA8,\n    0xAABBA8,\n    0xAABDA7,\n    0xAABDA7,\n    0xAABDA7,\n    0xAABDA7,\n    0xA9BCA8,\n    0xA8BBA7,\n    0xA8B9A6,\n    0xA8B9A6,\n    0x8FA08D,\n    0x879885,\n    0x849281,\n    0x839180,\n    0x7E8C7B,\n    0x768473,\n    0x768473,\n    0x7C8A79,\n    0x8D9B8A,\n    0x909E8D,\n    0x8B9988,\n    0x7E8C7B,\n    0x7B8978,\n    0x859382,\n    0x8B9988,\n    0x8A9887,\n    0x707E6D,\n    0x748271,\n    0x808E7D,\n    0x808E7D,\n    0x93A190,\n    0x879584,\n    0x8A9887,\n    0x8B9988,\n    0x839481,\n    0x899A87,\n    0x92A390,\n    0x9BAC99,\n    0xA0B19E,\n    0xA0B19E,\n    0x9EAF9C,\n    0x9CAD9A,\n    0x9FB09D,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9CAD9A,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x95A693,\n    0x94A592,\n    0x93A491,\n    0x92A390,\n    0x91A28F,\n    0x627360,\n    0x001000,\n    0x000F00,\n    0x000C00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000F00,\n    0x000B00,\n    0x000B00,\n    0x001000,\n    0x000D00,\n    0x011106,\n    0x62716A,\n    0x95A49F,\n    0x9EAAA6,\n    0x9CA8A4,\n    0x9CA8A4,\n    0xA0ACA8,\n    0xA1AEA7,\n    0x9EABA4,\n    0x9FAAA2,\n    0xA2ADA5,\n    0x9FAAA2,\n    0xA0ABA3,\n    0xA1ACA4,\n    0xA2ADA5,\n    0xA3ADA5,\n    0xA3ADA5,\n    0xA2ACA4,\n    0xA0ABA3,\n    0xA2B0A3,\n    0xA3B3A6,\n    0xA5B5A8,\n    0xA5B5A8,\n    0xA3B3A6,\n    0xA3B3A6,\n    0xA5B6A6,\n    0xA7B8A8,\n    0xA9BAAA,\n    0xA9BAAA,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xAABBA9,\n    0xAABBA9,\n    0xAABDA7,\n    0xAABDA7,\n    0xABBDA7,\n    0xABBDA7,\n    0xAABBA8,\n    0xA9BAA7,\n    0xA8B9A6,\n    0xA8B9A6,\n    0xB3C2AF,\n    0xADBCA9,\n    0xABB9A8,\n    0xAEBCAB,\n    0xADBBAA,\n    0xA8B6A5,\n    0xA9B6A5,\n    0xADBAA9,\n    0xA6B4A3,\n    0xAAB8A7,\n    0xA6B4A3,\n    0x9AA897,\n    0x98A695,\n    0xA0AE9D,\n    0xA3B1A0,\n    0x9FAD9C,\n    0x9BA998,\n    0x9BA998,\n    0xA0AE9D,\n    0x96A493,\n    0x9FAD9C,\n    0x8A9887,\n    0x869483,\n    0x839180,\n    0x839481,\n    0x899A87,\n    0x92A390,\n    0x9AAB98,\n    0x9FB09D,\n    0xA0B19E,\n    0x9EAF9C,\n    0x9CAD9A,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9CAD9A,\n    0x9BAC99,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x96A794,\n    0x95A693,\n    0x94A592,\n    0x93A491,\n    0x92A390,\n    0x90A18E,\n    0x70816E,\n    0x011200,\n    0x000E00,\n    0x000B00,\n    0x000D00,\n    0x000B00,\n    0x000B00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x001200,\n    0x000B00,\n    0x000D00,\n    0x001000,\n    0x000D00,\n    0x031308,\n    0x6E7D76,\n    0x94A39E,\n    0x9BA7A5,\n    0x98A4A2,\n    0x9AA6A2,\n    0xA0ACA8,\n    0xA2AFA8,\n    0x9FACA5,\n    0xA1ACA4,\n    0xA6B1A9,\n    0xA3AFA5,\n    0xA4B0A6,\n    0xA5B1A7,\n    0xA7B3A9,\n    0xA9B3AB,\n    0xABB5AD,\n    0xABB4AF,\n    0xABB6AE,\n    0xA1AEA4,\n    0xA2B2A5,\n    0xA5B5A8,\n    0xA5B5A8,\n    0xA4B4A7,\n    0xA3B3A6,\n    0xA5B5A8,\n    0xA7B7AA,\n    0xA9BAAA,\n    0xA9BAAA,\n    0xA9BAAA,\n    0xA9BAAA,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xAABBA9,\n    0xAABBA9,\n    0xAABCA6,\n    0xAABCA6,\n    0xABBDA7,\n    0xAABCA6,\n    0xAABBA8,\n    0xA9BAA7,\n    0xABBAA7,\n    0xAAB9A6,\n    0xAAB9A6,\n    0xA8B7A4,\n    0xA7B5A4,\n    0xA8B6A5,\n    0xABB8A7,\n    0xACB9A8,\n    0xACB9A8,\n    0xACB9A8,\n    0xA5B6A4,\n    0xA9BAA8,\n    0xAABBA9,\n    0xA7B8A6,\n    0xA9BAA8,\n    0xACBDAB,\n    0xA9BAA8,\n    0xA2B3A1,\n    0xA3B4A2,\n    0xA3B4A2,\n    0xA4B5A3,\n    0xA2B3A1,\n    0xABBCAA,\n    0xA4B5A3,\n    0xA5B6A4,\n    0xAABBA9,\n    0xA0B19E,\n    0xA0B19E,\n    0xA1B29F,\n    0xA2B3A0,\n    0xA2B3A0,\n    0xA2B3A0,\n    0xA1B29F,\n    0xA1B29F,\n    0x9FB09D,\n    0x9FB09D,\n    0x9FB09D,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9CAD9A,\n    0x9CAD9A,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x96A795,\n    0x96A795,\n    0x96A795,\n    0x96A795,\n    0x95A694,\n    0x94A593,\n    0x93A492,\n    0x92A391,\n    0x8E9F8D,\n    0x7E8F7D,\n    0x051604,\n    0x000E00,\n    0x000A00,\n    0x000D00,\n    0x000A00,\n    0x000C00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x011300,\n    0x000A00,\n    0x000D00,\n    0x001000,\n    0x000C00,\n    0x041409,\n    0x798881,\n    0x94A39E,\n    0x899593,\n    0x85918F,\n    0x87938F,\n    0x8E9A96,\n    0x909D94,\n    0x8D9A91,\n    0x8F9B91,\n    0x94A096,\n    0x929E94,\n    0x939F95,\n    0x939F95,\n    0x95A197,\n    0x97A199,\n    0x99A39B,\n    0x9BA49F,\n    0x9BA6A0,\n    0x98A59B,\n    0x9AAA9F,\n    0x9FAFA4,\n    0xA2B2A7,\n    0xA3B3A6,\n    0xA3B3A6,\n    0xA6B6A9,\n    0xA8B8AB,\n    0xAABBAB,\n    0xAABBAB,\n    0xAABBAB,\n    0xAABBAB,\n    0xAABBAB,\n    0xAABBAB,\n    0xA9BAAA,\n    0xA9BAA8,\n    0xAABBA8,\n    0xAABCA6,\n    0xAABCA6,\n    0xAABCA6,\n    0xACBBA8,\n    0xACBBA8,\n    0xABBAA7,\n    0xABBAA7,\n    0xA9B8A5,\n    0xAAB9A6,\n    0xA6B3A2,\n    0x9FAC9B,\n    0x9FAC9B,\n    0xA4B1A0,\n    0xA4B1A0,\n    0x9EAB9A,\n    0x98A997,\n    0x98A997,\n    0x9AAB99,\n    0xA0B19F,\n    0xA7B8A6,\n    0xAABBA9,\n    0xA7B8A6,\n    0xA2B3A1,\n    0xAABBA9,\n    0xACBDAB,\n    0xA3B4A2,\n    0xA4B5A3,\n    0xA3B4A2,\n    0xA3B4A2,\n    0x9EAF9D,\n    0xA6B7A5,\n    0xA6B7A4,\n    0xA4B5A2,\n    0xA2B3A0,\n    0x9FB09D,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9CAD9A,\n    0x9CAD9A,\n    0xA0B19E,\n    0x9FB09D,\n    0x9FB09D,\n    0x9FB09D,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x96A795,\n    0x96A795,\n    0x96A795,\n    0x96A795,\n    0x95A694,\n    0x94A593,\n    0x93A492,\n    0x92A391,\n    0x8D9E8C,\n    0x8B9C8A,\n    0x0B1C0A,\n    0x001100,\n    0x000B00,\n    0x000D00,\n    0x000800,\n    0x000D00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x011300,\n    0x000900,\n    0x000D00,\n    0x001000,\n    0x000D00,\n    0x06160B,\n    0x7F8E87,\n    0x95A4A1,\n    0x9CA8A6,\n    0x98A4A4,\n    0x99A5A1,\n    0x9FABA7,\n    0xA0ADA4,\n    0x9BA89F,\n    0x9DA99F,\n    0xA2AEA4,\n    0x9DA99D,\n    0x9CA89C,\n    0x9CA89E,\n    0x9CA89E,\n    0x9DA79F,\n    0x9FA8A3,\n    0xA0A9A4,\n    0xA0ABA5,\n    0x98A59C,\n    0x9BABA0,\n    0xA0B0A5,\n    0xA3B3A8,\n    0xA3B3A6,\n    0xA3B3A6,\n    0xA4B4A7,\n    0xA6B6A9,\n    0xAABAAD,\n    0xAABAAD,\n    0xAABBAB,\n    0xAABBAB,\n    0xAABBAB,\n    0xAABBAB,\n    0xA9BAAA,\n    0xA9BAA8,\n    0xA9BAA7,\n    0xA9BBA5,\n    0xAABCA6,\n    0xAABCA6,\n    0xACBBA8,\n    0xACBBA8,\n    0xACBBA8,\n    0xABBAA7,\n    0xA8B7A4,\n    0xAAB9A6,\n    0xA4B1A0,\n    0x97A493,\n    0x96A392,\n    0x9EAB9A,\n    0x9EAB9A,\n    0x96A392,\n    0x94A593,\n    0x8D9E8C,\n    0x8D9E8C,\n    0x96A795,\n    0xA1B2A0,\n    0xA7B8A6,\n    0xA8B9A7,\n    0xA9BAA8,\n    0xA5B6A4,\n    0xAABBA9,\n    0xA1B2A0,\n    0xABBCAA,\n    0xA5B6A4,\n    0xAABBA9,\n    0x9FB09E,\n    0xA9BAA8,\n    0xA2B3A0,\n    0xA2B3A0,\n    0xA4B5A2,\n    0xA4B5A2,\n    0xA4B5A2,\n    0xA4B5A2,\n    0xA2B3A0,\n    0xA1B29F,\n    0x9FB09D,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9CAD9A,\n    0x9BAC99,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x96A795,\n    0x96A795,\n    0x96A795,\n    0x96A795,\n    0x95A694,\n    0x94A593,\n    0x93A492,\n    0x92A391,\n    0x8E9F8D,\n    0x93A492,\n    0x10210F,\n    0x031402,\n    0x000B00,\n    0x000D00,\n    0x000800,\n    0x000E00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000700,\n    0x000A00,\n    0x000C00,\n    0x000900,\n    0x000B00,\n    0x000E00,\n    0x000B00,\n    0x000800,\n    0x000600,\n    0x011104,\n    0x000F02,\n    0x000700,\n    0x000900,\n    0x000D00,\n    0x000C00,\n    0x000F00,\n    0x000E00,\n    0x000D00,\n    0x000E01,\n    0x000B00,\n    0x08180D,\n    0x8A9A90,\n    0x97A69F,\n    0x98A7A0,\n    0x9BAAA5,\n    0x9EADA8,\n    0x9FAEA9,\n    0x9FAEA9,\n    0x9EADA8,\n    0x9EADA6,\n    0x9EADA6,\n    0x9EADA6,\n    0xA0AFA8,\n    0xA1B0A9,\n    0xA0AFA8,\n    0xA1B1A7,\n    0xA4B4AA,\n    0xA5B5AB,\n    0xA3B3A9,\n    0xA3B3A6,\n    0xA4B4A7,\n    0xA4B4A7,\n    0xA4B4A7,\n    0xA3B3A6,\n    0xA4B4A7,\n    0xA6B7A7,\n    0xA8B9A9,\n    0xA8B9A9,\n    0xA9BAAA,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xAABBA9,\n    0xAABBA9,\n    0xAABBA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xADBBAA,\n    0xADBBAA,\n    0xAAB8A7,\n    0xAAB8A7,\n    0xA9B5A7,\n    0xADB9AB,\n    0xB4C0B2,\n    0xAEBAAC,\n    0xA7B3A5,\n    0xA9B7A8,\n    0xA5B8A5,\n    0xA3B8A5,\n    0xA5B8A5,\n    0xA5B8A5,\n    0xA5B8A5,\n    0xA5B8A5,\n    0xA6B7A5,\n    0xA7B8A6,\n    0xA6B7A5,\n    0xA8B9A7,\n    0xA9B7A6,\n    0xA6B4A3,\n    0xA5B3A2,\n    0xA7B5A4,\n    0xA7B4A3,\n    0xA4B1A0,\n    0xA1B2A0,\n    0x9FB09E,\n    0xA0B19F,\n    0xA2B3A1,\n    0xA2B3A1,\n    0x9FB09E,\n    0x9EAF9D,\n    0xA0B19F,\n    0xA1B2A0,\n    0xA0B19F,\n    0x9EAF9D,\n    0x9EAF9D,\n    0x9EAF9D,\n    0x9EAF9D,\n    0x9CAD9B,\n    0x9BAC9A,\n    0x9BAC9A,\n    0x9BAC9A,\n    0x9AAB99,\n    0x9AAB99,\n    0x99AA98,\n    0x99AA98,\n    0x98A997,\n    0x98A997,\n    0x96A795,\n    0x9AAB99,\n    0x9BAC9A,\n    0x98A997,\n    0x98A997,\n    0x9AAB99,\n    0x9AAB99,\n    0x97A895,\n    0x97A993,\n    0x97A993,\n    0x97A993,\n    0x97A895,\n    0x96A795,\n    0x94A593,\n    0x93A494,\n    0x92A393,\n    0x8D9D90,\n    0x8B9B8E,\n    0x2E3F2F,\n    0x000E00,\n    0x000F00,\n    0x000C00,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000C00,\n    0x000900,\n    0x000C00,\n    0x001000,\n    0x000D00,\n    0x000700,\n    0x000700,\n    0x001100,\n    0x000800,\n    0x001000,\n    0x001000,\n    0x000A00,\n    0x000A00,\n    0x000E00,\n    0x000B00,\n    0x000700,\n    0x000700,\n    0x000F02,\n    0x000600,\n    0x000600,\n    0x001000,\n    0x000D00,\n    0x000A00,\n    0x031402,\n    0x000E00,\n    0x000E00,\n    0x000D00,\n    0x000E01,\n    0x000C00,\n    0x0F1F14,\n    0x8E9E94,\n    0x99A8A1,\n    0x8F9E97,\n    0x91A09B,\n    0x94A39E,\n    0x97A6A1,\n    0x99A8A3,\n    0x9CABA6,\n    0x9FAEA7,\n    0xA1B0A9,\n    0x9FAEA7,\n    0xA1B0A9,\n    0xA1B0A9,\n    0x9FAEA7,\n    0x9FAFA5,\n    0xA2B2A8,\n    0xA3B3A9,\n    0xA1B1A7,\n    0xA4B4A7,\n    0xA4B4A7,\n    0xA5B5A8,\n    0xA4B4A7,\n    0xA4B5A5,\n    0xA4B5A5,\n    0xA6B7A7,\n    0xA8B9A9,\n    0xA9BAAA,\n    0xA9BAAA,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xAABBA9,\n    0xAABBA9,\n    0xAABBA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xADBBAA,\n    0xADBBAA,\n    0xB2C0AF,\n    0xB2C0AF,\n    0xADB9AB,\n    0xAAB6A8,\n    0xACB8AA,\n    0xA8B4A6,\n    0xA8B4A6,\n    0xB1BFB0,\n    0xA7B8A6,\n    0xA4B7A4,\n    0xA3B6A3,\n    0xA4B7A4,\n    0xA6B9A6,\n    0xA7BAA7,\n    0xA6B7A5,\n    0xA4B5A3,\n    0xA4B5A3,\n    0xA6B7A5,\n    0xA8B6A5,\n    0xA6B4A3,\n    0xA7B5A4,\n    0xA9B7A6,\n    0xAAB7A6,\n    0xA8B5A4,\n    0xA7B8A6,\n    0xA5B6A4,\n    0xA5B6A4,\n    0xA7B8A6,\n    0xA5B6A4,\n    0xA2B3A1,\n    0xA0B19F,\n    0xA1B2A0,\n    0x9DAE9C,\n    0x9CAD9B,\n    0x9BAC9A,\n    0x9CAD9B,\n    0x9DAE9C,\n    0x9DAE9C,\n    0x9CAD9B,\n    0x9BAC9A,\n    0x9AAB99,\n    0x9AAB99,\n    0x9AAB99,\n    0x9AAB99,\n    0x9AAB99,\n    0x9AAB99,\n    0x9AAB99,\n    0x9BAC9A,\n    0x98A997,\n    0x9BAC9A,\n    0x9BAC9A,\n    0x98A997,\n    0x98A997,\n    0x9AAB99,\n    0x9AAB99,\n    0x97A895,\n    0x97A993,\n    0x97A993,\n    0x97A993,\n    0x97A895,\n    0x96A795,\n    0x94A593,\n    0x93A494,\n    0x92A393,\n    0x8F9F92,\n    0x8B9B8E,\n    0x364737,\n    0x000F00,\n    0x000F00,\n    0x000C00,\n    0x000B00,\n    0x000C00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000F00,\n    0x000700,\n    0x000700,\n    0x000F00,\n    0x021300,\n    0x081906,\n    0x21321F,\n    0x40513E,\n    0x001100,\n    0x132411,\n    0x10210E,\n    0x031401,\n    0x0A1B08,\n    0x0F200D,\n    0x061704,\n    0x011200,\n    0x102111,\n    0x203023,\n    0x091A0A,\n    0x000D00,\n    0x000E00,\n    0x001100,\n    0x041503,\n    0x000700,\n    0x000D00,\n    0x000D00,\n    0x000D00,\n    0x000F02,\n    0x000E01,\n    0x19291E,\n    0x91A197,\n    0x9AA9A2,\n    0x8A9992,\n    0x8B9A95,\n    0x8C9B96,\n    0x8C9B96,\n    0x8C9B96,\n    0x8E9D98,\n    0x909F98,\n    0x93A29B,\n    0x86958E,\n    0x899891,\n    0x8C9B94,\n    0x8E9D96,\n    0x93A399,\n    0x9CACA2,\n    0xA1B1A7,\n    0xA1B1A7,\n    0xA4B4A7,\n    0xA5B5A8,\n    0xA5B6A6,\n    0xA5B6A6,\n    0xA4B5A5,\n    0xA5B6A6,\n    0xA7B8A8,\n    0xA8B9A9,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xAABBA9,\n    0xAABBA9,\n    0xAABBA9,\n    0xAABBA9,\n    0xAABBA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xADBBAA,\n    0xADBBAA,\n    0xA2B09F,\n    0xA4B2A1,\n    0x9DA99B,\n    0x94A092,\n    0x919D8F,\n    0x8C988A,\n    0x8F9B8D,\n    0x9BA99A,\n    0x97A896,\n    0x93A693,\n    0x92A391,\n    0x93A492,\n    0x97A896,\n    0x98A997,\n    0x95A694,\n    0x92A391,\n    0x98A695,\n    0x9AA897,\n    0x9AA897,\n    0x97A594,\n    0x98A695,\n    0x9AA897,\n    0x9BA998,\n    0x99A796,\n    0x97A896,\n    0x96A795,\n    0x98A997,\n    0x9CAD9B,\n    0x9DAE9C,\n    0x9CAD9B,\n    0x9CAD9B,\n    0x9EAF9D,\n    0xA1B2A0,\n    0xA0B19F,\n    0x9EAF9D,\n    0x9EAF9D,\n    0x9FB09E,\n    0x9FB09E,\n    0x9EAF9D,\n    0x9DAE9C,\n    0x9BAC9A,\n    0x9BAC9A,\n    0x9BAC9A,\n    0x9BAC9A,\n    0x9AAB99,\n    0x9AAB99,\n    0x9AAB99,\n    0x9AAB99,\n    0x98A997,\n    0x9AAB99,\n    0x99AA98,\n    0x97A896,\n    0x97A896,\n    0x99AA98,\n    0x9AAB99,\n    0x99AA97,\n    0x97A993,\n    0x97A993,\n    0x97A993,\n    0x97A895,\n    0x96A795,\n    0x94A593,\n    0x93A494,\n    0x92A393,\n    0x91A194,\n    0x8B9B8E,\n    0x445545,\n    0x001000,\n    0x000F00,\n    0x000C00,\n    0x000C00,\n    0x000D00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000A00,\n    0x000800,\n    0x000B00,\n    0x000D00,\n    0x000700,\n    0x000700,\n    0x000700,\n    0x000D00,\n    0x000A00,\n    0x0D1E0B,\n    0x061704,\n    0x000D00,\n    0x091A07,\n    0x0B1C09,\n    0x011200,\n    0x051604,\n    0x000900,\n    0x061707,\n    0x051604,\n    0x051604,\n    0x000A00,\n    0x1B2C19,\n    0x425340,\n    0x061704,\n    0x000D00,\n    0x000D00,\n    0x000C00,\n    0x000E01,\n    0x000E01,\n    0x233328,\n    0x92A298,\n    0x99A8A1,\n    0xA0AFA8,\n    0xA0AFAA,\n    0xA1B0AB,\n    0xA0AFAA,\n    0x9EADA8,\n    0x9EADA8,\n    0x9FAEA7,\n    0xA0AFA8,\n    0xA3B2AB,\n    0xA4B3AC,\n    0xA2B1AA,\n    0x9FAEA7,\n    0xA0B0A6,\n    0xA4B4AA,\n    0xA6B6AC,\n    0xA6B6AB,\n    0xA4B4A7,\n    0xA5B6A6,\n    0xA6B7A7,\n    0xA5B6A6,\n    0xA4B5A5,\n    0xA5B6A6,\n    0xA7B8A6,\n    0xA9BAA8,\n    0xAABBA9,\n    0xAABBA9,\n    0xAABBA9,\n    0xAABBA9,\n    0xAABBA8,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xADBBAA,\n    0xADBBAA,\n    0xAEBCAB,\n    0xB3C1B0,\n    0xB1BDAF,\n    0xABB7A9,\n    0xA9B5A7,\n    0xA4B0A2,\n    0xA4B0A2,\n    0xADB9AB,\n    0xA6B7A5,\n    0xA4B5A3,\n    0xA4B5A3,\n    0xA4B5A3,\n    0xA8B6A5,\n    0xA8B6A5,\n    0xA6B4A3,\n    0xA4B2A1,\n    0xA0AE9D,\n    0xA2B09F,\n    0xA1AF9E,\n    0x9DAB9A,\n    0x9CAA99,\n    0x9EAC9B,\n    0x9EAC9B,\n    0x9CAA99,\n    0x9AAB99,\n    0x99AA98,\n    0x9BAC9A,\n    0xA0B19F,\n    0xA2B3A1,\n    0xA2B3A1,\n    0xA2B3A1,\n    0xA5B6A4,\n    0xA0B19F,\n    0x9FB09E,\n    0x9DAE9C,\n    0x9CAD9B,\n    0x9CAD9B,\n    0x9BAC9A,\n    0x9AAB99,\n    0x98A997,\n    0x9DAE9B,\n    0x9CAD9A,\n    0x9CAD9A,\n    0x9BAC99,\n    0x9AAB98,\n    0x99AA97,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x97A895,\n    0x96A794,\n    0x97A895,\n    0x99AA97,\n    0x9AAB98,\n    0x99AA97,\n    0x97A991,\n    0x97A993,\n    0x97A993,\n    0x97A895,\n    0x96A795,\n    0x94A593,\n    0x93A494,\n    0x92A393,\n    0x92A295,\n    0x8A9A8D,\n    0x556656,\n    0x001101,\n    0x000E00,\n    0x000A00,\n    0x000C00,\n    0x000D00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000700,\n    0x000700,\n    0x000C00,\n    0x000D00,\n    0x000D00,\n    0x000D00,\n    0x000E00,\n    0x000C00,\n    0x000700,\n    0x000F00,\n    0x000700,\n    0x000700,\n    0x021300,\n    0x000E00,\n    0x000700,\n    0x041502,\n    0x122311,\n    0x182917,\n    0x162714,\n    0x182916,\n    0x001100,\n    0x10210E,\n    0x324330,\n    0x000E00,\n    0x000D00,\n    0x000D00,\n    0x000C00,\n    0x000D00,\n    0x000D00,\n    0x2E3E33,\n    0x93A399,\n    0x95A49D,\n    0x93A29B,\n    0x96A5A0,\n    0x9AA9A4,\n    0x9DACA7,\n    0x9EADA8,\n    0x9FAEA9,\n    0xA1B0A9,\n    0xA2B1AA,\n    0xA4B3AC,\n    0xA5B4AD,\n    0xA4B3AC,\n    0xA1B0A9,\n    0xA2B2A8,\n    0xA6B6AC,\n    0xA8B8AE,\n    0xA7B7AC,\n    0xA5B5A8,\n    0xA6B7A7,\n    0xA6B7A7,\n    0xA6B7A7,\n    0xA5B6A4,\n    0xA6B7A5,\n    0xA8B9A7,\n    0xAABBA9,\n    0xAABBA9,\n    0xAABBA9,\n    0xAABBA8,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xADBBAA,\n    0xADBBAA,\n    0xA8B6A5,\n    0xADBBAA,\n    0xABB7A9,\n    0xA9B5A7,\n    0xADB9AB,\n    0xADB9AB,\n    0xAAB6A8,\n    0xAEBAAC,\n    0xAAB7A6,\n    0xACB9A8,\n    0xAEBBAA,\n    0xAEBBAA,\n    0xABB9A8,\n    0xA9B7A6,\n    0xA9B7A6,\n    0xAAB8A7,\n    0xA8B6A5,\n    0xA9B7A6,\n    0xA8B6A5,\n    0xA4B2A1,\n    0xA3B1A0,\n    0xA5B3A2,\n    0xA6B4A3,\n    0xA4B2A1,\n    0xA2B3A1,\n    0xA0B19F,\n    0xA0B19F,\n    0xA2B3A1,\n    0xA2B3A1,\n    0x9EAF9D,\n    0x9DAE9C,\n    0x9EAF9D,\n    0xA3B4A2,\n    0xA2B3A1,\n    0xA1B2A0,\n    0xA0B19F,\n    0xA1B2A0,\n    0xA0B19F,\n    0x9FB09E,\n    0x9EAF9D,\n    0x9CAD9A,\n    0x9BAC99,\n    0x9BAC99,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x9CAD9A,\n    0x9AAB98,\n    0x98A996,\n    0x98A996,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x97A991,\n    0x97A993,\n    0x97A993,\n    0x97A895,\n    0x96A795,\n    0x94A593,\n    0x93A494,\n    0x92A393,\n    0x91A194,\n    0x87978A,\n    0x677868,\n    0x011202,\n    0x000D00,\n    0x000900,\n    0x000C00,\n    0x000B00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000C00,\n    0x000E00,\n    0x000800,\n    0x000700,\n    0x000700,\n    0x000700,\n    0x000A00,\n    0x000700,\n    0x000B00,\n    0x000C00,\n    0x000700,\n    0x000800,\n    0x001000,\n    0x000900,\n    0x000700,\n    0x031401,\n    0x000700,\n    0x000C00,\n    0x000800,\n    0x000D00,\n    0x001000,\n    0x000800,\n    0x000B00,\n    0x000D00,\n    0x000D00,\n    0x000C00,\n    0x000C00,\n    0x000D00,\n    0x000E01,\n    0x39493F,\n    0x94A49A,\n    0x93A29B,\n    0x81908B,\n    0x84938E,\n    0x899893,\n    0x8D9C97,\n    0x8F9E99,\n    0x909F9A,\n    0x91A099,\n    0x92A19A,\n    0x899891,\n    0x8D9C95,\n    0x8F9E97,\n    0x91A099,\n    0x97A79D,\n    0x9FAFA5,\n    0xA4B4AA,\n    0xA5B5AA,\n    0xA5B6A6,\n    0xA6B7A5,\n    0xA7B8A6,\n    0xA6B7A5,\n    0xA5B6A4,\n    0xA6B7A5,\n    0xA8B9A7,\n    0xAABBA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xACBDAA,\n    0xACBEA8,\n    0xACBEA8,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xAEBCAB,\n    0xAEBCAB,\n    0xABB9A8,\n    0xACBAA9,\n    0xA4B0A2,\n    0x9EAA9C,\n    0xA3AFA1,\n    0xA3AFA1,\n    0x9FAB9D,\n    0x9FAB9D,\n    0xA5B0A0,\n    0xAAB5A5,\n    0xACB9A8,\n    0xABB8A7,\n    0xA7B4A3,\n    0xA4B1A0,\n    0xA5B2A1,\n    0xA7B4A3,\n    0xA9B7A6,\n    0xABB9A8,\n    0xAAB8A7,\n    0xA7B5A4,\n    0xA7B5A4,\n    0xAAB8A7,\n    0xACBAA9,\n    0xABB9A8,\n    0xA5B6A4,\n    0xA3B4A2,\n    0xA3B4A2,\n    0xA5B6A4,\n    0xA5B6A4,\n    0xA1B2A0,\n    0xA0B19F,\n    0xA1B2A0,\n    0x9DAE9C,\n    0x9CAD9B,\n    0x9BAC9A,\n    0x9CAD9B,\n    0x9DAE9C,\n    0x9EAF9D,\n    0x9DAE9C,\n    0x9CAD9B,\n    0x98A996,\n    0x98A996,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9EAF9C,\n    0x9AAB98,\n    0x98A996,\n    0x9BAC99,\n    0x9CAD9A,\n    0x9AAB98,\n    0x97A895,\n    0x96A794,\n    0x97A991,\n    0x97A993,\n    0x97A993,\n    0x97A895,\n    0x96A795,\n    0x94A593,\n    0x93A494,\n    0x92A393,\n    0x91A194,\n    0x859588,\n    0x798A7A,\n    0x041505,\n    0x000E00,\n    0x000800,\n    0x000C00,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000700,\n    0x000800,\n    0x000B00,\n    0x000D00,\n    0x000E00,\n    0x000D00,\n    0x000800,\n    0x000700,\n    0x000800,\n    0x000700,\n    0x000700,\n    0x000700,\n    0x000700,\n    0x000700,\n    0x000700,\n    0x000900,\n    0x000900,\n    0x000E00,\n    0x000800,\n    0x000E00,\n    0x061800,\n    0x000B00,\n    0x000800,\n    0x061802,\n    0x000C00,\n    0x000C00,\n    0x000C00,\n    0x000D00,\n    0x000F02,\n    0x435349,\n    0x97A79D,\n    0x94A39C,\n    0x98A7A2,\n    0x9AA9A4,\n    0x9CABA6,\n    0x9DACA7,\n    0x9DACA7,\n    0x9DACA7,\n    0x9EADA6,\n    0x9FAEA7,\n    0xA1B0A9,\n    0xA4B3AC,\n    0xA4B3AC,\n    0xA2B1AA,\n    0xA2B2A8,\n    0xA5B5AB,\n    0xA6B6AC,\n    0xA4B4A9,\n    0xA6B7A7,\n    0xA7B8A6,\n    0xA7B8A6,\n    0xA7B8A6,\n    0xA6B7A5,\n    0xA7B8A6,\n    0xA9BAA7,\n    0xAABBA8,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xACBDAA,\n    0xACBEA8,\n    0xACBEA8,\n    0xACBEA8,\n    0xACBEA8,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xAEBCAB,\n    0xAEBCAB,\n    0xA9B7A6,\n    0xA9B7A6,\n    0x9FAB9D,\n    0x97A395,\n    0x9AA698,\n    0x9AA698,\n    0x95A193,\n    0x94A092,\n    0x97A292,\n    0x9AA595,\n    0x9DA898,\n    0x9CA797,\n    0x9AA595,\n    0x97A292,\n    0x95A291,\n    0x96A392,\n    0x93A08F,\n    0x94A190,\n    0x92A08F,\n    0x8F9D8C,\n    0x8F9D8C,\n    0x92A08F,\n    0x92A391,\n    0x91A290,\n    0x8B9C8A,\n    0x8A9B89,\n    0x8B9C8A,\n    0x8E9F8D,\n    0x8FA08E,\n    0x8D9E8C,\n    0x8C9D8B,\n    0x8E9F8D,\n    0x90A18F,\n    0x8FA08E,\n    0x8E9F8D,\n    0x8E9F8D,\n    0x8E9F8D,\n    0x8E9F8D,\n    0x8D9E8C,\n    0x8B9C8A,\n    0x95A791,\n    0x95A791,\n    0x94A690,\n    0x94A690,\n    0x94A690,\n    0x93A58F,\n    0x93A58F,\n    0x93A58F,\n    0x95A791,\n    0x91A38D,\n    0x92A48E,\n    0x98AA94,\n    0x9CAE98,\n    0x9AAC96,\n    0x97A993,\n    0x97A993,\n    0x97A991,\n    0x97A993,\n    0x97A993,\n    0x97A895,\n    0x96A795,\n    0x94A593,\n    0x93A494,\n    0x92A393,\n    0x91A194,\n    0x849487,\n    0x879888,\n    0x071808,\n    0x000F00,\n    0x000900,\n    0x000C00,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000D00,\n    0x000800,\n    0x000700,\n    0x000900,\n    0x000900,\n    0x000700,\n    0x000700,\n    0x000D00,\n    0x000800,\n    0x000A00,\n    0x000D00,\n    0x000B00,\n    0x000800,\n    0x000D00,\n    0x001000,\n    0x000700,\n    0x000A00,\n    0x000800,\n    0x000F00,\n    0x000900,\n    0x000800,\n    0x000D00,\n    0x000E00,\n    0x000800,\n    0x000C00,\n    0x000B00,\n    0x000C00,\n    0x000E01,\n    0x001005,\n    0x49594F,\n    0x9BAAA3,\n    0x97A69F,\n    0x9BAAA5,\n    0x9CABA6,\n    0x9DACA7,\n    0x9DACA7,\n    0x9DACA7,\n    0x9FAEA9,\n    0xA1B0A9,\n    0xA4B3AC,\n    0x9FAEA7,\n    0xA2B1AA,\n    0xA3B2AB,\n    0xA2B1AA,\n    0xA3B3A9,\n    0xA6B6AC,\n    0xA6B6AC,\n    0xA4B4A9,\n    0xA6B7A7,\n    0xA7B8A6,\n    0xA7B8A6,\n    0xA7B8A6,\n    0xA6B7A5,\n    0xA7B8A6,\n    0xA9BAA7,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBCA9,\n    0xABBDA7,\n    0xACBEA8,\n    0xACBEA8,\n    0xACBEA8,\n    0xACBEA8,\n    0xADBFA9,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xAEBCAB,\n    0xAEBCAB,\n    0xACBAA9,\n    0xB1BFAE,\n    0xADB9AB,\n    0xA9B5A7,\n    0xAEBAAC,\n    0xB0BCAE,\n    0xACB8AA,\n    0xACB7A9,\n    0xAEB9A9,\n    0xB1B9AA,\n    0xB0BBAB,\n    0xB1BCAC,\n    0xB1BCAC,\n    0xAFBAAA,\n    0xABB8A7,\n    0xAAB7A6,\n    0xADBAA9,\n    0xAEBBAA,\n    0xAAB8A7,\n    0xA6B4A3,\n    0xA5B3A2,\n    0xA8B6A5,\n    0xA7B8A6,\n    0xA6B7A5,\n    0xA4B5A3,\n    0xA2B3A1,\n    0xA2B3A1,\n    0xA3B4A2,\n    0xA2B3A1,\n    0x9EAF9D,\n    0x9CAD9B,\n    0x9DAE9C,\n    0x9EAF9D,\n    0x9CAD9B,\n    0x99AA98,\n    0x97A896,\n    0x96A795,\n    0x94A593,\n    0x91A290,\n    0x8FA08E,\n    0x94A690,\n    0x93A58F,\n    0x91A38D,\n    0x8FA18B,\n    0x8D9F89,\n    0x8B9D87,\n    0x899B85,\n    0x889A84,\n    0x889A84,\n    0x859781,\n    0x899B85,\n    0x93A58F,\n    0x9AAC96,\n    0x9AAC96,\n    0x99AB95,\n    0x99AB95,\n    0x97A991,\n    0x97A993,\n    0x97A993,\n    0x97A895,\n    0x96A795,\n    0x94A593,\n    0x93A494,\n    0x92A393,\n    0x91A194,\n    0x849487,\n    0x90A191,\n    0x0A1B0B,\n    0x001100,\n    0x000A00,\n    0x000D00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000C00,\n    0x000800,\n    0x000800,\n    0x000700,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000D00,\n    0x000D00,\n    0x000800,\n    0x000D00,\n    0x000F00,\n    0x07170A,\n    0x5B6B61,\n    0x94A3A0,\n    0x8A9898,\n    0x909F9A,\n    0x92A19C,\n    0x96A5A0,\n    0x98A7A2,\n    0x99A8A3,\n    0x99A8A3,\n    0x9AA9A2,\n    0x9BAAA3,\n    0x9FAEA7,\n    0xA0AFA8,\n    0xA0AFA8,\n    0xA1B0A9,\n    0xA2B2A8,\n    0xA3B3A9,\n    0xA4B4AA,\n    0xA4B3AC,\n    0xA5B4AD,\n    0xA6B5B0,\n    0xA6B5AE,\n    0xA6B6AC,\n    0xA6B6AB,\n    0xA7B7AA,\n    0xA9BAA8,\n    0xABBCAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAB,\n    0xACBDAB,\n    0xAABDA7,\n    0xABBEA8,\n    0xABBEAA,\n    0xABBEAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAB,\n    0xACBDAB,\n    0xAFC0AE,\n    0xACBDAB,\n    0xA6B4A5,\n    0x9BA99A,\n    0x97A596,\n    0x9AA899,\n    0x9CAA9D,\n    0x9BA99C,\n    0x97A493,\n    0xA3B09F,\n    0xA8B5A4,\n    0xA1AE9D,\n    0x9FAC9B,\n    0xA6B3A2,\n    0xA7B4A3,\n    0xA1AE9D,\n    0xA3B09F,\n    0xA0AD9C,\n    0x9EAB9A,\n    0xA0AD9C,\n    0xA5B2A1,\n    0xA9B6A5,\n    0xAAB7A6,\n    0xA9B6A5,\n    0xA3AFA1,\n    0xA0AC9E,\n    0xA1AD9F,\n    0xA5B1A3,\n    0xA7B3A5,\n    0xA3AFA1,\n    0xA1AE9D,\n    0xA2AF9E,\n    0xA2AF9E,\n    0xA2AF9E,\n    0xA2AF9D,\n    0xA2AF9D,\n    0xA2AF9D,\n    0xA1AE9C,\n    0xA1AE9C,\n    0xA0AD9B,\n    0x98A996,\n    0x9BAC99,\n    0x9DAE9B,\n    0x9CAD9A,\n    0x99AA97,\n    0x99AA97,\n    0x9CAD9A,\n    0x9FB09D,\n    0x9BAC99,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AB95,\n    0x99AB95,\n    0x99AB95,\n    0x99AB95,\n    0x97A895,\n    0x96A794,\n    0x94A592,\n    0x93A491,\n    0x8FA08D,\n    0x8C9D8A,\n    0x869785,\n    0x243523,\n    0x000B00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000A00,\n    0x000F00,\n    0x011200,\n    0x000E00,\n    0x000B00,\n    0x000900,\n    0x001200,\n    0x000D00,\n    0x000D00,\n    0x000E00,\n    0x021205,\n    0x637369,\n    0x98A7A4,\n    0x909E9E,\n    0x8B9A95,\n    0x8D9C97,\n    0x909F9A,\n    0x91A09B,\n    0x91A09B,\n    0x909F9A,\n    0x909F98,\n    0x91A099,\n    0x8A9992,\n    0x8C9B94,\n    0x909F98,\n    0x95A49D,\n    0x9BABA1,\n    0xA0B0A6,\n    0xA4B4AA,\n    0xA6B5AE,\n    0xA5B4AD,\n    0xA6B5B0,\n    0xA6B5AE,\n    0xA6B6AC,\n    0xA6B6AB,\n    0xA7B7AA,\n    0xA9BAA8,\n    0xABBCAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAB,\n    0xACBDAB,\n    0xAABDA9,\n    0xAABDA9,\n    0xABBEAA,\n    0xABBEAA,\n    0xADBEAB,\n    0xACBDAA,\n    0xACBDAB,\n    0xACBDAB,\n    0xA5B6A4,\n    0xA6B7A5,\n    0xA6B4A5,\n    0xA2B0A1,\n    0xA1AFA0,\n    0xA4B2A3,\n    0xA5B3A4,\n    0xA3B1A2,\n    0xA0AD9C,\n    0xA6B3A2,\n    0xA5B2A1,\n    0x9DAA99,\n    0x99A695,\n    0x9DAA99,\n    0xA0AD9C,\n    0x9EAB9A,\n    0xA0AD9C,\n    0x9BA897,\n    0x97A493,\n    0x96A392,\n    0x97A493,\n    0x97A493,\n    0x95A291,\n    0x929F8E,\n    0x95A193,\n    0x929E90,\n    0x919D8F,\n    0x94A092,\n    0x939F91,\n    0x8F9B8D,\n    0x8C9988,\n    0x8C9988,\n    0x8D9A89,\n    0x8D9A89,\n    0x8E9B89,\n    0x8E9B89,\n    0x8D9A88,\n    0x8D9A88,\n    0x8C9987,\n    0x8C9987,\n    0x889986,\n    0x8B9C89,\n    0x8D9E8B,\n    0x8D9E8B,\n    0x8C9D8A,\n    0x8C9D8A,\n    0x8FA08D,\n    0x93A491,\n    0x9BAC99,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AB95,\n    0x99AB95,\n    0x99AB95,\n    0x99AB95,\n    0x97A895,\n    0x96A794,\n    0x94A592,\n    0x93A491,\n    0x8E9F8C,\n    0x8C9D8A,\n    0x879886,\n    0x2E3F2D,\n    0x000F00,\n    0x000C00,\n    0x000B00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000C00,\n    0x001100,\n    0x021301,\n    0x000F00,\n    0x000A00,\n    0x000900,\n    0x000B00,\n    0x000E00,\n    0x000800,\n    0x000F00,\n    0x000F02,\n    0x74847A,\n    0x9CABA8,\n    0x97A5A5,\n    0x9BAAA5,\n    0x9DACA7,\n    0xA0AFAA,\n    0xA1B0AB,\n    0xA0AFAA,\n    0xA0AFAA,\n    0xA1B0A9,\n    0xA1B0A9,\n    0xA7B6AF,\n    0xA7B6AF,\n    0xA6B5AE,\n    0xA6B5AE,\n    0xA5B5AB,\n    0xA4B4AA,\n    0xA3B3A9,\n    0xA3B2AB,\n    0xA5B4AD,\n    0xA6B5B0,\n    0xA7B6AF,\n    0xA6B5AE,\n    0xA6B6AB,\n    0xA7B7AC,\n    0xA9BAAA,\n    0xABBCAC,\n    0xACBDAB,\n    0xACBDAB,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAB,\n    0xACBDAB,\n    0xAABDA9,\n    0xAABDA9,\n    0xABBEAA,\n    0xABBEAA,\n    0xADBEAB,\n    0xADBEAB,\n    0xADBEAC,\n    0xACBDAB,\n    0xB1C2B0,\n    0xB2C3B1,\n    0xB2C0B1,\n    0xADBBAC,\n    0xABB9AA,\n    0xACBAAB,\n    0xACBAAB,\n    0xAAB8A9,\n    0xADBAA9,\n    0xAEBBAA,\n    0xAEBBAA,\n    0xACB9A8,\n    0xA9B6A5,\n    0xA9B6A5,\n    0xABB8A7,\n    0xAFBCAB,\n    0xABB8A7,\n    0xA8B5A4,\n    0xA6B3A2,\n    0xA6B3A2,\n    0xA8B5A4,\n    0xAAB7A6,\n    0xAAB7A6,\n    0xA8B5A4,\n    0xABB7A9,\n    0xA8B4A6,\n    0xA7B3A5,\n    0xA8B4A6,\n    0xA7B3A5,\n    0xA4B0A2,\n    0xA0AD9C,\n    0xA0AD9C,\n    0xA1AE9D,\n    0xA2AF9E,\n    0xA2AF9D,\n    0xA2AF9D,\n    0xA2AF9D,\n    0xA1AE9C,\n    0xA0AD9B,\n    0xA0AD9B,\n    0x94A592,\n    0x96A794,\n    0x97A895,\n    0x97A895,\n    0x96A794,\n    0x96A794,\n    0x98A996,\n    0x9BAC99,\n    0x9BAC99,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AB95,\n    0x99AB95,\n    0x99AB95,\n    0x99AB95,\n    0x97A895,\n    0x96A794,\n    0x94A592,\n    0x93A491,\n    0x8E9F8C,\n    0x8C9D8A,\n    0x899A88,\n    0x3D4E3C,\n    0x011200,\n    0x000E00,\n    0x000C00,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000800,\n    0x000800,\n    0x000A00,\n    0x000B00,\n    0x000A00,\n    0x000A00,\n    0x000C00,\n    0x000800,\n    0x001000,\n    0x000700,\n    0x011200,\n    0x001003,\n    0x819187,\n    0x97A6A3,\n    0x919F9F,\n    0x94A39E,\n    0x96A5A0,\n    0x99A8A3,\n    0x9BAAA5,\n    0x9CABA6,\n    0x9DACA7,\n    0x9FAEA7,\n    0xA1B0A9,\n    0xA2B1AA,\n    0xA2B1AA,\n    0xA2B1AA,\n    0xA3B2AB,\n    0xA4B4AA,\n    0xA5B5AB,\n    0xA5B5AB,\n    0xA6B5AE,\n    0xA5B4AD,\n    0xA6B5B0,\n    0xA7B6AF,\n    0xA7B6AF,\n    0xA6B6AC,\n    0xA7B7AD,\n    0xA9B9AC,\n    0xABBBAE,\n    0xACBDAD,\n    0xACBDAD,\n    0xACBDAB,\n    0xACBDAB,\n    0xACBDAB,\n    0xACBDAB,\n    0xACBDAA,\n    0xACBDAA,\n    0xA9BCA9,\n    0xAABDAA,\n    0xABBEAB,\n    0xABBEAB,\n    0xADBEAC,\n    0xADBEAC,\n    0xADBEAC,\n    0xADBEAC,\n    0xA8B9A7,\n    0xA4B5A3,\n    0xA0AE9D,\n    0x99A796,\n    0x95A392,\n    0x95A392,\n    0x96A493,\n    0x97A594,\n    0x98A695,\n    0x97A594,\n    0x9AA897,\n    0xA0AE9D,\n    0x9EAC9B,\n    0x98A695,\n    0x96A493,\n    0x9AA897,\n    0x98A695,\n    0x97A594,\n    0x98A695,\n    0x9CAA99,\n    0xA1AF9E,\n    0xA5B3A2,\n    0xA7B5A4,\n    0xA7B5A4,\n    0xA5B3A4,\n    0xA3B1A2,\n    0xA3B1A2,\n    0xA4B2A3,\n    0xA5B3A4,\n    0xA4B2A3,\n    0xA2B09F,\n    0xA1AF9E,\n    0xA0AE9D,\n    0xA0AE9D,\n    0xA0AF9C,\n    0xA0AF9C,\n    0xA0AF9C,\n    0x9FAE9B,\n    0x9FAE9B,\n    0x9EAD9A,\n    0x9DAE9B,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9AAB98,\n    0x99AA97,\n    0x9AAB98,\n    0x9CAD9A,\n    0x9BAC99,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AB95,\n    0x99AB95,\n    0x99AB95,\n    0x99AB95,\n    0x97A895,\n    0x96A794,\n    0x94A592,\n    0x93A491,\n    0x8FA08D,\n    0x8C9D8A,\n    0x889987,\n    0x4D5E4C,\n    0x011200,\n    0x000D00,\n    0x000D00,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000C00,\n    0x000800,\n    0x000800,\n    0x000700,\n    0x000700,\n    0x000700,\n    0x000900,\n    0x000E00,\n    0x000A00,\n    0x041600,\n    0x000A00,\n    0x021301,\n    0x021205,\n    0x87978D,\n    0x8E9D9A,\n    0x8B9999,\n    0x879691,\n    0x899893,\n    0x8B9A95,\n    0x8D9C97,\n    0x8E9D98,\n    0x909F9A,\n    0x92A19A,\n    0x94A39C,\n    0x92A19A,\n    0x93A29B,\n    0x95A49D,\n    0x97A69F,\n    0x99A99F,\n    0x9CACA2,\n    0x9EAEA4,\n    0x9EAEA4,\n    0xA6B5AE,\n    0xA6B5AE,\n    0xA7B6AF,\n    0xA7B6AF,\n    0xA6B6AC,\n    0xA7B7AD,\n    0xAABAAF,\n    0xACBCB1,\n    0xACBCAF,\n    0xACBCAF,\n    0xACBDAD,\n    0xACBDAD,\n    0xACBDAB,\n    0xACBDAB,\n    0xACBDAA,\n    0xACBDAA,\n    0xAABDAA,\n    0xAABDAA,\n    0xABBEAB,\n    0xABBEAB,\n    0xADBEAC,\n    0xADBEAC,\n    0xACBDAB,\n    0xACBDAB,\n    0xB3C4B2,\n    0xB0C1AF,\n    0xAEBCAB,\n    0xABB9A8,\n    0xA9B7A6,\n    0xA9B7A6,\n    0xABB9A8,\n    0xADBBAA,\n    0xAAB8A7,\n    0xA6B4A3,\n    0xA8B6A5,\n    0xAEBCAB,\n    0xABB9A8,\n    0xA1AF9E,\n    0x9DAB9A,\n    0xA1AF9E,\n    0xA3B1A0,\n    0xA3B1A0,\n    0xA3B1A0,\n    0xA5B3A2,\n    0xA7B5A4,\n    0xA8B6A5,\n    0xA9B7A6,\n    0xA9B7A6,\n    0xA7B5A6,\n    0xA7B5A6,\n    0xA7B5A6,\n    0xA7B5A6,\n    0xA9B7A8,\n    0xAAB8A9,\n    0xA9B7A6,\n    0xA7B5A4,\n    0xA4B2A1,\n    0xA4B2A1,\n    0xA4B3A0,\n    0xA4B3A0,\n    0xA4B3A0,\n    0xA4B3A0,\n    0xA3B29F,\n    0xA3B29F,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9CAD9A,\n    0x9BAC99,\n    0x99AA97,\n    0x98A996,\n    0x98A996,\n    0x99AA97,\n    0x9BAC99,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AB95,\n    0x99AB95,\n    0x99AB95,\n    0x99AB95,\n    0x97A895,\n    0x96A794,\n    0x94A592,\n    0x93A491,\n    0x91A28F,\n    0x8B9C89,\n    0x869785,\n    0x5D6E5C,\n    0x001100,\n    0x000B00,\n    0x000F00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000A00,\n    0x000900,\n    0x000A00,\n    0x000B00,\n    0x000A00,\n    0x000800,\n    0x000900,\n    0x000C00,\n    0x000C00,\n    0x011300,\n    0x000800,\n    0x001000,\n    0x08180B,\n    0x8E9E94,\n    0x93A29F,\n    0x95A3A3,\n    0x94A39E,\n    0x96A5A0,\n    0x97A6A1,\n    0x98A7A2,\n    0x98A7A2,\n    0x99A8A3,\n    0x9BAAA3,\n    0x9DACA5,\n    0xA2B1AA,\n    0xA1B0A9,\n    0xA0AFA8,\n    0x9FAEA7,\n    0x9DADA3,\n    0x9CACA2,\n    0x9AAAA0,\n    0x9AAAA0,\n    0xA6B5AE,\n    0xA7B6AF,\n    0xA7B6AF,\n    0xA7B6AF,\n    0xA7B6AF,\n    0xA8B7B0,\n    0xAAB9B2,\n    0xACBBB4,\n    0xACBCB1,\n    0xACBCB1,\n    0xACBCAF,\n    0xACBCAF,\n    0xACBDAB,\n    0xACBDAB,\n    0xACBDAA,\n    0xACBDAB,\n    0xABBEAB,\n    0xABBDAD,\n    0xABBDAD,\n    0xACBEAE,\n    0xACBDAD,\n    0xACBDAD,\n    0xACBDAB,\n    0xABBCAA,\n    0xADBEAC,\n    0xABBCAA,\n    0xAEBDAA,\n    0xB1C0AD,\n    0xB0BFAC,\n    0xADBCA9,\n    0xACBBA8,\n    0xADBCA9,\n    0xADBEAC,\n    0xA8B9A7,\n    0xA7B8A6,\n    0xAABBA9,\n    0xA9BAA8,\n    0xA5B6A4,\n    0xA5B6A4,\n    0xA9BAA8,\n    0xA5B6A4,\n    0xA5B6A4,\n    0xA4B5A3,\n    0xA4B5A3,\n    0xA3B4A2,\n    0xA3B4A2,\n    0xA2B3A1,\n    0xA1B2A0,\n    0xA2B3A3,\n    0xA2B3A3,\n    0xA1B2A2,\n    0x9FB0A0,\n    0xA0B1A1,\n    0xA2B3A3,\n    0xA1B2A0,\n    0x9EAF9D,\n    0x9CAD9B,\n    0x9CAD9B,\n    0x9CAD9A,\n    0x9CAD9A,\n    0x9CAD9A,\n    0x9BAC99,\n    0x9BAC99,\n    0x9AAB98,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9BAC99,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AB95,\n    0x99AB95,\n    0x99AB95,\n    0x99AB95,\n    0x97A895,\n    0x96A794,\n    0x94A592,\n    0x93A491,\n    0x92A390,\n    0x8B9C89,\n    0x859684,\n    0x6D7E6C,\n    0x001100,\n    0x000B00,\n    0x001000,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000D00,\n    0x000B00,\n    0x000800,\n    0x000800,\n    0x000B00,\n    0x000A00,\n    0x000C00,\n    0x000800,\n    0x000F00,\n    0x132316,\n    0x94A49A,\n    0x96A5A2,\n    0x9AA8A8,\n    0x9AA9A4,\n    0x9BAAA5,\n    0x9DACA7,\n    0x9DACA7,\n    0x9EADA8,\n    0x9FAEA9,\n    0xA1B0A9,\n    0xA3B2AB,\n    0x9FAEA7,\n    0xA0AFA8,\n    0xA0AFA8,\n    0xA2B1AA,\n    0xA3B3A9,\n    0xA4B4AA,\n    0xA5B5AB,\n    0xA5B5AB,\n    0xA6B5AE,\n    0xA7B6AF,\n    0xA8B7B0,\n    0xA7B6AF,\n    0xA7B6B1,\n    0xA8B7B2,\n    0xAAB9B2,\n    0xACBBB4,\n    0xACBCB2,\n    0xACBCB2,\n    0xACBCAF,\n    0xACBCAF,\n    0xACBDAB,\n    0xACBDAB,\n    0xACBEA8,\n    0xACBDAA,\n    0xACBFAC,\n    0xACBEAE,\n    0xACBEAE,\n    0xACBEAE,\n    0xACBDAD,\n    0xACBDAD,\n    0xABBCAA,\n    0xAABBA9,\n    0xA9BAA8,\n    0xA7B8A6,\n    0xABBAA7,\n    0xAEBDAA,\n    0xAEBDAA,\n    0xAAB9A6,\n    0xA8B7A4,\n    0xAAB9A6,\n    0xA8B9A7,\n    0xA7B8A6,\n    0xA8B9A7,\n    0xAABBA9,\n    0xABBCAA,\n    0xACBDAB,\n    0xADBEAC,\n    0xAEBFAD,\n    0xA8B9A7,\n    0xA8B9A7,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xA9BAA8,\n    0xA8B9A7,\n    0xA9BAA8,\n    0xA8B9A9,\n    0xA9BAAA,\n    0xA7B8A8,\n    0xA4B5A5,\n    0xA4B5A5,\n    0xA7B8A8,\n    0xA6B7A5,\n    0xA3B4A2,\n    0xA1B2A0,\n    0xA2B3A1,\n    0xA2B3A0,\n    0xA2B3A0,\n    0xA2B3A0,\n    0xA1B29F,\n    0xA0B19E,\n    0xA0B19E,\n    0x9BAC99,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9BAC99,\n    0x9BAC99,\n    0x9BAC99,\n    0x9BAC99,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AB95,\n    0x99AB95,\n    0x99AB95,\n    0x99AB95,\n    0x97A895,\n    0x96A794,\n    0x94A592,\n    0x93A491,\n    0x92A390,\n    0x8B9C89,\n    0x879886,\n    0x7C8D7B,\n    0x041503,\n    0x000C00,\n    0x001100,\n    0x000800,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000B00,\n    0x000900,\n    0x000A00,\n    0x000A00,\n    0x000800,\n    0x000700,\n    0x000800,\n    0x000D00,\n    0x000D00,\n    0x000D00,\n    0x000E00,\n    0x031402,\n    0x1C2C1F,\n    0x92A298,\n    0x8D9C99,\n    0x909E9E,\n    0x93A29D,\n    0x95A49F,\n    0x97A6A1,\n    0x98A7A2,\n    0x9AA9A4,\n    0x9CABA6,\n    0x9FAEA7,\n    0xA2B1AA,\n    0xA5B4AD,\n    0xA5B4AD,\n    0xA5B4AD,\n    0xA5B4AD,\n    0xA5B5AB,\n    0xA5B5AB,\n    0xA6B6AC,\n    0xA6B6AC,\n    0xA6B6AC,\n    0xA7B7AD,\n    0xA8B7B0,\n    0xA7B6AF,\n    0xA7B6B1,\n    0xA8B7B2,\n    0xAAB9B4,\n    0xACBBB6,\n    0xACBBB4,\n    0xACBCB2,\n    0xACBCB1,\n    0xACBCAF,\n    0xACBDAB,\n    0xACBDAB,\n    0xACBEA8,\n    0xACBDAA,\n    0xACBEAE,\n    0xACBEB0,\n    0xACBEAE,\n    0xACBEAE,\n    0xACBDAD,\n    0xABBCAC,\n    0xAABBA9,\n    0xAABBA9,\n    0xA6B7A5,\n    0xA3B4A2,\n    0xA5B4A1,\n    0xA8B7A4,\n    0xAAB9A6,\n    0xAAB9A6,\n    0xADBCA7,\n    0xB2C1AE,\n    0xA1B29F,\n    0xA5B6A4,\n    0xA8B9A7,\n    0xA8B9A7,\n    0xA9BAA8,\n    0xA8B9A7,\n    0xA4B5A3,\n    0x9FB09E,\n    0xA3B4A2,\n    0xA4B5A3,\n    0xA5B6A4,\n    0xA5B6A4,\n    0xA4B5A3,\n    0xA4B5A3,\n    0xA3B4A2,\n    0xA4B5A3,\n    0xA2B3A3,\n    0xA4B5A5,\n    0xA3B4A4,\n    0x9FB0A0,\n    0xA1B2A2,\n    0xA4B5A5,\n    0xA4B5A3,\n    0xA0B19F,\n    0xA0B19F,\n    0xA0B19F,\n    0xA0B19E,\n    0xA0B19E,\n    0xA0B19E,\n    0x9FB09D,\n    0x9FB09D,\n    0x9EAF9C,\n    0xA0B19E,\n    0x9FB09D,\n    0x9DAE9B,\n    0x9CAD9A,\n    0x9CAD9A,\n    0x9CAD9A,\n    0x9BAC99,\n    0x9AAB98,\n    0x9BAC99,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AB95,\n    0x99AB95,\n    0x99AB95,\n    0x99AB95,\n    0x97A895,\n    0x96A794,\n    0x94A592,\n    0x93A491,\n    0x92A390,\n    0x8B9C89,\n    0x889987,\n    0x869785,\n    0x071806,\n    0x000D00,\n    0x011200,\n    0x000700,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000D00,\n    0x011202,\n    0x000D02,\n    0x2A3A2F,\n    0x90A096,\n    0x8B9A93,\n    0x94A39C,\n    0x85958B,\n    0x84948A,\n    0x85958B,\n    0x88988E,\n    0x8B9B91,\n    0x8C9C92,\n    0x8A9A90,\n    0x87978D,\n    0x92A298,\n    0x94A49A,\n    0x95A59B,\n    0x95A59B,\n    0x93A399,\n    0x92A298,\n    0x92A298,\n    0x92A298,\n    0xA0B0A6,\n    0xA2B2A8,\n    0xA5B5AB,\n    0xA7B7AD,\n    0xA8B8AD,\n    0xA8B8AD,\n    0xA8B8AB,\n    0xA9B9AC,\n    0xACBDAD,\n    0xACBDAD,\n    0xACBDAB,\n    0xACBDAB,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xADBEAB,\n    0xACBDAA,\n    0xAABBA8,\n    0xABBCA9,\n    0xAABBA8,\n    0xA1B29F,\n    0x96A794,\n    0x97A895,\n    0x98A996,\n    0x768774,\n    0x768774,\n    0x7B8C79,\n    0x7C8D7A,\n    0x8B9C89,\n    0x768774,\n    0x94A592,\n    0x798A77,\n    0x879885,\n    0x7E8F7C,\n    0x7F907D,\n    0x92A390,\n    0x80917E,\n    0x788976,\n    0x7A8B78,\n    0x7A8B78,\n    0x8A9B88,\n    0x80917E,\n    0x6C7D6A,\n    0x889986,\n    0x98A996,\n    0x728370,\n    0x899A87,\n    0x92A390,\n    0x9EAF9C,\n    0xA5B6A3,\n    0xA5B6A3,\n    0xA3B4A1,\n    0xA1B29F,\n    0xA0B19E,\n    0xA1B29F,\n    0xA0B19E,\n    0xA0B19E,\n    0x9FB09D,\n    0x9FB09D,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9FB09D,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9CAD9A,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9BAC99,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x97A895,\n    0x96A794,\n    0x94A593,\n    0x93A492,\n    0x93A492,\n    0x8A9B89,\n    0x8B9C8C,\n    0x7E8F7F,\n    0x1E2F1F,\n    0x000A00,\n    0x000C00,\n    0x000E00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000C00,\n    0x000C00,\n    0x000F00,\n    0x000B00,\n    0x324237,\n    0x95A59B,\n    0x93A29B,\n    0x9AA9A2,\n    0x9BABA1,\n    0x9CACA2,\n    0x9DADA3,\n    0xA0B0A6,\n    0xA2B2A8,\n    0xA4B4AA,\n    0xA3B3A9,\n    0xA2B2A8,\n    0xA1B1A7,\n    0xA1B1A7,\n    0xA2B2A8,\n    0xA1B1A7,\n    0xA1B1A7,\n    0xA2B2A8,\n    0xA5B5AB,\n    0xA7B7AD,\n    0xA3B3A9,\n    0xA5B5AB,\n    0xA7B7AD,\n    0xA8B8AE,\n    0xA8B8AD,\n    0xA8B8AD,\n    0xAABAAD,\n    0xABBBAE,\n    0xACBDAD,\n    0xACBDAD,\n    0xACBDAB,\n    0xACBDAB,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xACBDAA,\n    0xAABBA8,\n    0xACBDAA,\n    0xADBEAB,\n    0xABBCA9,\n    0xABBCA9,\n    0xACBDAA,\n    0xA9BAA7,\n    0xA4B5A2,\n    0xA9BAA7,\n    0xB2C3B0,\n    0x9EAF9C,\n    0xA4B5A2,\n    0xA9BAA7,\n    0xA6B7A4,\n    0xB3C4B1,\n    0xA0B19E,\n    0xADBEAB,\n    0x9CAD9A,\n    0xA7B8A5,\n    0x9DAE9B,\n    0x9EAF9C,\n    0xADBEAB,\n    0x9CAD9A,\n    0x9CAD9A,\n    0x9AAB98,\n    0x94A592,\n    0x9DAE9B,\n    0x98A996,\n    0x869784,\n    0x92A390,\n    0x9BAC99,\n    0x849582,\n    0x92A390,\n    0x99AA97,\n    0xA0B19E,\n    0xA4B5A2,\n    0xA4B5A2,\n    0xA2B3A0,\n    0xA1B29F,\n    0xA2B3A0,\n    0xA0B19E,\n    0xA0B19E,\n    0xA0B19E,\n    0x9FB09D,\n    0x9FB09D,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9CAD9A,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x97A895,\n    0x96A794,\n    0x94A593,\n    0x93A492,\n    0x92A391,\n    0x8B9C8A,\n    0x8D9E8E,\n    0x819282,\n    0x273828,\n    0x000C00,\n    0x000C00,\n    0x000C00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000D00,\n    0x000B00,\n    0x000E00,\n    0x000C01,\n    0x3F4F44,\n    0x96A69C,\n    0x92A19A,\n    0x94A39C,\n    0x95A49D,\n    0x97A69F,\n    0x99A8A1,\n    0x9BAAA3,\n    0x9CABA4,\n    0x9EADA6,\n    0xA0AFA8,\n    0xA2B1AA,\n    0xA3B2AB,\n    0xA5B4AD,\n    0xA7B6AF,\n    0xA8B7B0,\n    0xA7B6AF,\n    0xA7B6AF,\n    0xA9B8B1,\n    0xAAB9B2,\n    0xA6B6AB,\n    0xA7B7AC,\n    0xA8B8AD,\n    0xA8B8AD,\n    0xA8B8AD,\n    0xA9B9AE,\n    0xABBBAE,\n    0xADBDB0,\n    0xACBDAD,\n    0xACBDAD,\n    0xACBDAB,\n    0xACBDAB,\n    0xACBDAB,\n    0xACBDAB,\n    0xACBDAB,\n    0xACBDAB,\n    0xA9BAA7,\n    0xACBDAA,\n    0xADBEAB,\n    0xABBCA9,\n    0xAABBA8,\n    0xABBCA9,\n    0xAEBFAC,\n    0xAEBFAC,\n    0xA0B19E,\n    0xAEBFAC,\n    0xA4B5A2,\n    0xAABBA8,\n    0xABBCA9,\n    0xA7B8A5,\n    0xB2C3B0,\n    0xA6B7A4,\n    0xADBEAB,\n    0xA8B9A6,\n    0xB0C1AE,\n    0xA3B4A1,\n    0xA5B6A3,\n    0xAEBFAC,\n    0x9FB09D,\n    0xA7B8A5,\n    0xACBDAA,\n    0xA3B4A1,\n    0xA6B7A4,\n    0xAABBA8,\n    0xA3B4A1,\n    0xA1B29F,\n    0xA4B5A2,\n    0xA1B29F,\n    0x9DAE9B,\n    0xA0B19E,\n    0xA4B5A2,\n    0xA4B5A2,\n    0xA2B3A0,\n    0xA1B29F,\n    0xA1B29F,\n    0xA3B4A1,\n    0xA0B19E,\n    0xA0B19E,\n    0xA0B19E,\n    0x9FB09D,\n    0x9FB09D,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9CAD9A,\n    0x9CAD9A,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x97A895,\n    0x95A693,\n    0x94A593,\n    0x93A492,\n    0x91A290,\n    0x8C9D8B,\n    0x8E9F8F,\n    0x839484,\n    0x364737,\n    0x000E00,\n    0x000C00,\n    0x000B00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x001000,\n    0x000F04,\n    0x4B5B50,\n    0x90A096,\n    0x8B9A93,\n    0x889790,\n    0x8C9B94,\n    0x8E9D96,\n    0x91A099,\n    0x91A099,\n    0x91A099,\n    0x93A29B,\n    0x97A69F,\n    0x9AA9A2,\n    0x95A49D,\n    0x9AA9A2,\n    0xA0AFA8,\n    0xA4B3AC,\n    0xA6B5AE,\n    0xA5B4AD,\n    0xA4B3AC,\n    0xA3B2AB,\n    0xA9B9AE,\n    0xA9B9AE,\n    0xA8B8AD,\n    0xA7B7AC,\n    0xA6B6A9,\n    0xA8B8AB,\n    0xABBBAE,\n    0xADBDB0,\n    0xABBCAC,\n    0xABBCAC,\n    0xABBCAC,\n    0xABBCAC,\n    0xABBCAA,\n    0xABBCAA,\n    0xABBCAA,\n    0xABBCAA,\n    0xABBCA9,\n    0xACBDAA,\n    0xACBDAA,\n    0xAABBA8,\n    0xA8B9A6,\n    0xA9BAA7,\n    0xAABBA8,\n    0xABBCA9,\n    0xAABBA8,\n    0xB1C2AF,\n    0xA7B8A5,\n    0xA6B7A4,\n    0xA2B3A0,\n    0x9FB09D,\n    0xABBCA9,\n    0xA5B6A3,\n    0x9DAE9B,\n    0xA2B3A0,\n    0xA5B6A3,\n    0x9CAD9A,\n    0xA7B8A5,\n    0xAEBFAC,\n    0xA3B4A1,\n    0xAFC0AD,\n    0xA8B9A6,\n    0xA5B6A3,\n    0xA4B5A2,\n    0xAABBA8,\n    0xACBDAA,\n    0xA7B8A5,\n    0xA6B7A4,\n    0xADBEAB,\n    0xA2B3A0,\n    0xA4B5A2,\n    0xA5B6A3,\n    0xA4B5A2,\n    0xA2B3A0,\n    0xA1B29F,\n    0xA1B29F,\n    0xA2B3A0,\n    0xA0B19E,\n    0xA0B19E,\n    0x9FB09D,\n    0x9FB09D,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9CAD9A,\n    0x9BAC99,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x97A895,\n    0x95A693,\n    0x94A593,\n    0x93A492,\n    0x91A290,\n    0x8E9F8D,\n    0x8D9E8E,\n    0x839484,\n    0x465747,\n    0x000E00,\n    0x000C00,\n    0x000B00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000B00,\n    0x000B00,\n    0x011202,\n    0x001005,\n    0x57675C,\n    0x8C9C92,\n    0x8D9C95,\n    0x8C9B94,\n    0x8F9E97,\n    0x92A19A,\n    0x94A39C,\n    0x94A39C,\n    0x94A39C,\n    0x95A49D,\n    0x98A7A0,\n    0x9BAAA3,\n    0x94A39C,\n    0x99A8A1,\n    0x9EADA6,\n    0xA3B2AB,\n    0xA6B5AE,\n    0xA7B6AF,\n    0xA8B7B0,\n    0xA9B9AF,\n    0xA8B8AD,\n    0xA8B8AB,\n    0xA7B7AA,\n    0xA6B6A9,\n    0xA5B5A8,\n    0xA6B6A9,\n    0xA9B9AC,\n    0xACBCAF,\n    0xABBCAC,\n    0xABBCAC,\n    0xABBCAC,\n    0xABBCAC,\n    0xABBCAC,\n    0xABBCAC,\n    0xABBCAC,\n    0xABBCAC,\n    0xABBCA9,\n    0xAABBA8,\n    0xA9BAA7,\n    0xAABBA8,\n    0xAABBA8,\n    0xA9BAA7,\n    0xA8B9A6,\n    0xA7B8A5,\n    0xA2B3A0,\n    0xA2B3A0,\n    0x97A895,\n    0x91A28F,\n    0x8E9F8C,\n    0x8E9F8C,\n    0x96A794,\n    0x95A693,\n    0x849582,\n    0x8A9B88,\n    0x8B9C89,\n    0x8A9B88,\n    0x9AAB98,\n    0xA4B5A2,\n    0x9DAE9B,\n    0xA6B7A4,\n    0xA6B7A4,\n    0xAABBA8,\n    0xA6B7A4,\n    0xA3B4A1,\n    0xA8B9A6,\n    0xA5B6A3,\n    0xA1B29F,\n    0xA5B6A3,\n    0xA2B3A0,\n    0xA3B4A1,\n    0xA4B5A2,\n    0xA4B5A2,\n    0xA3B4A1,\n    0xA1B29F,\n    0xA0B19E,\n    0xA0B19E,\n    0xA0B19E,\n    0xA0B19E,\n    0x9FB09D,\n    0x9FB09D,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9CAD9A,\n    0x9CAD9A,\n    0x9CAD9A,\n    0x9BAC99,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x97A895,\n    0x95A693,\n    0x93A492,\n    0x92A391,\n    0x91A290,\n    0x8FA08E,\n    0x8A9B8B,\n    0x809181,\n    0x556656,\n    0x000D00,\n    0x000C00,\n    0x000C00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000C00,\n    0x000B00,\n    0x001000,\n    0x000E03,\n    0x627267,\n    0x8D9D93,\n    0x97A69F,\n    0x97A69F,\n    0x97A6A1,\n    0x99A8A3,\n    0x9BAAA5,\n    0x9CABA6,\n    0x9CABA6,\n    0x9DACA7,\n    0x9FAEA9,\n    0xA1B0AB,\n    0xA5B4AF,\n    0xA5B4AF,\n    0xA5B4AF,\n    0xA4B3AE,\n    0xA3B2AD,\n    0xA4B3AE,\n    0xA7B6B1,\n    0xA9B8B1,\n    0xA7B7AC,\n    0xA7B7AA,\n    0xA6B6A9,\n    0xA5B5A8,\n    0xA4B4A7,\n    0xA6B6A9,\n    0xA9B9AC,\n    0xABBBAE,\n    0xABBCAC,\n    0xABBCAC,\n    0xABBCAC,\n    0xABBCAC,\n    0xABBCAC,\n    0xABBCAC,\n    0xABBCAC,\n    0xABBCAC,\n    0xAABBA8,\n    0xA8B9A6,\n    0xA8B9A6,\n    0xACBDAA,\n    0xADBEAB,\n    0xABBCA9,\n    0xA9BAA7,\n    0xA8B9A6,\n    0xADBEAB,\n    0xABBCA9,\n    0xA6B7A4,\n    0xA3B4A1,\n    0xA3B4A1,\n    0xA4B5A2,\n    0xA6B7A4,\n    0xA5B6A3,\n    0xA1B29F,\n    0xA3B4A1,\n    0xA0B19E,\n    0xA0B19E,\n    0xAABBA8,\n    0xB0C1AE,\n    0xACBDAA,\n    0xABBCA9,\n    0xA4B5A2,\n    0xABBCA9,\n    0xA8B9A6,\n    0xA2B3A0,\n    0xA5B6A3,\n    0xA6B7A4,\n    0xA3B4A1,\n    0xA3B4A1,\n    0xA0B19E,\n    0xA1B29F,\n    0xA2B3A0,\n    0xA3B4A1,\n    0xA3B4A1,\n    0xA2B3A0,\n    0xA0B19E,\n    0xA0B19E,\n    0x9FB09D,\n    0x9FB09D,\n    0x9FB09D,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9CAD9A,\n    0x9CAD9A,\n    0x9CAD9A,\n    0x9BAC99,\n    0x9BAC99,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x97A895,\n    0x96A794,\n    0x95A693,\n    0x93A492,\n    0x92A391,\n    0x91A290,\n    0x90A18F,\n    0x899A8A,\n    0x7F9080,\n    0x647565,\n    0x000E00,\n    0x000D00,\n    0x000C00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000D00,\n    0x000A00,\n    0x000F00,\n    0x000E03,\n    0x6D7D72,\n    0x8B9B91,\n    0x94A39C,\n    0x8F9E97,\n    0x97A6A1,\n    0x98A7A2,\n    0x99A8A3,\n    0x9CABA6,\n    0x9FAEA9,\n    0xA1B0AB,\n    0xA1B0AB,\n    0xA0AFAA,\n    0xA3B2AD,\n    0xA4B3AE,\n    0xA4B3AE,\n    0xA4B3AE,\n    0xA2B1AC,\n    0xA2B1AC,\n    0xA3B2AD,\n    0xA4B3AC,\n    0xA6B6A9,\n    0xA6B7A7,\n    0xA7B8A8,\n    0xA6B7A7,\n    0xA5B6A6,\n    0xA6B7A7,\n    0xA9BAAA,\n    0xABBCAC,\n    0xABBBAE,\n    0xABBBAE,\n    0xABBBAE,\n    0xABBBAE,\n    0xABBBAE,\n    0xABBBAE,\n    0xABBBAE,\n    0xABBCAC,\n    0xA9BAA8,\n    0xA8B9A6,\n    0xAABBA8,\n    0xADBEAB,\n    0xACBDAA,\n    0xA8B9A6,\n    0xA9BAA7,\n    0xACBDAA,\n    0xABBCA9,\n    0xAABBA8,\n    0xACBDAA,\n    0xAABBA8,\n    0xA9BAA7,\n    0xA9BAA7,\n    0xA7B8A5,\n    0xA9BAA7,\n    0xABBCA9,\n    0xA7B8A5,\n    0xA4B5A2,\n    0xA4B5A2,\n    0xA3B4A1,\n    0xA5B6A3,\n    0xA7B8A5,\n    0x9DAE9B,\n    0xA5B6A3,\n    0xA5B6A3,\n    0xA5B6A3,\n    0xA6B7A4,\n    0xA5B6A3,\n    0xA6B7A4,\n    0xA7B8A5,\n    0xA6B7A4,\n    0xA2B3A0,\n    0xA1B29F,\n    0xA1B29F,\n    0xA1B29F,\n    0xA1B29F,\n    0xA1B29F,\n    0xA1B29F,\n    0xA0B19E,\n    0x9FB09D,\n    0x9FB09D,\n    0x9FB09D,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9BAC99,\n    0x9BAC99,\n    0x9BAC99,\n    0x9BAC99,\n    0x9BAC99,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x97A895,\n    0x98A996,\n    0x98A996,\n    0x97A895,\n    0x96A794,\n    0x94A592,\n    0x93A492,\n    0x92A391,\n    0x90A18F,\n    0x92A391,\n    0x8A9B8B,\n    0x819282,\n    0x738474,\n    0x001000,\n    0x000D00,\n    0x000B00,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000900,\n    0x000800,\n    0x000800,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000A00,\n    0x000C00,\n    0x000900,\n    0x000F00,\n    0x001005,\n    0x748479,\n    0x87978D,\n    0x87968F,\n    0x798881,\n    0x83928D,\n    0x83928D,\n    0x84938E,\n    0x899893,\n    0x8E9D98,\n    0x909F9A,\n    0x8F9E99,\n    0x8D9C97,\n    0x8B9A95,\n    0x91A09B,\n    0x9BAAA5,\n    0xA3B2AD,\n    0xA7B6B1,\n    0xA8B7B2,\n    0xA7B6B1,\n    0xA7B6AF,\n    0xA5B5A8,\n    0xA6B7A7,\n    0xA7B8A8,\n    0xA7B8A8,\n    0xA6B7A7,\n    0xA7B8A8,\n    0xA9BAAA,\n    0xABBCAC,\n    0xABBBAE,\n    0xABBBAE,\n    0xABBBAE,\n    0xABBBAE,\n    0xABBBAE,\n    0xABBBAE,\n    0xABBBAE,\n    0xABBCAC,\n    0xA9BAA8,\n    0xA9BAA7,\n    0xACBDAA,\n    0xACBDAA,\n    0xA8B9A6,\n    0xA3B4A1,\n    0xA6B7A4,\n    0xADBEAB,\n    0xA3B4A1,\n    0xA1B29F,\n    0xA6B7A4,\n    0xA2B3A0,\n    0x9DAE9B,\n    0x9CAD9A,\n    0x98A996,\n    0x9EAF9C,\n    0xA4B5A2,\n    0xA0B19E,\n    0xA0B19E,\n    0xA4B5A2,\n    0x9EAF9C,\n    0xA2B3A0,\n    0xABBCA9,\n    0x9DAE9B,\n    0xABBCA9,\n    0xA2B3A0,\n    0xA4B5A2,\n    0xA9BAA7,\n    0xA4B5A2,\n    0xA0B19E,\n    0xA1B29F,\n    0xA2B3A0,\n    0xA4B5A2,\n    0xA3B4A1,\n    0xA0B19E,\n    0x9FB09D,\n    0xA0B19E,\n    0xA1B29F,\n    0xA1B29F,\n    0xA1B29F,\n    0x9FB09D,\n    0x9FB09D,\n    0x9FB09D,\n    0x9EAF9C,\n    0x9EAF9C,\n    0x9DAE9B,\n    0x9DAE9B,\n    0x9CAD9A,\n    0x9BAC99,\n    0x9BAC99,\n    0x9BAC99,\n    0x9BAC99,\n    0x9BAC99,\n    0x9BAC99,\n    0x9AAB98,\n    0x9AAB98,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x99AA97,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x98A996,\n    0x97A895,\n    0x98A996,\n    0x98A996,\n    0x97A895,\n    0x96A794,\n    0x94A592,\n    0x93A492,\n    0x92A391,\n    0x8FA08E,\n    0x92A391,\n    0x8C9D8D,\n    0x849585,\n    0x7D8E7E,\n    0x011202,\n    0x000D00,\n    0x000900\n};\n"
  },
  {
    "path": "esp_jpeg/test_apps/main/tjpgd_test.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include \"sdkconfig.h\"\n#include \"unity.h\"\n\n\n#include \"jpeg_decoder.h\"\n#include \"test_logo_jpg.h\"\n#include \"test_logo_rgb888.h\"\n#include \"test_usb_camera_2_jpg.h\"\n#include \"test_usb_camera_2_rgb888.h\"\n\n#define TESTW 46\n#define TESTH 46\n\nvoid esp_jpeg_print_ascii(unsigned char *rgb888, esp_jpeg_image_output_t *outimg)\n{\n    char aapix[] = \" .:;+=xX$$\";\n    unsigned char *p = rgb888 + 2;\n\n    for (int y = 0; y < outimg->width; y++) {\n        for (int x = 0; x < outimg->height; x++) {\n            int v = ((*p) * (sizeof(aapix) - 2) * 2) / 256;\n            printf(\"%c%c\", aapix[v / 2], aapix[(v + 1) / 2]);\n            p += 3;\n        }\n        printf(\"%c%c\", ' ', '\\n');\n    }\n}\n\nTEST_CASE(\"Test JPEG decompression library\", \"[esp_jpeg]\")\n{\n    unsigned char *decoded, *p;\n    const unsigned char *o;\n    int decoded_outsize = TESTW * TESTH * 3;\n\n    decoded = malloc(decoded_outsize);\n    for (int x = 0; x < decoded_outsize; x += 2) {\n        decoded[x] = 0;\n        decoded[x + 1] = 0xff;\n    }\n\n    /* JPEG decode */\n    esp_jpeg_image_cfg_t jpeg_cfg = {\n        .indata = (uint8_t *)logo_jpg,\n        .indata_size = logo_jpg_len,\n        .outbuf = decoded,\n        .outbuf_size = decoded_outsize,\n        .out_format = JPEG_IMAGE_FORMAT_RGB888,\n        .out_scale = JPEG_IMAGE_SCALE_0,\n        .flags = {\n            .swap_color_bytes = 0,\n        }\n    };\n    esp_jpeg_image_output_t outimg;\n    esp_err_t err = esp_jpeg_decode(&jpeg_cfg, &outimg);\n    TEST_ASSERT_EQUAL(err, ESP_OK);\n\n    /* Decoded image size */\n    TEST_ASSERT_EQUAL(outimg.width, TESTW);\n    TEST_ASSERT_EQUAL(outimg.height, TESTH);\n\n    p = decoded;\n    o = logo_rgb888;\n    for (int x = 0; x < outimg.width * outimg.height; x++) {\n        /* The color can be +- 2 */\n        TEST_ASSERT_UINT8_WITHIN(2, o[0], p[0]);\n        TEST_ASSERT_UINT8_WITHIN(2, o[1], p[1]);\n        TEST_ASSERT_UINT8_WITHIN(2, o[2], p[2]);\n\n        p += 3;\n        o += 3;\n    }\n\n    esp_jpeg_print_ascii(decoded, &outimg);\n\n    free(decoded);\n}\n\n/**\n * @brief JPEG unknown size test\n *\n * This test case verifies the functionality of the JPEG decompression library\n * when decoding an image with unknown size. The image is decoded from a\n * JPEG file, and the output size is determined dynamically. The test checks\n * that the decoded image dimensions match the expected values and that the\n * pixel data is within an acceptable tolerance range.\n */\nTEST_CASE(\"Test JPEG unknown size\", \"[esp_jpeg]\")\n{\n    unsigned char *decoded, *p;\n    const unsigned char *o;\n\n    /* JPEG decode */\n    esp_jpeg_image_cfg_t jpeg_cfg = {\n        .indata = (uint8_t *)logo_jpg,\n        .indata_size = logo_jpg_len,\n        .out_format = JPEG_IMAGE_FORMAT_RGB888,\n    };\n\n    // 1. Get required output size\n    esp_jpeg_image_output_t outimg;\n    esp_err_t err = esp_jpeg_get_image_info(&jpeg_cfg, &outimg);\n    TEST_ASSERT_EQUAL(err, ESP_OK);\n    TEST_ASSERT_EQUAL(TESTW * TESTH * 3, outimg.output_len);\n    TEST_ASSERT_EQUAL(outimg.width, TESTW);\n    TEST_ASSERT_EQUAL(outimg.height, TESTH);\n\n    // 2. Allocate output buffer and assign it to the config\n    decoded = malloc(outimg.output_len);\n    TEST_ASSERT_NOT_NULL(decoded);\n    jpeg_cfg.outbuf = decoded;\n    jpeg_cfg.outbuf_size = outimg.output_len;\n\n    // 3. Decode the image\n    err = esp_jpeg_decode(&jpeg_cfg, &outimg);\n    TEST_ASSERT_EQUAL(err, ESP_OK);\n\n    /* Decoded image size */\n    TEST_ASSERT_EQUAL(TESTW * TESTH * 3, outimg.output_len);\n    TEST_ASSERT_EQUAL(outimg.width, TESTW);\n    TEST_ASSERT_EQUAL(outimg.height, TESTH);\n\n    p = decoded;\n    o = logo_rgb888;\n    for (int x = 0; x < outimg.width * outimg.height; x++) {\n        /* The color can be +- 2 */\n        TEST_ASSERT_UINT8_WITHIN(2, o[0], p[0]);\n        TEST_ASSERT_UINT8_WITHIN(2, o[1], p[1]);\n        TEST_ASSERT_UINT8_WITHIN(2, o[2], p[2]);\n\n        p += 3;\n        o += 3;\n    }\n    free(decoded);\n}\n\n#define WORKING_BUFFER_SIZE 4096\nTEST_CASE(\"Test JPEG decompression library: User defined working buffer\", \"[esp_jpeg]\")\n{\n    unsigned char *decoded, *p;\n    const unsigned char *o;\n    int decoded_outsize = TESTW * TESTH * 3;\n\n    decoded = malloc(decoded_outsize);\n    uint8_t *working_buf = malloc(WORKING_BUFFER_SIZE);\n    assert(decoded);\n    assert(working_buf);\n\n    for (int x = 0; x < decoded_outsize; x += 2) {\n        decoded[x] = 0;\n        decoded[x + 1] = 0xff;\n    }\n\n    /* JPEG decode */\n    esp_jpeg_image_cfg_t jpeg_cfg = {\n        .indata = (uint8_t *)logo_jpg,\n        .indata_size = logo_jpg_len,\n        .outbuf = decoded,\n        .outbuf_size = decoded_outsize,\n        .out_format = JPEG_IMAGE_FORMAT_RGB888,\n        .out_scale = JPEG_IMAGE_SCALE_0,\n        .flags = {\n            .swap_color_bytes = 0,\n        },\n        .advanced = {\n            .working_buffer = working_buf,\n            .working_buffer_size = WORKING_BUFFER_SIZE,\n        },\n    };\n    esp_jpeg_image_output_t outimg;\n    esp_err_t err = esp_jpeg_decode(&jpeg_cfg, &outimg);\n    TEST_ASSERT_EQUAL(err, ESP_OK);\n\n    /* Decoded image size */\n    TEST_ASSERT_EQUAL(outimg.width, TESTW);\n    TEST_ASSERT_EQUAL(outimg.height, TESTH);\n\n    p = decoded;\n    o = logo_rgb888;\n    for (int x = 0; x < outimg.width * outimg.height; x++) {\n        /* The color can be +- 2 */\n        TEST_ASSERT_UINT8_WITHIN(2, o[0], p[0]);\n        TEST_ASSERT_UINT8_WITHIN(2, o[1], p[1]);\n        TEST_ASSERT_UINT8_WITHIN(2, o[2], p[2]);\n\n        p += 3;\n        o += 3;\n    }\n    free(working_buf);\n    free(decoded);\n}\n\n#if CONFIG_JD_DEFAULT_HUFFMAN\n#include \"test_usb_camera_jpg.h\"\n#include \"test_usb_camera_rgb888.h\"\n\n/**\n * @brief Test for JPEG decompression without Huffman tables\n *\n * This test case verifies the functionality of the JPEG decompression library\n * when decoding an image that lacks Huffman tables, such as a USB frame\n * from a Logitech C270 USB camera. The image was reconstructed from raw USB data\n * (using `hex_to_jpg.py`) and then converted into an RGB888 C-style array\n * (using `jpg_to_rgb888_hex.py`).\n *\n * Due to the unique structure of the JPEG data (double block size, 16x8 pixels)\n * and absence of Huffman tables, this test assesses whether the decompression\n * library correctly decodes the image and outputs RGB888 pixel data within\n * an acceptable tolerance range.\n *\n * The test performs the following steps:\n * - Allocates a buffer for the decoded image.\n * - Configures and runs the JPEG decoder with the RGB888 output format.\n * - Checks that the decoded image dimensions match expected values.\n * - Compares the decompressed image data against the reference RGB888 data,\n *   allowing a tolerance of ±16 in each color component due to potential\n *   differences in Huffman tables or decompression accuracy.\n *\n * @note This test allows a margin of error in pixel values due to potential\n *       differences in how color data is interpreted across different decoders.\n *\n * @param None\n *\n * @return None\n *\n * @test Requirements:\n * - JPEG decompression library support for images without Huffman tables.\n * - JPEG decompression accuracy within acceptable error margins.\n */\nTEST_CASE(\"Test JPEG decompression library: No Huffman tables\", \"[esp_jpeg]\")\n{\n    unsigned char *decoded, *p;\n    const unsigned int *o;\n    int decoded_outsize = 160 * 120 * 3;\n\n    decoded = malloc(decoded_outsize);\n\n    /* JPEG decode */\n    esp_jpeg_image_cfg_t jpeg_cfg = {\n        .indata = (uint8_t *)jpeg_no_huffman,\n        .indata_size = jpeg_no_huffman_len,\n        .outbuf = decoded,\n        .outbuf_size = decoded_outsize,\n        .out_format = JPEG_IMAGE_FORMAT_RGB888,\n        .out_scale = JPEG_IMAGE_SCALE_0,\n        .flags = {\n            .swap_color_bytes = 0,\n        }\n    };\n    esp_jpeg_image_output_t outimg;\n    esp_err_t err = esp_jpeg_decode(&jpeg_cfg, &outimg);\n    TEST_ASSERT_EQUAL(err, ESP_OK);\n\n    /* Decoded image size */\n    TEST_ASSERT_EQUAL(outimg.width, 160);\n    TEST_ASSERT_EQUAL(outimg.height, 120);\n\n    p = decoded;\n    o = jpeg_no_huffman_rgb888;\n    for (int x = 0; x < outimg.width * outimg.height; x++) {\n        /* The color can be +- 16 */\n        // Here we allow bigger decoding error\n        // It might be that the Windows decoder used slightly different Huffman tables\n        TEST_ASSERT_UINT8_WITHIN(16, (*o) & 0xff, p[0]);\n        TEST_ASSERT_UINT8_WITHIN(16, (*o >> 8) & 0xff, p[1]);\n        TEST_ASSERT_UINT8_WITHIN(16, (*o >> 16) & 0xff, p[2]);\n\n        p += 3; // this is uint8_t\n        o ++;   // this is unt32_t\n    }\n\n    free(decoded);\n}\n\n#endif\n\n/**\n * @brief Invalid JPEG marker test\n *\n * This test case verifies the behavior of the JPEG decompression library\n * when encountering an invalid marker (0xFFFF) in the JPEG data stream.\n * The test uses a known JPEG image (camera_2_jpg) that contains this invalid\n * marker. The test checks whether the library can handle the invalid marker\n * gracefully and still decode the image correctly.\n */\nTEST_CASE(\"Test JPEG invalid marker 0xFFFF\", \"[esp_jpeg]\")\n{\n    unsigned char *decoded;\n    int decoded_outsize = 160 * 120 * 3;\n\n    decoded = malloc(decoded_outsize);\n    assert(decoded);\n    for (int x = 0; x < decoded_outsize; x += 2) {\n        decoded[x] = 0;\n        decoded[x + 1] = 0xff;\n    }\n\n    /* JPEG decode */\n    esp_jpeg_image_cfg_t jpeg_cfg = {\n        .indata = (uint8_t *)camera_2_jpg,\n        .indata_size = camera_2_jpg_len,\n        .outbuf = decoded,\n        .outbuf_size = decoded_outsize,\n        .out_format = JPEG_IMAGE_FORMAT_RGB888,\n        .out_scale = JPEG_IMAGE_SCALE_0,\n        .flags = {\n            .swap_color_bytes = 0,\n        }\n    };\n    esp_jpeg_image_output_t outimg;\n    esp_err_t err = esp_jpeg_decode(&jpeg_cfg, &outimg);\n    TEST_ASSERT_EQUAL(ESP_OK, err);\n\n    /* Decoded image size */\n    TEST_ASSERT_EQUAL(160, outimg.width);\n    TEST_ASSERT_EQUAL(120, outimg.height);\n\n    free(decoded);\n}\n\n"
  },
  {
    "path": "esp_jpeg/test_apps/pytest_esp_jpeg.py",
    "content": "import pytest\n\n\n@pytest.mark.generic\ndef test_esp_jpeg(dut) -> None:\n    dut.run_all_single_board_cases()\n"
  },
  {
    "path": "esp_jpeg/test_apps/sdkconfig.ci",
    "content": "# This file was generated using idf.py save-defconfig. It can be edited manually.\n# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration\n#\nCONFIG_ESP_TASK_WDT_INIT=n\nCONFIG_JD_USE_ROM=n\nCONFIG_JD_DEFAULT_HUFFMAN=y\n"
  },
  {
    "path": "esp_jpeg/test_apps/sdkconfig.defaults",
    "content": "# This file was generated using idf.py save-defconfig. It can be edited manually.\n# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration\n#\nCONFIG_ESP_TASK_WDT_INIT=n\n"
  },
  {
    "path": "esp_jpeg/tjpgd/tjpgd.c",
    "content": "/*----------------------------------------------------------------------------/\n/ TJpgDec - Tiny JPEG Decompressor R0.03                      (C)ChaN, 2021\n/-----------------------------------------------------------------------------/\n/ The TJpgDec is a generic JPEG decompressor module for tiny embedded systems.\n/ This is a free software that opened for education, research and commercial\n/  developments under license policy of following terms.\n/\n/  Copyright (C) 2021, ChaN, all right reserved.\n/\n/ * The TJpgDec module is a free software and there is NO WARRANTY.\n/ * No restriction on use. You can use, modify and redistribute it for\n/   personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.\n/ * Redistributions of source code must retain the above copyright notice.\n/\n/-----------------------------------------------------------------------------/\n/ Oct 04, 2011 R0.01  First release.\n/ Feb 19, 2012 R0.01a Fixed decompression fails when scan starts with an escape seq.\n/ Sep 03, 2012 R0.01b Added JD_TBLCLIP option.\n/ Mar 16, 2019 R0.01c Supported stdint.h.\n/ Jul 01, 2020 R0.01d Fixed wrong integer type usage.\n/ May 08, 2021 R0.02  Supported grayscale image. Separated configuration options.\n/ Jun 11, 2021 R0.02a Some performance improvement.\n/ Jul 01, 2021 R0.03  Added JD_FASTDECODE option.\n/                     Some performance improvement.\n/----------------------------------------------------------------------------*/\n\n#include \"tjpgd.h\"\n\n\n#if JD_FASTDECODE == 2\n#define HUFF_BIT    10  /* Bit length to apply fast huffman decode */\n#define HUFF_LEN    (1 << HUFF_BIT)\n#define HUFF_MASK   (HUFF_LEN - 1)\n#endif\n\n\n/*-----------------------------------------------*/\n/* Zigzag-order to raster-order conversion table */\n/*-----------------------------------------------*/\n\nstatic const uint8_t Zig[64] = {    /* Zigzag-order to raster-order conversion table */\n    0,  1,  8, 16,  9,  2,  3, 10, 17, 24, 32, 25, 18, 11,  4,  5,\n    12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13,  6,  7, 14, 21, 28,\n    35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,\n    58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63\n};\n\n\n\n/*-------------------------------------------------*/\n/* Input scale factor of Arai algorithm            */\n/* (scaled up 16 bits for fixed point operations)  */\n/*-------------------------------------------------*/\n\nstatic const uint16_t Ipsf[64] = {  /* See also aa_idct.png */\n    (uint16_t)(1.00000 * 8192), (uint16_t)(1.38704 * 8192), (uint16_t)(1.30656 * 8192), (uint16_t)(1.17588 * 8192), (uint16_t)(1.00000 * 8192), (uint16_t)(0.78570 * 8192), (uint16_t)(0.54120 * 8192), (uint16_t)(0.27590 * 8192),\n    (uint16_t)(1.38704 * 8192), (uint16_t)(1.92388 * 8192), (uint16_t)(1.81226 * 8192), (uint16_t)(1.63099 * 8192), (uint16_t)(1.38704 * 8192), (uint16_t)(1.08979 * 8192), (uint16_t)(0.75066 * 8192), (uint16_t)(0.38268 * 8192),\n    (uint16_t)(1.30656 * 8192), (uint16_t)(1.81226 * 8192), (uint16_t)(1.70711 * 8192), (uint16_t)(1.53636 * 8192), (uint16_t)(1.30656 * 8192), (uint16_t)(1.02656 * 8192), (uint16_t)(0.70711 * 8192), (uint16_t)(0.36048 * 8192),\n    (uint16_t)(1.17588 * 8192), (uint16_t)(1.63099 * 8192), (uint16_t)(1.53636 * 8192), (uint16_t)(1.38268 * 8192), (uint16_t)(1.17588 * 8192), (uint16_t)(0.92388 * 8192), (uint16_t)(0.63638 * 8192), (uint16_t)(0.32442 * 8192),\n    (uint16_t)(1.00000 * 8192), (uint16_t)(1.38704 * 8192), (uint16_t)(1.30656 * 8192), (uint16_t)(1.17588 * 8192), (uint16_t)(1.00000 * 8192), (uint16_t)(0.78570 * 8192), (uint16_t)(0.54120 * 8192), (uint16_t)(0.27590 * 8192),\n    (uint16_t)(0.78570 * 8192), (uint16_t)(1.08979 * 8192), (uint16_t)(1.02656 * 8192), (uint16_t)(0.92388 * 8192), (uint16_t)(0.78570 * 8192), (uint16_t)(0.61732 * 8192), (uint16_t)(0.42522 * 8192), (uint16_t)(0.21677 * 8192),\n    (uint16_t)(0.54120 * 8192), (uint16_t)(0.75066 * 8192), (uint16_t)(0.70711 * 8192), (uint16_t)(0.63638 * 8192), (uint16_t)(0.54120 * 8192), (uint16_t)(0.42522 * 8192), (uint16_t)(0.29290 * 8192), (uint16_t)(0.14932 * 8192),\n    (uint16_t)(0.27590 * 8192), (uint16_t)(0.38268 * 8192), (uint16_t)(0.36048 * 8192), (uint16_t)(0.32442 * 8192), (uint16_t)(0.27590 * 8192), (uint16_t)(0.21678 * 8192), (uint16_t)(0.14932 * 8192), (uint16_t)(0.07612 * 8192)\n};\n\n\n\n/*---------------------------------------------*/\n/* Conversion table for fast clipping process  */\n/*---------------------------------------------*/\n\n#if JD_TBLCLIP\n\n#define BYTECLIP(v) Clip8[(unsigned int)(v) & 0x3FF]\n\nstatic const uint8_t Clip8[1024] = {\n    /* 0..255 */\n    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,\n    32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,\n    64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,\n    96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,\n    128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,\n    160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,\n    192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,\n    224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,\n    /* 256..511 */\n    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n    /* -512..-257 */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    /* -256..-1 */\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n};\n\n#else   /* JD_TBLCLIP */\n\nstatic uint8_t BYTECLIP (int val)\n{\n    if (val < 0) {\n        return 0;\n    }\n    if (val > 255) {\n        return 255;\n    }\n    return (uint8_t)val;\n}\n\n#endif\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Allocate a memory block from memory pool                              */\n/*-----------------------------------------------------------------------*/\n\nstatic void *alloc_pool (   /* Pointer to allocated memory block (NULL:no memory available) */\n    JDEC *jd,               /* Pointer to the decompressor object */\n    size_t ndata            /* Number of bytes to allocate */\n)\n{\n    char *rp = 0;\n\n\n    ndata = (ndata + 3) & ~3;           /* Align block size to the word boundary */\n\n    if (jd->sz_pool >= ndata) {\n        jd->sz_pool -= ndata;\n        rp = (char *)jd->pool;          /* Get start of available memory pool */\n        jd->pool = (void *)(rp + ndata); /* Allocate required bytes */\n    }\n\n    return (void *)rp;  /* Return allocated memory block (NULL:no memory to allocate) */\n}\n\n\n\n#if JD_DEFAULT_HUFFMAN\n/*-----------------------------------------------------------------------*/\n/* Load default Huffman table                                            */\n/*-----------------------------------------------------------------------*/\n\nextern unsigned char esp_jpeg_lum_dc_num_bits[], esp_jpeg_lum_dc_values[];\nextern unsigned char esp_jpeg_chrom_dc_num_bits[], esp_jpeg_chrom_dc_values[];\nextern unsigned char esp_jpeg_lum_ac_num_bits[], esp_jpeg_lum_ac_values[];\nextern unsigned char esp_jpeg_chrom_ac_num_bits[], esp_jpeg_chrom_ac_values[];\nextern unsigned esp_jpeg_lum_dc_codes_total, esp_jpeg_lum_ac_codes_total, esp_jpeg_chrom_dc_codes_total, esp_jpeg_chrom_ac_codes_total;\nJRESULT jd_load_default_huffman (JDEC *jd)\n{\n    // Variable declarations to keep a similar structure to create_huffman_tbl()\n    unsigned int i, j, b;\n    uint8_t *pb;\n    uint16_t hc, *ph;\n\n    // Group default tables for Y/CbCr channels and DC/AC components to access them in loops\n    // These arrays store predefined Huffman bit lengths and values for JPEG decoding\n    unsigned char *num_bits[2][2] = {\n        {esp_jpeg_lum_dc_num_bits, esp_jpeg_lum_ac_num_bits},   // Luminance (Y) DC and AC bit lengths\n        {esp_jpeg_chrom_dc_num_bits, esp_jpeg_chrom_ac_num_bits} // Chrominance (CbCr) DC and AC bit lengths\n    };\n    unsigned codes_total[2][2] = {\n        {esp_jpeg_lum_dc_codes_total, esp_jpeg_lum_ac_codes_total},   // Total codes for Y DC and AC components\n        {esp_jpeg_chrom_dc_codes_total, esp_jpeg_chrom_ac_codes_total} // Total codes for CbCr DC and AC components\n    };\n    unsigned char *values[2][2] = {\n        {esp_jpeg_lum_dc_values, esp_jpeg_lum_ac_values},   // Default Huffman values for Y DC and AC components\n        {esp_jpeg_chrom_dc_values, esp_jpeg_chrom_ac_values} // Default Huffman values for CbCr DC and AC components\n    };\n\n    // Loop over Y/CbCr channels and DC/AC components to initialize Huffman tables\n    for (int ycbcr = 0; ycbcr < 2; ycbcr++) { // Loop for Luminance (Y) and Chrominance (CbCr)\n        for (int dcac = 0; dcac < 2; dcac++) { // Loop for DC and AC tables\n            // Assign the bit lengths and values arrays to Huffman table fields in the JDEC structure\n            jd->huffbits[ycbcr][dcac] = num_bits[ycbcr][dcac];\n            jd->huffdata[ycbcr][dcac] = values[ycbcr][dcac];\n\n            // Calculate Huffman codes from bit lengths to construct codeword tables\n            pb = num_bits[ycbcr][dcac]; // Access bit length array\n            size_t np = codes_total[ycbcr][dcac]; // Total number of codes\n\n            // The bits and values are usually in the Huffman table of the JPEG picture.\n            // The codes themselves must be calculated based on the bits and values; that is what we do here.\n            // Since this function uses default bits and values that are constant and known at compile time,\n            // We could optimize this even more by providing pre-calculated codes too...\n\n            // Allocate memory for the Huffman codeword table\n            ph = alloc_pool(jd, np * sizeof(uint16_t));\n            if (!ph) {\n                return JDR_MEM1;    // Error: Memory allocation failed\n            }\n            jd->huffcode[ycbcr][dcac] = ph; // Store allocated memory address for code table\n            hc = 0; // Initialize Huffman code\n\n            // Generate Huffman codes based on the bit lengths in pb\n            for (j = i = 0; i < 16; i++) { // Iterate over 16 possible code lengths\n                b = pb[i]; // Number of codes with length (i+1) bits\n                while (b--) {\n                    ph[j++] = hc++; // Assign code and increment index\n                }\n                hc <<= 1; // Left shift code to increase bit length\n            }\n        }\n    }\n    return JDR_OK; // Return success status\n}\n#endif\n\n/*-----------------------------------------------------------------------*/\n/* Create de-quantization and prescaling tables with a DQT segment       */\n/*-----------------------------------------------------------------------*/\n\nstatic JRESULT create_qt_tbl (  /* 0:OK, !0:Failed */\n    JDEC *jd,               /* Pointer to the decompressor object */\n    const uint8_t *data,    /* Pointer to the quantizer tables */\n    size_t ndata            /* Size of input data */\n)\n{\n    unsigned int i, zi;\n    uint8_t d;\n    int32_t *pb;\n\n\n    while (ndata) { /* Process all tables in the segment */\n        if (ndata < 65) {\n            return JDR_FMT1;    /* Err: table size is unaligned */\n        }\n        ndata -= 65;\n        d = *data++;                            /* Get table property */\n        if (d & 0xF0) {\n            return JDR_FMT1;    /* Err: not 8-bit resolution */\n        }\n        i = d & 3;                              /* Get table ID */\n        pb = alloc_pool(jd, 64 * sizeof (int32_t));/* Allocate a memory block for the table */\n        if (!pb) {\n            return JDR_MEM1;    /* Err: not enough memory */\n        }\n        jd->qttbl[i] = pb;                      /* Register the table */\n        for (i = 0; i < 64; i++) {              /* Load the table */\n            zi = Zig[i];                        /* Zigzag-order to raster-order conversion */\n            pb[zi] = (int32_t)((uint32_t) * data++ * Ipsf[zi]); /* Apply scale factor of Arai algorithm to the de-quantizers */\n        }\n    }\n\n    return JDR_OK;\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Create huffman code tables with a DHT segment                         */\n/*-----------------------------------------------------------------------*/\n\nstatic JRESULT create_huffman_tbl ( /* 0:OK, !0:Failed */\n    JDEC *jd,                   /* Pointer to the decompressor object */\n    const uint8_t *data,        /* Pointer to the packed huffman tables */\n    size_t ndata                /* Size of input data */\n)\n{\n    unsigned int i, j, b, cls, num;\n    size_t np;\n    uint8_t d, *pb, *pd;\n    uint16_t hc, *ph;\n\n\n    while (ndata) { /* Process all tables in the segment */\n        if (ndata < 17) {\n            return JDR_FMT1;    /* Err: wrong data size */\n        }\n        ndata -= 17;\n        d = *data++;                        /* Get table number and class */\n        if (d & 0xEE) {\n            return JDR_FMT1;    /* Err: invalid class/number */\n        }\n        cls = d >> 4; num = d & 0x0F;       /* class = dc(0)/ac(1), table number = 0/1 */\n        pb = alloc_pool(jd, 16);            /* Allocate a memory block for the bit distribution table */\n        if (!pb) {\n            return JDR_MEM1;    /* Err: not enough memory */\n        }\n        jd->huffbits[num][cls] = pb;\n        for (np = i = 0; i < 16; i++) {     /* Load number of patterns for 1 to 16-bit code */\n            np += (pb[i] = *data++);        /* Get sum of code words for each code */\n        }\n        ph = alloc_pool(jd, np * sizeof (uint16_t));/* Allocate a memory block for the code word table */\n        if (!ph) {\n            return JDR_MEM1;    /* Err: not enough memory */\n        }\n        jd->huffcode[num][cls] = ph;\n        hc = 0;\n        for (j = i = 0; i < 16; i++) {      /* Re-build huffman code word table */\n            b = pb[i];\n            while (b--) {\n                ph[j++] = hc++;\n            }\n            hc <<= 1;\n        }\n\n        if (ndata < np) {\n            return JDR_FMT1;    /* Err: wrong data size */\n        }\n        ndata -= np;\n        pd = alloc_pool(jd, np);            /* Allocate a memory block for the decoded data */\n        if (!pd) {\n            return JDR_MEM1;    /* Err: not enough memory */\n        }\n        jd->huffdata[num][cls] = pd;\n        for (i = 0; i < np; i++) {          /* Load decoded data corresponds to each code word */\n            d = *data++;\n            if (!cls && d > 11) {\n                return JDR_FMT1;\n            }\n            pd[i] = d;\n        }\n#if JD_FASTDECODE == 2\n        { /* Create fast huffman decode table */\n            unsigned int span, td, ti;\n            uint16_t *tbl_ac = 0;\n            uint8_t *tbl_dc = 0;\n\n            if (cls) {\n                tbl_ac = alloc_pool(jd, HUFF_LEN * sizeof (uint16_t));  /* LUT for AC elements */\n                if (!tbl_ac) {\n                    return JDR_MEM1;    /* Err: not enough memory */\n                }\n                jd->hufflut_ac[num] = tbl_ac;\n                memset(tbl_ac, 0xFF, HUFF_LEN * sizeof (uint16_t));     /* Default value (0xFFFF: may be long code) */\n            } else {\n                tbl_dc = alloc_pool(jd, HUFF_LEN * sizeof (uint8_t));   /* LUT for AC elements */\n                if (!tbl_dc) {\n                    return JDR_MEM1;    /* Err: not enough memory */\n                }\n                jd->hufflut_dc[num] = tbl_dc;\n                memset(tbl_dc, 0xFF, HUFF_LEN * sizeof (uint8_t));      /* Default value (0xFF: may be long code) */\n            }\n            for (i = b = 0; b < HUFF_BIT; b++) {    /* Create LUT */\n                for (j = pb[b]; j; j--) {\n                    ti = ph[i] << (HUFF_BIT - 1 - b) & HUFF_MASK;   /* Index of input pattern for the code */\n                    if (cls) {\n                        td = pd[i++] | ((b + 1) << 8);  /* b15..b8: code length, b7..b0: zero run and data length */\n                        for (span = 1 << (HUFF_BIT - 1 - b); span; span--, tbl_ac[ti++] = (uint16_t)td) ;\n                    } else {\n                        td = pd[i++] | ((b + 1) << 4);  /* b7..b4: code length, b3..b0: data length */\n                        for (span = 1 << (HUFF_BIT - 1 - b); span; span--, tbl_dc[ti++] = (uint8_t)td) ;\n                    }\n                }\n            }\n            jd->longofs[num][cls] = i;  /* Code table offset for long code */\n        }\n#endif\n    }\n\n    return JDR_OK;\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Extract a huffman decoded data from input stream                      */\n/*-----------------------------------------------------------------------*/\n\nstatic int huffext (    /* >=0: decoded data, <0: error code */\n    JDEC *jd,           /* Pointer to the decompressor object */\n    unsigned int id,    /* Table ID (0:Y, 1:C) */\n    unsigned int cls    /* Table class (0:DC, 1:AC) */\n)\n{\n    size_t dc = jd->dctr;\n    uint8_t *dp = jd->dptr;\n    unsigned int d, flg = 0;\n\n#if JD_FASTDECODE == 0\n    uint8_t bm, nd, bl;\n    const uint8_t *hb = jd->huffbits[id][cls];  /* Bit distribution table */\n    const uint16_t *hc = jd->huffcode[id][cls]; /* Code word table */\n    const uint8_t *hd = jd->huffdata[id][cls];  /* Data table */\n\n\n    bm = jd->dbit;  /* Bit mask to extract */\n    d = 0; bl = 16; /* Max code length */\n    do {\n        if (!bm) {      /* Next byte? */\n            if (!dc) {  /* No input data is available, re-fill input buffer */\n                dp = jd->inbuf; /* Top of input buffer */\n                dc = jd->infunc(jd, dp, JD_SZBUF);\n                if (!dc) {\n                    return 0 - (int)JDR_INP;    /* Err: read error or wrong stream termination */\n                }\n            } else {\n                dp++;   /* Next data ptr */\n            }\n            dc--;       /* Decrement number of available bytes */\n            if (flg) {      /* In flag sequence? */\n                flg = 0;    /* Exit flag sequence */\n                if (*dp != 0) {\n                    return 0 - (int)JDR_FMT1;    /* Err: unexpected flag is detected (may be corrupted data) */\n                }\n                *dp = 0xFF;             /* The flag is a data 0xFF */\n            } else {\n                if (*dp == 0xFF) {      /* Is start of flag sequence? */\n                    flg = 1; continue;  /* Enter flag sequence, get trailing byte */\n                }\n            }\n            bm = 0x80;      /* Read from MSB */\n        }\n        d <<= 1;            /* Get a bit */\n        if (*dp & bm) {\n            d++;\n        }\n        bm >>= 1;\n\n        for (nd = *hb++; nd; nd--) {    /* Search the code word in this bit length */\n            if (d == *hc++) {   /* Matched? */\n                jd->dbit = bm; jd->dctr = dc; jd->dptr = dp;\n                return *hd;     /* Return the decoded data */\n            }\n            hd++;\n        }\n        bl--;\n    } while (bl);\n\n#else\n    const uint8_t *hb, *hd;\n    const uint16_t *hc;\n    unsigned int nc, bl, wbit = jd->dbit % 32;\n    uint32_t w = jd->wreg & ((1UL << wbit) - 1);\n\n\n    while (wbit < 16) { /* Prepare 16 bits into the working register */\n        if (jd->marker) {\n            d = 0xFF;   /* Input stream has stalled for a marker. Generate stuff bits */\n        } else {\n            if (!dc) {  /* Buffer empty, re-fill input buffer */\n                dp = jd->inbuf;                     /* Top of input buffer */\n                dc = jd->infunc(jd, dp, JD_SZBUF);\n                if (!dc) {\n                    return 0 - (int)JDR_INP;    /* Err: read error or wrong stream termination */\n                }\n            }\n            d = *dp++; dc--;\n            if (flg) {      /* In flag sequence? */\n                flg = 0;    /* Exit flag sequence */\n                if (d != 0) {\n                    jd->marker = d;    /* Not an escape of 0xFF but a marker */\n                }\n                d = 0xFF;\n            } else {\n                if (d == 0xFF) {        /* Is start of flag sequence? */\n                    flg = 1; continue;  /* Enter flag sequence, get trailing byte */\n                }\n            }\n        }\n        w = w << 8 | d; /* Shift 8 bits in the working register */\n        wbit += 8;\n    }\n    jd->dctr = dc; jd->dptr = dp;\n    jd->wreg = w;\n\n#if JD_FASTDECODE == 2\n    /* Table search for the short codes */\n    d = (unsigned int)(w >> (wbit - HUFF_BIT)); /* Short code as table index */\n    if (cls) {  /* AC element */\n        d = jd->hufflut_ac[id][d];  /* Table decode */\n        if (d != 0xFFFF) {  /* It is done if hit in short code */\n            jd->dbit = wbit - (d >> 8); /* Snip the code length */\n            return d & 0xFF;    /* b7..0: zero run and following data bits */\n        }\n    } else {    /* DC element */\n        d = jd->hufflut_dc[id][d];  /* Table decode */\n        if (d != 0xFF) {    /* It is done if hit in short code */\n            jd->dbit = wbit - (d >> 4); /* Snip the code length  */\n            return d & 0xF; /* b3..0: following data bits */\n        }\n    }\n\n    /* Incremental search for the codes longer than HUFF_BIT */\n    hb = jd->huffbits[id][cls] + HUFF_BIT;              /* Bit distribution table */\n    hc = jd->huffcode[id][cls] + jd->longofs[id][cls];  /* Code word table */\n    hd = jd->huffdata[id][cls] + jd->longofs[id][cls];  /* Data table */\n    bl = HUFF_BIT + 1;\n#else\n    /* Incremental search for all codes */\n    hb = jd->huffbits[id][cls]; /* Bit distribution table */\n    hc = jd->huffcode[id][cls]; /* Code word table */\n    hd = jd->huffdata[id][cls]; /* Data table */\n    bl = 1;\n#endif\n    for ( ; bl <= 16; bl++) {   /* Incremental search */\n        nc = *hb++;\n        if (nc) {\n            d = w >> (wbit - bl);\n            do {    /* Search the code word in this bit length */\n                if (d == *hc++) {       /* Matched? */\n                    jd->dbit = wbit - bl;   /* Snip the huffman code */\n                    return *hd;         /* Return the decoded data */\n                }\n                hd++;\n            } while (--nc);\n        }\n    }\n#endif\n\n    return 0 - (int)JDR_FMT1;   /* Err: code not found (may be corrupted data) */\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Extract N bits from input stream                                      */\n/*-----------------------------------------------------------------------*/\n\nstatic int bitext ( /* >=0: extracted data, <0: error code */\n    JDEC *jd,           /* Pointer to the decompressor object */\n    unsigned int nbit   /* Number of bits to extract (1 to 16) */\n)\n{\n    size_t dc = jd->dctr;\n    uint8_t *dp = jd->dptr;\n    unsigned int d, flg = 0;\n\n#if JD_FASTDECODE == 0\n    uint8_t mbit = jd->dbit;\n\n    d = 0;\n    do {\n        if (!mbit) {            /* Next byte? */\n            if (!dc) {          /* No input data is available, re-fill input buffer */\n                dp = jd->inbuf; /* Top of input buffer */\n                dc = jd->infunc(jd, dp, JD_SZBUF);\n                if (!dc) {\n                    return 0 - (int)JDR_INP;    /* Err: read error or wrong stream termination */\n                }\n            } else {\n                dp++;           /* Next data ptr */\n            }\n            dc--;               /* Decrement number of available bytes */\n            if (flg) {          /* In flag sequence? */\n                flg = 0;        /* Exit flag sequence */\n                if (*dp != 0) {\n                    return 0 - (int)JDR_FMT1;    /* Err: unexpected flag is detected (may be corrupted data) */\n                }\n                *dp = 0xFF;     /* The flag is a data 0xFF */\n            } else {\n                if (*dp == 0xFF) {      /* Is start of flag sequence? */\n                    flg = 1; continue;  /* Enter flag sequence */\n                }\n            }\n            mbit = 0x80;        /* Read from MSB */\n        }\n        d <<= 1;    /* Get a bit */\n        if (*dp & mbit) {\n            d |= 1;\n        }\n        mbit >>= 1;\n        nbit--;\n    } while (nbit);\n\n    jd->dbit = mbit; jd->dctr = dc; jd->dptr = dp;\n    return (int)d;\n\n#else\n    unsigned int wbit = jd->dbit % 32;\n    uint32_t w = jd->wreg & ((1UL << wbit) - 1);\n\n\n    while (wbit < nbit) {   /* Prepare nbit bits into the working register */\n        if (jd->marker) {\n            d = 0xFF;   /* Input stream stalled, generate stuff bits */\n        } else {\n            if (!dc) {  /* Buffer empty, re-fill input buffer */\n                dp = jd->inbuf; /* Top of input buffer */\n                dc = jd->infunc(jd, dp, JD_SZBUF);\n                if (!dc) {\n                    return 0 - (int)JDR_INP;    /* Err: read error or wrong stream termination */\n                }\n            }\n            d = *dp++; dc--;\n            if (flg) {      /* In flag sequence? */\n                flg = 0;    /* Exit flag sequence */\n                if (d != 0) {\n                    jd->marker = d;    /* Not an escape of 0xFF but a marker */\n                }\n                d = 0xFF;\n            } else {\n                if (d == 0xFF) {        /* Is start of flag sequence? */\n                    flg = 1; continue;  /* Enter flag sequence, get trailing byte */\n                }\n            }\n        }\n        w = w << 8 | d; /* Get 8 bits into the working register */\n        wbit += 8;\n    }\n    jd->wreg = w; jd->dbit = wbit - nbit;\n    jd->dctr = dc; jd->dptr = dp;\n\n    return (int)(w >> ((wbit - nbit) % 32));\n#endif\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Process restart interval                                              */\n/*-----------------------------------------------------------------------*/\n\nstatic JRESULT restart (\n    JDEC *jd,       /* Pointer to the decompressor object */\n    uint16_t rstn   /* Expected restert sequence number */\n)\n{\n    unsigned int i;\n    uint8_t *dp = jd->dptr;\n    size_t dc = jd->dctr;\n\n#if JD_FASTDECODE == 0\n    uint16_t d = 0;\n\n    /* Get two bytes from the input stream */\n    for (i = 0; i < 2; i++) {\n        if (!dc) {  /* No input data is available, re-fill input buffer */\n            dp = jd->inbuf;\n            dc = jd->infunc(jd, dp, JD_SZBUF);\n            if (!dc) {\n                return JDR_INP;\n            }\n        } else {\n            dp++;\n        }\n        dc--;\n        d = d << 8 | *dp;   /* Get a byte */\n    }\n    jd->dptr = dp; jd->dctr = dc; jd->dbit = 0;\n\n    /* Check the marker */\n    if ((d & 0xFFD8) != 0xFFD0 || (d & 7) != (rstn & 7)) {\n        return JDR_FMT1;    /* Err: expected RSTn marker is not detected (may be corrupted data) */\n    }\n\n#else\n    uint16_t marker;\n\n\n    if (jd->marker) {   /* Generate a maker if it has been detected */\n        marker = 0xFF00 | jd->marker;\n        jd->marker = 0;\n    } else {\n        marker = 0;\n        for (i = 0; i < 2; i++) {   /* Get a restart marker */\n            if (!dc) {      /* No input data is available, re-fill input buffer */\n                dp = jd->inbuf;\n                dc = jd->infunc(jd, dp, JD_SZBUF);\n                if (!dc) {\n                    return JDR_INP;\n                }\n            }\n            marker = (marker << 8) | *dp++; /* Get a byte */\n            dc--;\n        }\n        jd->dptr = dp; jd->dctr = dc;\n    }\n\n    /* Check the marker */\n    if ((marker & 0xFFD8) != 0xFFD0 || (marker & 7) != (rstn & 7)) {\n        return JDR_FMT1;    /* Err: expected RSTn marker was not detected (may be corrupted data) */\n    }\n\n    jd->dbit = 0;           /* Discard stuff bits */\n#endif\n\n    jd->dcv[2] = jd->dcv[1] = jd->dcv[0] = 0;   /* Reset DC offset */\n    return JDR_OK;\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Apply Inverse-DCT in Arai Algorithm (see also aa_idct.png)            */\n/*-----------------------------------------------------------------------*/\n\nstatic void block_idct (\n    int32_t *src,   /* Input block data (de-quantized and pre-scaled for Arai Algorithm) */\n    jd_yuv_t *dst   /* Pointer to the destination to store the block as byte array */\n)\n{\n    const int32_t M13 = (int32_t)(1.41421 * 4096), M2 = (int32_t)(1.08239 * 4096), M4 = (int32_t)(2.61313 * 4096), M5 = (int32_t)(1.84776 * 4096);\n    int32_t v0, v1, v2, v3, v4, v5, v6, v7;\n    int32_t t10, t11, t12, t13;\n    int i;\n\n    /* Process columns */\n    for (i = 0; i < 8; i++) {\n        v0 = src[8 * 0];    /* Get even elements */\n        v1 = src[8 * 2];\n        v2 = src[8 * 4];\n        v3 = src[8 * 6];\n\n        t10 = v0 + v2;      /* Process the even elements */\n        t12 = v0 - v2;\n        t11 = (v1 - v3) * M13 >> 12;\n        v3 += v1;\n        t11 -= v3;\n        v0 = t10 + v3;\n        v3 = t10 - v3;\n        v1 = t11 + t12;\n        v2 = t12 - t11;\n\n        v4 = src[8 * 7];    /* Get odd elements */\n        v5 = src[8 * 1];\n        v6 = src[8 * 5];\n        v7 = src[8 * 3];\n\n        t10 = v5 - v4;      /* Process the odd elements */\n        t11 = v5 + v4;\n        t12 = v6 - v7;\n        v7 += v6;\n        v5 = (t11 - v7) * M13 >> 12;\n        v7 += t11;\n        t13 = (t10 + t12) * M5 >> 12;\n        v4 = t13 - (t10 * M2 >> 12);\n        v6 = t13 - (t12 * M4 >> 12) - v7;\n        v5 -= v6;\n        v4 -= v5;\n\n        src[8 * 0] = v0 + v7;   /* Write-back transformed values */\n        src[8 * 7] = v0 - v7;\n        src[8 * 1] = v1 + v6;\n        src[8 * 6] = v1 - v6;\n        src[8 * 2] = v2 + v5;\n        src[8 * 5] = v2 - v5;\n        src[8 * 3] = v3 + v4;\n        src[8 * 4] = v3 - v4;\n\n        src++;  /* Next column */\n    }\n\n    /* Process rows */\n    src -= 8;\n    for (i = 0; i < 8; i++) {\n        v0 = src[0] + (128L << 8);  /* Get even elements (remove DC offset (-128) here) */\n        v1 = src[2];\n        v2 = src[4];\n        v3 = src[6];\n\n        t10 = v0 + v2;              /* Process the even elements */\n        t12 = v0 - v2;\n        t11 = (v1 - v3) * M13 >> 12;\n        v3 += v1;\n        t11 -= v3;\n        v0 = t10 + v3;\n        v3 = t10 - v3;\n        v1 = t11 + t12;\n        v2 = t12 - t11;\n\n        v4 = src[7];                /* Get odd elements */\n        v5 = src[1];\n        v6 = src[5];\n        v7 = src[3];\n\n        t10 = v5 - v4;              /* Process the odd elements */\n        t11 = v5 + v4;\n        t12 = v6 - v7;\n        v7 += v6;\n        v5 = (t11 - v7) * M13 >> 12;\n        v7 += t11;\n        t13 = (t10 + t12) * M5 >> 12;\n        v4 = t13 - (t10 * M2 >> 12);\n        v6 = t13 - (t12 * M4 >> 12) - v7;\n        v5 -= v6;\n        v4 -= v5;\n\n        /* Descale the transformed values 8 bits and output a row */\n#if JD_FASTDECODE >= 1\n        dst[0] = (int16_t)((v0 + v7) >> 8);\n        dst[7] = (int16_t)((v0 - v7) >> 8);\n        dst[1] = (int16_t)((v1 + v6) >> 8);\n        dst[6] = (int16_t)((v1 - v6) >> 8);\n        dst[2] = (int16_t)((v2 + v5) >> 8);\n        dst[5] = (int16_t)((v2 - v5) >> 8);\n        dst[3] = (int16_t)((v3 + v4) >> 8);\n        dst[4] = (int16_t)((v3 - v4) >> 8);\n#else\n        dst[0] = BYTECLIP((v0 + v7) >> 8);\n        dst[7] = BYTECLIP((v0 - v7) >> 8);\n        dst[1] = BYTECLIP((v1 + v6) >> 8);\n        dst[6] = BYTECLIP((v1 - v6) >> 8);\n        dst[2] = BYTECLIP((v2 + v5) >> 8);\n        dst[5] = BYTECLIP((v2 - v5) >> 8);\n        dst[3] = BYTECLIP((v3 + v4) >> 8);\n        dst[4] = BYTECLIP((v3 - v4) >> 8);\n#endif\n\n        dst += 8; src += 8; /* Next row */\n    }\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Load all blocks in an MCU into working buffer                         */\n/*-----------------------------------------------------------------------*/\n\nstatic JRESULT mcu_load (\n    JDEC *jd        /* Pointer to the decompressor object */\n)\n{\n    int32_t *tmp = (int32_t *)jd->workbuf;  /* Block working buffer for de-quantize and IDCT */\n    int d, e;\n    unsigned int blk, nby, i, bc, z, id, cmp;\n    jd_yuv_t *bp;\n    const int32_t *dqf;\n\n\n    nby = jd->msx * jd->msy;    /* Number of Y blocks (1, 2 or 4) */\n    bp = jd->mcubuf;            /* Pointer to the first block of MCU */\n\n    for (blk = 0; blk < nby + 2; blk++) {   /* Get nby Y blocks and two C blocks */\n        cmp = (blk < nby) ? 0 : blk - nby + 1;  /* Component number 0:Y, 1:Cb, 2:Cr */\n\n        if (cmp && jd->ncomp != 3) {        /* Clear C blocks if not exist (monochrome image) */\n            for (i = 0; i < 64; bp[i++] = 128) ;\n\n        } else {                            /* Load Y/C blocks from input stream */\n            id = cmp ? 1 : 0;                       /* Huffman table ID of this component */\n\n            /* Extract a DC element from input stream */\n            d = huffext(jd, id, 0);                 /* Extract a huffman coded data (bit length) */\n            if (d < 0) {\n                return (JRESULT)(0 - d);    /* Err: invalid code or input */\n            }\n            bc = (unsigned int)d;\n            d = jd->dcv[cmp];                       /* DC value of previous block */\n            if (bc) {                               /* If there is any difference from previous block */\n                e = bitext(jd, bc);                 /* Extract data bits */\n                if (e < 0) {\n                    return (JRESULT)(0 - e);    /* Err: input */\n                }\n                bc = 1 << (bc - 1);                 /* MSB position */\n                if (!(e & bc)) {\n                    e -= (bc << 1) - 1;    /* Restore negative value if needed */\n                }\n                d += e;                             /* Get current value */\n                jd->dcv[cmp] = (int16_t)d;          /* Save current DC value for next block */\n            }\n            dqf = jd->qttbl[jd->qtid[cmp]];         /* De-quantizer table ID for this component */\n            tmp[0] = d * dqf[0] >> 8;               /* De-quantize, apply scale factor of Arai algorithm and descale 8 bits */\n\n            /* Extract following 63 AC elements from input stream */\n            memset(&tmp[1], 0, 63 * sizeof (int32_t));  /* Initialize all AC elements */\n            z = 1;      /* Top of the AC elements (in zigzag-order) */\n            do {\n                d = huffext(jd, id, 1);             /* Extract a huffman coded value (zero runs and bit length) */\n                if (d == 0) {\n                    break;    /* EOB? */\n                }\n                if (d < 0) {\n                    return (JRESULT)(0 - d);    /* Err: invalid code or input error */\n                }\n                bc = (unsigned int)d;\n                z += bc >> 4;                       /* Skip leading zero run */\n                if (z >= 64) {\n                    return JDR_FMT1;    /* Too long zero run */\n                }\n                if (bc &= 0x0F) {                   /* Bit length? */\n                    d = bitext(jd, bc);             /* Extract data bits */\n                    if (d < 0) {\n                        return (JRESULT)(0 - d);    /* Err: input device */\n                    }\n                    bc = 1 << (bc - 1);             /* MSB position */\n                    if (!(d & bc)) {\n                        d -= (bc << 1) - 1;    /* Restore negative value if needed */\n                    }\n                    i = Zig[z];                     /* Get raster-order index */\n                    tmp[i] = d * dqf[i] >> 8;       /* De-quantize, apply scale factor of Arai algorithm and descale 8 bits */\n                }\n            } while (++z < 64);     /* Next AC element */\n\n            if (JD_FORMAT != 2 || !cmp) {   /* C components may not be processed if in grayscale output */\n                if (z == 1 || (JD_USE_SCALE && jd->scale == 3)) {   /* If no AC element or scale ratio is 1/8, IDCT can be omitted and the block is filled with DC value */\n                    d = (jd_yuv_t)((*tmp / 256) + 128);\n                    if (JD_FASTDECODE >= 1) {\n                        for (i = 0; i < 64; bp[i++] = d) ;\n                    } else {\n                        memset(bp, d, 64);\n                    }\n                } else {\n                    block_idct(tmp, bp);    /* Apply IDCT and store the block to the MCU buffer */\n                }\n            }\n        }\n\n        bp += 64;               /* Next block */\n    }\n\n    return JDR_OK;  /* All blocks have been loaded successfully */\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Output an MCU: Convert YCrCb to RGB and output it in RGB form         */\n/*-----------------------------------------------------------------------*/\n\nstatic JRESULT mcu_output (\n    JDEC *jd,           /* Pointer to the decompressor object */\n    int (*outfunc)(JDEC *, void *, JRECT *), /* RGB output function */\n    unsigned int x,     /* MCU location in the image */\n    unsigned int y      /* MCU location in the image */\n)\n{\n    const int CVACC = (sizeof (int) > 2) ? 1024 : 128;  /* Adaptive accuracy for both 16-/32-bit systems */\n    unsigned int ix, iy, mx, my, rx, ry;\n    int yy, cb, cr;\n    jd_yuv_t *py, *pc;\n    uint8_t *pix;\n    JRECT rect;\n\n\n    mx = jd->msx * 8; my = jd->msy * 8;                 /* MCU size (pixel) */\n    rx = (x + mx <= jd->width) ? mx : jd->width - x;    /* Output rectangular size (it may be clipped at right/bottom end of image) */\n    ry = (y + my <= jd->height) ? my : jd->height - y;\n    if (JD_USE_SCALE) {\n        rx >>= jd->scale; ry >>= jd->scale;\n        if (!rx || !ry) {\n            return JDR_OK;    /* Skip this MCU if all pixel is to be rounded off */\n        }\n        x >>= jd->scale; y >>= jd->scale;\n    }\n    rect.left = x; rect.right = x + rx - 1;             /* Rectangular area in the frame buffer */\n    rect.top = y; rect.bottom = y + ry - 1;\n\n\n    if (!JD_USE_SCALE || jd->scale != 3) {  /* Not for 1/8 scaling */\n        pix = (uint8_t *)jd->workbuf;\n\n        if (JD_FORMAT != 2) {   /* RGB output (build an RGB MCU from Y/C component) */\n            for (iy = 0; iy < my; iy++) {\n                pc = py = jd->mcubuf;\n                if (my == 16) {     /* Double block height? */\n                    pc += 64 * 4 + (iy >> 1) * 8;\n                    if (iy >= 8) {\n                        py += 64;\n                    }\n                } else {            /* Single block height */\n                    pc += mx * 8 + iy * 8;\n                }\n                py += iy * 8;\n                for (ix = 0; ix < mx; ix++) {\n                    cb = pc[0] - 128;   /* Get Cb/Cr component and remove offset */\n                    cr = pc[64] - 128;\n                    if (mx == 16) {                 /* Double block width? */\n                        if (ix == 8) {\n                            py += 64 - 8;    /* Jump to next block if double block height */\n                        }\n                        /* Step forward chroma pointer every two pixels */\n                        if (ix % 2) {\n                            pc++;\n                        }\n                    } else {                        /* Single block width */\n                        pc++;                       /* Step forward chroma pointer every pixel */\n                    }\n                    yy = *py++;         /* Get Y component */\n                    *pix++ = /*R*/ BYTECLIP(yy + ((int)(1.402 * CVACC) * cr) / CVACC);\n                    *pix++ = /*G*/ BYTECLIP(yy - ((int)(0.344 * CVACC) * cb + (int)(0.714 * CVACC) * cr) / CVACC);\n                    *pix++ = /*B*/ BYTECLIP(yy + ((int)(1.772 * CVACC) * cb) / CVACC);\n                }\n            }\n        } else {    /* Monochrome output (build a grayscale MCU from Y component) */\n            for (iy = 0; iy < my; iy++) {\n                py = jd->mcubuf + iy * 8;\n                if (my == 16) {     /* Double block height? */\n                    if (iy >= 8) {\n                        py += 64;\n                    }\n                }\n                for (ix = 0; ix < mx; ix++) {\n                    if (mx == 16) {                 /* Double block width? */\n                        if (ix == 8) {\n                            py += 64 - 8;    /* Jump to next block if double block height */\n                        }\n                    }\n                    *pix++ = (uint8_t) * py++;          /* Get and store a Y value as grayscale */\n                }\n            }\n        }\n\n        /* Descale the MCU rectangular if needed */\n        if (JD_USE_SCALE && jd->scale) {\n            unsigned int x, y, r, g, b, s, w, a;\n            uint8_t *op;\n\n            /* Get averaged RGB value of each square corresponds to a pixel */\n            s = jd->scale * 2;  /* Number of shifts for averaging */\n            w = 1 << jd->scale; /* Width of square */\n            a = (mx - w) * (JD_FORMAT != 2 ? 3 : 1);    /* Bytes to skip for next line in the square */\n            op = (uint8_t *)jd->workbuf;\n            for (iy = 0; iy < my; iy += w) {\n                for (ix = 0; ix < mx; ix += w) {\n                    pix = (uint8_t *)jd->workbuf + (iy * mx + ix) * (JD_FORMAT != 2 ? 3 : 1);\n                    r = g = b = 0;\n                    for (y = 0; y < w; y++) {   /* Accumulate RGB value in the square */\n                        for (x = 0; x < w; x++) {\n                            r += *pix++;    /* Accumulate R or Y (monochrome output) */\n                            if (JD_FORMAT != 2) {   /* RGB output? */\n                                g += *pix++;    /* Accumulate G */\n                                b += *pix++;    /* Accumulate B */\n                            }\n                        }\n                        pix += a;\n                    }                           /* Put the averaged pixel value */\n                    *op++ = (uint8_t)(r >> s);  /* Put R or Y (monochrome output) */\n                    if (JD_FORMAT != 2) {   /* RGB output? */\n                        *op++ = (uint8_t)(g >> s);  /* Put G */\n                        *op++ = (uint8_t)(b >> s);  /* Put B */\n                    }\n                }\n            }\n        }\n\n    } else {    /* For only 1/8 scaling (left-top pixel in each block are the DC value of the block) */\n\n        /* Build a 1/8 descaled RGB MCU from discrete components */\n        pix = (uint8_t *)jd->workbuf;\n        pc = jd->mcubuf + mx * my;\n        cb = pc[0] - 128;       /* Get Cb/Cr component and restore right level */\n        cr = pc[64] - 128;\n        for (iy = 0; iy < my; iy += 8) {\n            py = jd->mcubuf;\n            if (iy == 8) {\n                py += 64 * 2;\n            }\n            for (ix = 0; ix < mx; ix += 8) {\n                yy = *py;   /* Get Y component */\n                py += 64;\n                if (JD_FORMAT != 2) {\n                    *pix++ = /*R*/ BYTECLIP(yy + ((int)(1.402 * CVACC) * cr / CVACC));\n                    *pix++ = /*G*/ BYTECLIP(yy - ((int)(0.344 * CVACC) * cb + (int)(0.714 * CVACC) * cr) / CVACC);\n                    *pix++ = /*B*/ BYTECLIP(yy + ((int)(1.772 * CVACC) * cb / CVACC));\n                } else {\n                    *pix++ = yy;\n                }\n            }\n        }\n    }\n\n    /* Squeeze up pixel table if a part of MCU is to be truncated */\n    mx >>= jd->scale;\n    if (rx < mx) {  /* Is the MCU spans rigit edge? */\n        uint8_t *s, *d;\n        unsigned int x, y;\n\n        s = d = (uint8_t *)jd->workbuf;\n        for (y = 0; y < ry; y++) {\n            for (x = 0; x < rx; x++) {  /* Copy effective pixels */\n                *d++ = *s++;\n                if (JD_FORMAT != 2) {\n                    *d++ = *s++;\n                    *d++ = *s++;\n                }\n            }\n            s += (mx - rx) * (JD_FORMAT != 2 ? 3 : 1);  /* Skip truncated pixels */\n        }\n    }\n\n    /* Convert RGB888 to RGB565 if needed */\n    if (JD_FORMAT == 1) {\n        uint8_t *s = (uint8_t *)jd->workbuf;\n        uint16_t w, *d = (uint16_t *)s;\n        unsigned int n = rx * ry;\n\n        do {\n            w = (*s++ & 0xF8) << 8;     /* RRRRR----------- */\n            w |= (*s++ & 0xFC) << 3;    /* -----GGGGGG----- */\n            w |= *s++ >> 3;             /* -----------BBBBB */\n            *d++ = w;\n        } while (--n);\n    }\n\n    /* Output the rectangular */\n    return outfunc(jd, jd->workbuf, &rect) ? JDR_OK : JDR_INTR;\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Analyze the JPEG image and Initialize decompressor object             */\n/*-----------------------------------------------------------------------*/\n\n#define LDB_WORD(ptr)       (uint16_t)(((uint16_t)*((uint8_t*)(ptr))<<8)|(uint16_t)*(uint8_t*)((ptr)+1))\n\n\nJRESULT jd_prepare (\n    JDEC *jd,               /* Blank decompressor object */\n    size_t (*infunc)(JDEC *, uint8_t *, size_t), /* JPEG stream input function */\n    void *pool,             /* Working buffer for the decompression session */\n    size_t sz_pool,         /* Size of working buffer */\n    void *dev               /* I/O device identifier for the session */\n)\n{\n    uint8_t *seg, b;\n    uint16_t marker;\n    unsigned int n, i, ofs;\n    size_t len;\n    JRESULT rc;\n\n\n    memset(jd, 0, sizeof (JDEC));   /* Clear decompression object (this might be a problem if machine's null pointer is not all bits zero) */\n    jd->pool = pool;        /* Work memory */\n    jd->sz_pool = sz_pool;  /* Size of given work memory */\n    jd->infunc = infunc;    /* Stream input function */\n    jd->device = dev;       /* I/O device identifier */\n\n    jd->inbuf = seg = alloc_pool(jd, JD_SZBUF);     /* Allocate stream input buffer */\n    if (!seg) {\n        return JDR_MEM1;\n    }\n\n    ofs = marker = 0;       /* Find SOI marker */\n    do {\n        if (jd->infunc(jd, seg, 1) != 1) {\n            return JDR_INP;    /* Err: SOI was not detected */\n        }\n        ofs++;\n        marker = marker << 8 | seg[0];\n    } while (marker != 0xFFD8);\n\n    for (;;) {              /* Parse JPEG segments */\n        /* Get a JPEG marker */\n        if (jd->infunc(jd, seg, 4) != 4) {\n            return JDR_INP;\n        }\n        marker = LDB_WORD(seg);     /* Marker */\n        len = LDB_WORD(seg + 2);    /* Length field */\n\n        /*\n        In the baseline JPEG specification, 0xFF is always used as the \"marker prefix,\" and the byte that follows determines\n        the marker type (e.g., 0xD8 for SOI, 0xD9 for EOI, 0xDA for SOS, etc.).\n        A 0xFFFF sequence, however, does not correspond to any valid, standard JPEG marker.\n\n        In JPEG-compressed data, any single 0xFF in the entropy-coded segment is supposed to be followed by 0x00 if it is not a marker.\n        Sometimes, encoders or hardware incorrectly insert repeated 0xFF bytes without the 0x00 \"stuffing\" byte.\n        This confuses decoders that strictly follow the JPEG standard.\n        */\n        if (marker == 0xFFFF) {\n            // Check if ignoring seg[0] byte gives us valid marker\n            // We must read 1 more byte from the input stream\n            if (jd->infunc(jd, &seg[4], 1) != 1) {\n                return JDR_INP;\n            }\n            marker = LDB_WORD(seg + 1);\n            len = LDB_WORD(seg + 3);\n        }\n        if (len <= 2 || (marker >> 8) != 0xFF) {\n            return JDR_FMT1;\n        }\n        len -= 2;           /* Segent content size */\n        ofs += 4 + len;     /* Number of bytes loaded */\n\n        switch (marker & 0xFF) {\n        case 0xC0:  /* SOF0 (baseline JPEG) */\n            if (len > JD_SZBUF) {\n                return JDR_MEM2;\n            }\n            if (jd->infunc(jd, seg, len) != len) {\n                return JDR_INP;    /* Load segment data */\n            }\n\n            jd->width = LDB_WORD(&seg[3]);      /* Image width in unit of pixel */\n            jd->height = LDB_WORD(&seg[1]);     /* Image height in unit of pixel */\n            jd->ncomp = seg[5];                 /* Number of color components */\n            if (jd->ncomp != 3 && jd->ncomp != 1) {\n                return JDR_FMT3;    /* Err: Supports only Grayscale and Y/Cb/Cr */\n            }\n\n            /* Check each image component */\n            for (i = 0; i < jd->ncomp; i++) {\n                b = seg[7 + 3 * i];                         /* Get sampling factor */\n                if (i == 0) {   /* Y component */\n                    if (b != 0x11 && b != 0x22 && b != 0x21) {  /* Check sampling factor */\n                        return JDR_FMT3;                    /* Err: Supports only 4:4:4, 4:2:0 or 4:2:2 */\n                    }\n                    jd->msx = b >> 4; jd->msy = b & 15;     /* Size of MCU [blocks] */\n                } else {        /* Cb/Cr component */\n                    if (b != 0x11) {\n                        return JDR_FMT3;    /* Err: Sampling factor of Cb/Cr must be 1 */\n                    }\n                }\n                jd->qtid[i] = seg[8 + 3 * i];               /* Get dequantizer table ID for this component */\n                if (jd->qtid[i] > 3) {\n                    return JDR_FMT3;    /* Err: Invalid ID */\n                }\n            }\n            break;\n\n        case 0xDD:  /* DRI - Define Restart Interval */\n            if (len > JD_SZBUF) {\n                return JDR_MEM2;\n            }\n            if (jd->infunc(jd, seg, len) != len) {\n                return JDR_INP;    /* Load segment data */\n            }\n\n            jd->nrst = LDB_WORD(seg);   /* Get restart interval (MCUs) */\n            break;\n\n        case 0xC4:  /* DHT - Define Huffman Tables */\n            if (len > JD_SZBUF) {\n                return JDR_MEM2;\n            }\n            if (jd->infunc(jd, seg, len) != len) {\n                return JDR_INP;    /* Load segment data */\n            }\n\n            rc = create_huffman_tbl(jd, seg, len);  /* Create huffman tables */\n            if (rc) {\n                return rc;\n            }\n            break;\n\n        case 0xDB:  /* DQT - Define Quaitizer Tables */\n            if (len > JD_SZBUF) {\n                return JDR_MEM2;\n            }\n            if (jd->infunc(jd, seg, len) != len) {\n                return JDR_INP;    /* Load segment data */\n            }\n\n            rc = create_qt_tbl(jd, seg, len);   /* Create de-quantizer tables */\n            if (rc) {\n                return rc;\n            }\n            break;\n\n        case 0xDA:  /* SOS - Start of Scan */\n            if (len > JD_SZBUF) {\n                return JDR_MEM2;\n            }\n            if (jd->infunc(jd, seg, len) != len) {\n                return JDR_INP;    /* Load segment data */\n            }\n\n            if (!jd->width || !jd->height) {\n                return JDR_FMT1;    /* Err: Invalid image size */\n            }\n            if (seg[0] != jd->ncomp) {\n                return JDR_FMT3;    /* Err: Wrong color components */\n            }\n\n            /* Check if all tables corresponding to each components have been loaded */\n            for (i = 0; i < jd->ncomp; i++) {\n                b = seg[2 + 2 * i]; /* Get huffman table ID */\n                if (b != 0x00 && b != 0x11) {\n                    return JDR_FMT3;    /* Err: Different table number for DC/AC element */\n                }\n                n = i ? 1 : 0;                          /* Component class */\n                if (!jd->huffbits[n][0] || !jd->huffbits[n][1]) {   /* Check huffman table for this component */\n#if JD_DEFAULT_HUFFMAN\n                    jd_load_default_huffman(jd); // Always returns OK\n#else\n                    return JDR_FMT1;                    /* Err: Nnot loaded */\n#endif\n                }\n                if (!jd->qttbl[jd->qtid[i]]) {          /* Check dequantizer table for this component */\n                    return JDR_FMT1;                    /* Err: Not loaded */\n                }\n            }\n\n            /* Allocate working buffer for MCU and pixel output */\n            n = jd->msy * jd->msx;                      /* Number of Y blocks in the MCU */\n            if (!n) {\n                return JDR_FMT1;    /* Err: SOF0 has not been loaded */\n            }\n            len = n * 64 * 2 + 64;                      /* Allocate buffer for IDCT and RGB output */\n            if (len < 256) {\n                len = 256;    /* but at least 256 byte is required for IDCT */\n            }\n            jd->workbuf = alloc_pool(jd, len);          /* and it may occupy a part of following MCU working buffer for RGB output */\n            if (!jd->workbuf) {\n                return JDR_MEM1;    /* Err: not enough memory */\n            }\n            jd->mcubuf = alloc_pool(jd, (n + 2) * 64 * sizeof (jd_yuv_t));  /* Allocate MCU working buffer */\n            if (!jd->mcubuf) {\n                return JDR_MEM1;    /* Err: not enough memory */\n            }\n\n            /* Align stream read offset to JD_SZBUF */\n            if (ofs %= JD_SZBUF) {\n                jd->dctr = jd->infunc(jd, seg + ofs, (size_t)(JD_SZBUF - ofs));\n            }\n            jd->dptr = seg + ofs - (JD_FASTDECODE ? 0 : 1);\n\n            return JDR_OK;      /* Initialization succeeded. Ready to decompress the JPEG image. */\n\n        case 0xC1:  /* SOF1 */\n        case 0xC2:  /* SOF2 */\n        case 0xC3:  /* SOF3 */\n        case 0xC5:  /* SOF5 */\n        case 0xC6:  /* SOF6 */\n        case 0xC7:  /* SOF7 */\n        case 0xC9:  /* SOF9 */\n        case 0xCA:  /* SOF10 */\n        case 0xCB:  /* SOF11 */\n        case 0xCD:  /* SOF13 */\n        case 0xCE:  /* SOF14 */\n        case 0xCF:  /* SOF15 */\n        case 0xD9:  /* EOI */\n            return JDR_FMT3;    /* Unsuppoted JPEG standard (may be progressive JPEG) */\n\n        default:    /* Unknown segment (comment, exif or etc..) */\n            /* Skip segment data (null pointer specifies to remove data from the stream) */\n            if (jd->infunc(jd, 0, len) != len) {\n                return JDR_INP;\n            }\n        }\n    }\n}\n\n\n\n\n/*-----------------------------------------------------------------------*/\n/* Start to decompress the JPEG picture                                  */\n/*-----------------------------------------------------------------------*/\n\nJRESULT jd_decomp (\n    JDEC *jd,                               /* Initialized decompression object */\n    int (*outfunc)(JDEC *, void *, JRECT *), /* RGB output function */\n    uint8_t scale                           /* Output de-scaling factor (0 to 3) */\n)\n{\n    unsigned int x, y, mx, my;\n    uint16_t rst, rsc;\n    JRESULT rc;\n\n\n    if (scale > (JD_USE_SCALE ? 3 : 0)) {\n        return JDR_PAR;\n    }\n    jd->scale = scale;\n\n    mx = jd->msx * 8; my = jd->msy * 8;         /* Size of the MCU (pixel) */\n\n    jd->dcv[2] = jd->dcv[1] = jd->dcv[0] = 0;   /* Initialize DC values */\n    rst = rsc = 0;\n\n    rc = JDR_OK;\n    for (y = 0; y < jd->height; y += my) {      /* Vertical loop of MCUs */\n        for (x = 0; x < jd->width; x += mx) {   /* Horizontal loop of MCUs */\n            if (jd->nrst && rst++ == jd->nrst) {    /* Process restart interval if enabled */\n                rc = restart(jd, rsc++);\n                if (rc != JDR_OK) {\n                    return rc;\n                }\n                rst = 1;\n            }\n            rc = mcu_load(jd);                  /* Load an MCU (decompress huffman coded stream, dequantize and apply IDCT) */\n            if (rc != JDR_OK) {\n                return rc;\n            }\n            rc = mcu_output(jd, outfunc, x, y); /* Output the MCU (YCbCr to RGB, scaling and output) */\n            if (rc != JDR_OK) {\n                return rc;\n            }\n        }\n    }\n\n    return rc;\n}\n"
  },
  {
    "path": "esp_jpeg/tjpgd/tjpgd.h",
    "content": "/*----------------------------------------------------------------------------/\n/ TJpgDec - Tiny JPEG Decompressor R0.03 include file         (C)ChaN, 2021\n/----------------------------------------------------------------------------*/\n#ifndef DEF_TJPGDEC\n#define DEF_TJPGDEC\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include \"tjpgdcnf.h\"\n#include <string.h>\n\n#if defined(_WIN32) /* VC++ or some compiler without stdint.h */\ntypedef unsigned char   uint8_t;\ntypedef unsigned short  uint16_t;\ntypedef short           int16_t;\ntypedef unsigned long   uint32_t;\ntypedef long            int32_t;\n#else               /* Embedded platform */\n#include <stdint.h>\n#endif\n\n#if JD_FASTDECODE >= 1\ntypedef int16_t jd_yuv_t;\n#else\ntypedef uint8_t jd_yuv_t;\n#endif\n\n\n/* Error code */\ntypedef enum {\n    JDR_OK = 0, /* 0: Succeeded */\n    JDR_INTR,   /* 1: Interrupted by output function */\n    JDR_INP,    /* 2: Device error or wrong termination of input stream */\n    JDR_MEM1,   /* 3: Insufficient memory pool for the image */\n    JDR_MEM2,   /* 4: Insufficient stream input buffer */\n    JDR_PAR,    /* 5: Parameter error */\n    JDR_FMT1,   /* 6: Data format error (may be broken data) */\n    JDR_FMT2,   /* 7: Right format but not supported */\n    JDR_FMT3    /* 8: Not supported JPEG standard */\n} JRESULT;\n\n\n\n/* Rectangular region in the output image */\ntypedef struct {\n    uint16_t left;      /* Left end */\n    uint16_t right;     /* Right end */\n    uint16_t top;       /* Top end */\n    uint16_t bottom;    /* Bottom end */\n} JRECT;\n\n\n\n/* Decompressor object structure */\ntypedef struct JDEC JDEC;\nstruct JDEC {\n    size_t dctr;                /* Number of bytes available in the input buffer */\n    uint8_t *dptr;              /* Current data read ptr */\n    uint8_t *inbuf;             /* Bit stream input buffer */\n    uint8_t dbit;               /* Number of bits available in wreg or reading bit mask */\n    uint8_t scale;              /* Output scaling ratio */\n    uint8_t msx, msy;           /* MCU size in unit of block (width, height) */\n    uint8_t qtid[3];            /* Quantization table ID of each component, Y, Cb, Cr */\n    uint8_t ncomp;              /* Number of color components 1:grayscale, 3:color */\n    int16_t dcv[3];             /* Previous DC element of each component */\n    uint16_t nrst;              /* Restart interval */\n    uint16_t width, height;     /* Size of the input image (pixel) */\n    uint8_t *huffbits[2][2];    /* Huffman bit distribution tables [id][dcac] */\n    uint16_t *huffcode[2][2];   /* Huffman code word tables [id][dcac] */\n    uint8_t *huffdata[2][2];    /* Huffman decoded data tables [id][dcac] */\n    int32_t *qttbl[4];          /* Dequantizer tables [id] */\n#if JD_FASTDECODE >= 1\n    uint32_t wreg;              /* Working shift register */\n    uint8_t marker;             /* Detected marker (0:None) */\n#if JD_FASTDECODE == 2\n    uint8_t longofs[2][2];      /* Table offset of long code [id][dcac] */\n    uint16_t *hufflut_ac[2];    /* Fast huffman decode tables for AC short code [id] */\n    uint8_t *hufflut_dc[2];     /* Fast huffman decode tables for DC short code [id] */\n#endif\n#endif\n    void *workbuf;              /* Working buffer for IDCT and RGB output */\n    jd_yuv_t *mcubuf;           /* Working buffer for the MCU */\n    void *pool;                 /* Pointer to available memory pool */\n    size_t sz_pool;             /* Size of memory pool (bytes available) */\n    size_t (*infunc)(JDEC *, uint8_t *, size_t); /* Pointer to jpeg stream input function */\n    void *device;               /* Pointer to I/O device identifier for the session */\n};\n\n\n\n/* TJpgDec API functions */\nJRESULT jd_prepare (JDEC *jd, size_t (*infunc)(JDEC *, uint8_t *, size_t), void *pool, size_t sz_pool, void *dev);\nJRESULT jd_decomp (JDEC *jd, int (*outfunc)(JDEC *, void *, JRECT *), uint8_t scale);\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _TJPGDEC */\n"
  },
  {
    "path": "esp_jpeg/tjpgd/tjpgdcnf.h",
    "content": "/*----------------------------------------------*/\n/* TJpgDec System Configurations R0.03          */\n/*----------------------------------------------*/\n\n#include \"sdkconfig.h\"\n\n#define JD_SZBUF        CONFIG_JD_SZBUF\n/* Specifies size of stream input buffer */\n\n#define JD_FORMAT       CONFIG_JD_FORMAT\n/* Specifies output pixel format.\n/  0: RGB888 (24-bit/pix)\n/  1: RGB565 (16-bit/pix)\n/  2: Grayscale (8-bit/pix)\n*/\n\n#if defined(CONFIG_JD_USE_SCALE)\n#define JD_USE_SCALE    CONFIG_JD_USE_SCALE\n#else\n#define JD_USE_SCALE    0\n#endif\n/* Switches output descaling feature.\n/  0: Disable\n/  1: Enable\n*/\n\n#if defined(CONFIG_JD_TBLCLIP)\n#define JD_TBLCLIP      CONFIG_JD_TBLCLIP\n#else\n#define JD_TBLCLIP      0\n#endif\n/* Use table conversion for saturation arithmetic. A bit faster, but increases 1 KB of code size.\n/  0: Disable\n/  1: Enable\n*/\n\n#define JD_FASTDECODE   CONFIG_JD_FASTDECODE\n/* Optimization level\n/  0: Basic optimization. Suitable for 8/16-bit MCUs.\n/  1: + 32-bit barrel shifter. Suitable for 32-bit MCUs.\n/  2: + Table conversion for huffman decoding (wants 6 << HUFF_BIT bytes of RAM)\n*/\n\n#if defined(CONFIG_JD_DEFAULT_HUFFMAN)\n#define JD_DEFAULT_HUFFMAN CONFIG_JD_DEFAULT_HUFFMAN\n#else\n#define JD_DEFAULT_HUFFMAN 0\n#endif\n"
  },
  {
    "path": "esp_lcd_qemu_rgb/CHANGELOG.md",
    "content": "## 1.0.2\n\n- Switched to RGB565 color format in the example by default\n- Fixed compatibility with IDF v5.3-dev\n\n## 1.0.1\n\n- Added support for RGB565 color format\n\n## 1.0.0\n\n- Initial driver version\n"
  },
  {
    "path": "esp_lcd_qemu_rgb/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"src/esp_lcd_qemu_rgb.c\"\n                       INCLUDE_DIRS \"interface\"\n                       REQUIRES \"esp_lcd\")\n"
  },
  {
    "path": "esp_lcd_qemu_rgb/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "esp_lcd_qemu_rgb/README.md",
    "content": "# QEMU RGB Panel\n\nThis component presents an interface for the virtual QEMU RGB panel, implemented into Espressif's QEMU fork starting from version 8.1.3-20231206.\n\nThis virtual RGB panel that can be used to display graphical interfaces. This panel also includes a dedicated frame buffer, absent in real hardware and independent from the internal RAM, that allows user program to populate the pixels in.\n\n**Please note** that the virtual RGB panel currently supports only two color modes: ARGB8888 (32-bit) and RGB565 (16-bit).\n"
  },
  {
    "path": "esp_lcd_qemu_rgb/examples/lcd_qemu_rgb_panel/CMakeLists.txt",
    "content": "# For more information about build system see\n# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html\n# The following five lines of boilerplate have to be in your project's\n# CMakeLists in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(lcd_qemu_rgb_panel)\n"
  },
  {
    "path": "esp_lcd_qemu_rgb/examples/lcd_qemu_rgb_panel/README.md",
    "content": "# QEMU RGB Panel\n\nThis example demonstrates how to use the virtual QEMU RGB panel. In this case, LVGL uses the virtual panel to render its graphical user interface.\n\nThe frame buffer can be chosen between internal RAM or dedicated frame buffer.\n\n## How to Use Example\n\n### Hardware Required\n\n* No hardware target is required to run this example\n\n### Configure the Example\n\nBy default, the example will use the target internal RAM as the frame buffer. To utilize the QEMU dedicated frame buffer, enable the option `Use QEMU RGB panel dedicated framebuffer` within the `menuconfig`.\n\n### Build and run\n\nTo build the example, run `idf.py build` command.\n\nPlease refer to the [QEMU Guide](https://github.com/espressif/esp-toolchain-docs/blob/main/qemu/README.md) for the detailed steps to setup and run the image.\n\n## Example Output\n\n```text\nI (55) example: Install RGB LCD panel driver\nI (55) example: Initialize RGB LCD panel\nI (55) example: Initialize LVGL library\nI (55) example: Allocate separate LVGL draw buffer\nI (55) example: Register display driver to LVGL\nI (55) example: Install LVGL tick timer\nI (55) example: Create LVGL task\nI (55) example: Starting LVGL task\nI (65) example: Display LVGL Scatter Chart\nI (75) main_task: Returned from app_main()\n```\n"
  },
  {
    "path": "esp_lcd_qemu_rgb/examples/lcd_qemu_rgb_panel/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"lcd_qemu_rgb_panel_main.c\" \"lvgl_demo_ui.c\"\n                       INCLUDE_DIRS \".\"\n                       REQUIRES \"esp_lcd\")\n"
  },
  {
    "path": "esp_lcd_qemu_rgb/examples/lcd_qemu_rgb_panel/main/Kconfig.projbuild",
    "content": "menu \"Example Configuration\"\n\n    config EXAMPLE_QEMU_RGB_PANEL_DEDIC_FB\n        bool \"Use QEMU RGB panel dedicated framebuffer\"\n        default \"n\"\n        help\n            Use QEMU RGB panel dedicated framebuffer as the framebuffer for LVGL.\n\nendmenu\n"
  },
  {
    "path": "esp_lcd_qemu_rgb/examples/lcd_qemu_rgb_panel/main/idf_component.yml",
    "content": "## IDF Component Manager Manifest File\ndependencies:\n  espressif/esp_lcd_qemu_rgb:\n    version: '^1'\n    override_path: '../../../'\n  lvgl/lvgl: \"~8.3.0\"\n"
  },
  {
    "path": "esp_lcd_qemu_rgb/examples/lcd_qemu_rgb_panel/main/lcd_qemu_rgb_panel_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n\n#include <stdio.h>\n#include \"sdkconfig.h\"\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"freertos/semphr.h\"\n#include \"esp_timer.h\"\n#include \"esp_lcd_panel_ops.h\"\n#include \"esp_lcd_qemu_rgb.h\"\n#include \"driver/gpio.h\"\n#include \"esp_err.h\"\n#include \"esp_log.h\"\n#include \"lvgl.h\"\n\nstatic const char *TAG = \"example\";\n\n/**\n * 32-bit and 16-bit colors are currently supported by QEMU RGB Panel\n */\n#if CONFIG_LV_COLOR_DEPTH_32\n#define CURRENT_COLOR_DEPTH RGB_QEMU_BPP_32\n#elif CONFIG_LV_COLOR_DEPTH_16\n#define CURRENT_COLOR_DEPTH RGB_QEMU_BPP_16\n#else\n#error \"QEMU RGB Panel only supports 32-bit and 16-bit colors, please enable LV_COLOR_DEPTH_32 or LV_COLOR_DEPTH_16\"\n#endif\n\n// The pixel number in horizontal and vertical\n#define EXAMPLE_LCD_H_RES              800\n#define EXAMPLE_LCD_V_RES              480\n\n#define EXAMPLE_LVGL_TICK_PERIOD_MS    2\n#define EXAMPLE_LVGL_TASK_MAX_DELAY_MS 500\n#define EXAMPLE_LVGL_TASK_MIN_DELAY_MS 1\n#define EXAMPLE_LVGL_TASK_STACK_SIZE   (4 * 1024)\n#define EXAMPLE_LVGL_TASK_PRIORITY     2\n\nstatic SemaphoreHandle_t lvgl_mux = NULL;\n\nextern void example_lvgl_demo_ui(lv_disp_t *disp);\n\n\nstatic void example_lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map)\n{\n    esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data;\n    int offsetx1 = area->x1;\n    int offsetx2 = area->x2;\n    int offsety1 = area->y1;\n    int offsety2 = area->y2;\n    // pass the draw buffer to the driver\n    esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map);\n    lv_disp_flush_ready(drv);\n}\n\nstatic void example_increase_lvgl_tick(void *arg)\n{\n    /* Tell LVGL how many milliseconds has elapsed */\n    lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS);\n}\n\nbool example_lvgl_lock(int timeout_ms)\n{\n    // Convert timeout in milliseconds to FreeRTOS ticks\n    // If `timeout_ms` is set to -1, the program will block until the condition is met\n    const TickType_t timeout_ticks = (timeout_ms == -1) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms);\n    return xSemaphoreTakeRecursive(lvgl_mux, timeout_ticks) == pdTRUE;\n}\n\nvoid example_lvgl_unlock(void)\n{\n    xSemaphoreGiveRecursive(lvgl_mux);\n}\n\nstatic void example_lvgl_port_task(void *arg)\n{\n    ESP_LOGI(TAG, \"Starting LVGL task\");\n    uint32_t task_delay_ms = EXAMPLE_LVGL_TASK_MAX_DELAY_MS;\n    while (1) {\n        // Lock the mutex due to the LVGL APIs are not thread-safe\n        if (example_lvgl_lock(-1)) {\n            task_delay_ms = lv_timer_handler();\n            // Release the mutex\n            example_lvgl_unlock();\n        }\n        if (task_delay_ms > EXAMPLE_LVGL_TASK_MAX_DELAY_MS) {\n            task_delay_ms = EXAMPLE_LVGL_TASK_MAX_DELAY_MS;\n        } else if (task_delay_ms < EXAMPLE_LVGL_TASK_MIN_DELAY_MS) {\n            task_delay_ms = EXAMPLE_LVGL_TASK_MIN_DELAY_MS;\n        }\n        vTaskDelay(pdMS_TO_TICKS(task_delay_ms));\n    }\n}\n\nstatic size_t example_lvgl_get_buffers(esp_lcd_panel_handle_t panel_handle, void **buf1, void **buf2)\n{\n    if (buf2) {\n        *buf2 = NULL;\n    }\n#if CONFIG_EXAMPLE_QEMU_RGB_PANEL_DEDIC_FB\n    ESP_LOGI(TAG, \"Use QEMU dedicated frame buffer as LVGL draw buffer\");\n    ESP_ERROR_CHECK(esp_lcd_rgb_qemu_get_frame_buffer(panel_handle, buf1));\n    return EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES;\n#else\n    ESP_LOGI(TAG, \"Allocate separate LVGL draw buffer\");\n    /* Allocate 10 horizontal lines as the frame buffer */\n    *buf1 = malloc(EXAMPLE_LCD_H_RES * 10 * sizeof(lv_color_t));\n    assert(*buf1);\n    return EXAMPLE_LCD_H_RES * 10;\n#endif // CONFIG_EXAMPLE_DOUBLE_FB\n}\n\nvoid app_main(void)\n{\n    static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s)\n    static lv_disp_drv_t disp_drv;      // contains callback functions\n\n    ESP_LOGI(TAG, \"Install RGB LCD panel driver\");\n    esp_lcd_panel_handle_t panel_handle = NULL;\n    esp_lcd_rgb_qemu_config_t panel_config = {\n        .width = EXAMPLE_LCD_H_RES,\n        .height = EXAMPLE_LCD_V_RES,\n        .bpp = CURRENT_COLOR_DEPTH,\n    };\n    ESP_ERROR_CHECK(esp_lcd_new_rgb_qemu(&panel_config, &panel_handle));\n\n    ESP_LOGI(TAG, \"Initialize RGB LCD panel\");\n    ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));\n    ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));\n\n    ESP_LOGI(TAG, \"Initialize LVGL library\");\n    lv_init();\n    void *buf1 = NULL;\n    void *buf2 = NULL;\n    const size_t buf_pixels = example_lvgl_get_buffers(panel_handle, &buf1, &buf2);\n    lv_disp_draw_buf_init(&disp_buf, buf1, buf2, buf_pixels);\n\n    ESP_LOGI(TAG, \"Register display driver to LVGL\");\n    lv_disp_drv_init(&disp_drv);\n    disp_drv.hor_res = EXAMPLE_LCD_H_RES;\n    disp_drv.ver_res = EXAMPLE_LCD_V_RES;\n    disp_drv.flush_cb = example_lvgl_flush_cb;\n    disp_drv.draw_buf = &disp_buf;\n    disp_drv.user_data = panel_handle;\n#if CONFIG_EXAMPLE_QEMU_RGB_PANEL_DEDIC_FB\n    disp_drv.full_refresh = true; // the full_refresh mode can maintain the synchronization between the two frame buffers\n#endif\n    lv_disp_t *disp = lv_disp_drv_register(&disp_drv);\n\n    ESP_LOGI(TAG, \"Install LVGL tick timer\");\n    // Tick interface for LVGL (using esp_timer to generate 2ms periodic event)\n    const esp_timer_create_args_t lvgl_tick_timer_args = {\n        .callback = &example_increase_lvgl_tick,\n        .name = \"lvgl_tick\"\n    };\n    esp_timer_handle_t lvgl_tick_timer = NULL;\n    ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));\n    ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000));\n\n    lvgl_mux = xSemaphoreCreateRecursiveMutex();\n    assert(lvgl_mux);\n    ESP_LOGI(TAG, \"Create LVGL task\");\n    xTaskCreate(example_lvgl_port_task, \"LVGL\", EXAMPLE_LVGL_TASK_STACK_SIZE, NULL, EXAMPLE_LVGL_TASK_PRIORITY, NULL);\n\n    ESP_LOGI(TAG, \"Display LVGL Scatter Chart\");\n    // Lock the mutex due to the LVGL APIs are not thread-safe\n    if (example_lvgl_lock(-1)) {\n        example_lvgl_demo_ui(disp);\n        // Release the mutex\n        example_lvgl_unlock();\n    }\n}\n"
  },
  {
    "path": "esp_lcd_qemu_rgb/examples/lcd_qemu_rgb_panel/main/lvgl_demo_ui.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n\n// This demo UI is adapted from LVGL official example: https://docs.lvgl.io/master/examples.html#scatter-chart\n\n#include \"lvgl.h\"\n#include <stdio.h>\n\nstatic void draw_event_cb(lv_event_t *e)\n{\n    lv_obj_draw_part_dsc_t *dsc = lv_event_get_draw_part_dsc(e);\n    if (dsc->part == LV_PART_ITEMS) {\n        lv_obj_t *obj = lv_event_get_target(e);\n        lv_chart_series_t *ser = lv_chart_get_series_next(obj, NULL);\n        uint32_t cnt = lv_chart_get_point_count(obj);\n        /*Make older value more transparent*/\n        dsc->rect_dsc->bg_opa = (LV_OPA_COVER *  dsc->id) / (cnt - 1);\n\n        /*Make smaller values blue, higher values red*/\n        lv_coord_t *x_array = lv_chart_get_x_array(obj, ser);\n        lv_coord_t *y_array = lv_chart_get_y_array(obj, ser);\n        /*dsc->id is the tells drawing order, but we need the ID of the point being drawn.*/\n        uint32_t start_point = lv_chart_get_x_start_point(obj, ser);\n        uint32_t p_act = (start_point + dsc->id) % cnt; /*Consider start point to get the index of the array*/\n        lv_opa_t x_opa = (x_array[p_act] * LV_OPA_50) / 200;\n        lv_opa_t y_opa = (y_array[p_act] * LV_OPA_50) / 1000;\n\n        dsc->rect_dsc->bg_color = lv_color_mix(lv_palette_main(LV_PALETTE_RED),\n                                               lv_palette_main(LV_PALETTE_BLUE),\n                                               x_opa + y_opa);\n    }\n}\n\nstatic void add_data(lv_timer_t *timer)\n{\n    lv_obj_t *chart = timer->user_data;\n    lv_chart_set_next_value2(chart, lv_chart_get_series_next(chart, NULL), lv_rand(0, 200), lv_rand(0, 1000));\n}\n\nvoid example_lvgl_demo_ui(lv_disp_t *disp)\n{\n    lv_obj_t *scr = lv_disp_get_scr_act(disp);\n    lv_obj_t *chart = lv_chart_create(scr);\n    lv_obj_set_size(chart, 200, 150);\n    lv_obj_align(chart, LV_ALIGN_CENTER, 0, 0);\n    lv_obj_add_event_cb(chart, draw_event_cb, LV_EVENT_DRAW_PART_BEGIN, NULL);\n    lv_obj_set_style_line_width(chart, 0, LV_PART_ITEMS);   /*Remove the lines*/\n\n    lv_chart_set_type(chart, LV_CHART_TYPE_SCATTER);\n\n    lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_X, 5, 5, 5, 1, true, 30);\n    lv_chart_set_axis_tick(chart, LV_CHART_AXIS_PRIMARY_Y, 10, 5, 6, 5, true, 50);\n\n    lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_X, 0, 200);\n    lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 1000);\n\n    lv_chart_set_point_count(chart, 50);\n\n    lv_chart_series_t *ser = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y);\n    for (int i = 0; i < 50; i++) {\n        lv_chart_set_next_value2(chart, ser, lv_rand(0, 200), lv_rand(0, 1000));\n    }\n\n    lv_timer_create(add_data, 100, chart);\n}\n"
  },
  {
    "path": "esp_lcd_qemu_rgb/idf_component.yml",
    "content": "version: \"1.0.2\"\ndescription: Driver for the virtual QEMU RGB panel\nurl: https://github.com/espressif/idf-extra-components/tree/master/esp_lcd_qemu_rgb\nrepository: https://github.com/espressif/idf-extra-components.git\nissues: https://github.com/espressif/idf-extra-components/issues\ndependencies:\n  idf: \">=5.3\"\n"
  },
  {
    "path": "esp_lcd_qemu_rgb/interface/esp_lcd_qemu_rgb.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdint.h>\n#include \"esp_err.h\"\n#include \"esp_lcd_types.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef enum {\n    RGB_QEMU_BPP_32 = 32,\n    RGB_QEMU_BPP_16 = 16,\n} esp_lcd_rgb_qemu_bpp_t;\n/**\n * @brief QEMU RGB panel configuration structure\n */\ntypedef struct {\n    uint32_t width;             /*!< Width of the graphical window in pixels */\n    uint32_t height;            /*!< Height of the graphical window in pixels */\n    esp_lcd_rgb_qemu_bpp_t bpp;                /*!< BPP - bit per pixel*/\n} esp_lcd_rgb_qemu_config_t;\n\n/**\n * @brief Create QEMU RGB panel\n *\n * @param[in] rgb_config QEMU RGB panel configuration\n * @param[out] ret_panel Returned panel handle\n * @return\n *      - ESP_ERR_INVALID_ARG: Creation failed because of invalid argument, check the configuration parameter\n *      - ESP_ERR_NO_MEM: Creation failed because of the lack of free memory in the heap\n *      - ESP_ERR_NOT_SUPPORTED: Creation failed because this API must only be used within a QEMU virtual machine\n *      - ESP_OK: Panel created successfully\n */\nesp_err_t esp_lcd_new_rgb_qemu(const esp_lcd_rgb_qemu_config_t *rgb_config, esp_lcd_panel_handle_t *ret_panel);\n\n/**\n * @brief Get the address of the frame buffer for the QEMU RGB panel\n *\n * @param[in] panel QEMU RGB panel handle, returned from `esp_lcd_new_rgb_qemu`\n * @param[out] fb Returned address of the frame buffer\n * @return\n *      - ESP_OK: Frame buffer returned successfully\n */\nesp_err_t esp_lcd_rgb_qemu_get_frame_buffer(esp_lcd_panel_handle_t panel, void **fb);\n\n/**\n * @brief Manually trigger once transmission of the frame buffer to the panel\n *\n * @param[in] panel QEMU RGB panel handle, returned from `esp_lcd_new_rgb_qemu`\n * @returns ESP_OK unconditionally\n */\nesp_err_t esp_lcd_rgb_qemu_refresh(esp_lcd_panel_handle_t panel);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_lcd_qemu_rgb/src/esp_lcd_qemu_rgb.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"sdkconfig.h\"\n#include \"esp_check.h\"\n#include \"esp_lcd_panel_interface.h\"\n#include \"esp_lcd_qemu_rgb_struct.h\"\n#include \"esp_lcd_qemu_rgb.h\"\n#include \"esp_lcd_panel_ops.h\"\n#include \"soc/syscon_reg.h\"\n\n/* \"QEMU\" as a 32-bit value, used to check whether the current application is running in\n * QEMU or on real hardware */\n#define RGB_QEMU_ORIGIN     0x51454d55\n\nstatic const char *TAG = \"lcd_qemu.rgb\";\n\nstatic rgb_qemu_dev_t *s_rgb_dev = (void *) 0x21000000;\nstatic uint32_t *s_rgb_framebuffer = (void *) 0x20000000;\n\n\n/* Software handler for the RGB Qemu virtual panel */\ntypedef struct esp_rgb_qemu_t {\n    esp_lcd_panel_t base;  // Base class of generic lcd panel\n    int panel_id;          // LCD panel ID\n    uint32_t width;\n    uint32_t height;\n} esp_rgb_qemu_t;\n\nstatic_assert(offsetof(esp_rgb_qemu_t, base) == 0, \"Base field must be the first\");\n\nstatic esp_err_t rgb_qemu_del(esp_lcd_panel_t *panel);\nstatic esp_err_t rgb_qemu_reset(esp_lcd_panel_t *panel);\nstatic esp_err_t rgb_qemu_init(esp_lcd_panel_t *panel);\nstatic esp_err_t rgb_qemu_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int y_start, int x_end, int y_end, const void *color_data);\nstatic esp_err_t rgb_qemu_invert_color(esp_lcd_panel_t *panel, bool invert_color_data);\nstatic esp_err_t rgb_qemu_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y);\nstatic esp_err_t rgb_qemu_swap_xy(esp_lcd_panel_t *panel, bool swap_axes);\nstatic esp_err_t rgb_qemu_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap);\nstatic esp_err_t rgb_qemu_disp_on_off(esp_lcd_panel_t *panel, bool off);\n\nesp_err_t esp_lcd_new_rgb_qemu(const esp_lcd_rgb_qemu_config_t *rgb_config, esp_lcd_panel_handle_t *ret_panel)\n{\n    esp_err_t ret = ESP_OK;\n    esp_rgb_qemu_t *rgb_panel = NULL;\n    ESP_GOTO_ON_FALSE(ret_panel, ESP_ERR_INVALID_ARG, err, TAG, \"invalid parameter\");\n\n    /* Check if we are actually running on QEMU, read the special register allocated just before the\n     * SYSCON date one. */\n    const uint32_t origin = REG_READ(SYSCON_DATE_REG - 4);\n\n    /* In case we are running in QEMU, this register contains \"QEMU\" as a 32-bit value */\n    ESP_GOTO_ON_FALSE(origin == RGB_QEMU_ORIGIN, ESP_ERR_NOT_SUPPORTED, err, TAG, \"qemu panel is not available on real hardware\");\n\n    rgb_panel = calloc(1, sizeof(esp_rgb_qemu_t));\n    ESP_GOTO_ON_FALSE(rgb_panel, ESP_ERR_NO_MEM, err, TAG, \"no mem for rgb qemu panel\");\n\n    /* Resize the window and setup bpp*/\n    s_rgb_dev->size.height = rgb_config->height;\n    s_rgb_dev->size.width = rgb_config->width;\n    s_rgb_dev->bpp = rgb_config->bpp ? rgb_config->bpp : RGB_QEMU_BPP_32;\n    /* If the configured size is bigger than authorized, the hardware will arrange it.\n     * So, read back the configured size */\n    rgb_panel->height = rgb_config->height;\n    rgb_panel->width = rgb_config->width;\n\n    /* Fill function table */\n    rgb_panel->base.del = rgb_qemu_del;\n    rgb_panel->base.reset = rgb_qemu_reset;\n    rgb_panel->base.init = rgb_qemu_init;\n    rgb_panel->base.draw_bitmap = rgb_qemu_draw_bitmap;\n    rgb_panel->base.disp_on_off = rgb_qemu_disp_on_off;\n    rgb_panel->base.invert_color = rgb_qemu_invert_color;\n    rgb_panel->base.mirror = rgb_qemu_mirror;\n    rgb_panel->base.swap_xy = rgb_qemu_swap_xy;\n    rgb_panel->base.set_gap = rgb_qemu_set_gap;\n\n    /* Return base class */\n    *ret_panel = &(rgb_panel->base);\n    ret = ESP_OK;\n\nerr:\n    return ret;\n}\n\nesp_err_t esp_lcd_rgb_qemu_get_frame_buffer(esp_lcd_panel_handle_t panel, void **fb)\n{\n    if (fb) {\n        *fb = (void *) s_rgb_framebuffer;\n    }\n\n    return ESP_OK;\n}\n\nesp_err_t esp_lcd_rgb_qemu_refresh(esp_lcd_panel_handle_t panel)\n{\n    esp_rgb_qemu_t *rgb_panel = (esp_rgb_qemu_t *) panel;\n    return rgb_qemu_draw_bitmap(panel, 0, 0, rgb_panel->width, rgb_panel->height, s_rgb_framebuffer);\n}\n\n/*** PRIVATE FUNCTIONS ***/\n\nstatic esp_err_t rgb_qemu_del(esp_lcd_panel_t *panel)\n{\n    free(panel);\n    return ESP_OK;\n}\n\nstatic esp_err_t rgb_qemu_reset(esp_lcd_panel_t *panel)\n{\n    return ESP_OK;\n}\n\nstatic esp_err_t rgb_qemu_init(esp_lcd_panel_t *panel)\n{\n    return ESP_OK;\n}\n\nstatic esp_err_t rgb_qemu_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int y_start, int x_end, int y_end, const void *color_data)\n{\n    esp_rgb_qemu_t *rgb_panel = (esp_rgb_qemu_t *) panel;\n    assert((x_start < x_end) && (y_start < y_end) && \"start position must be smaller than end position\");\n    s_rgb_dev->update_from.x = x_start;\n    s_rgb_dev->update_from.y = y_start;\n    /* The rendering WON'T include end (x,y) coordinates  */\n    s_rgb_dev->update_to.x = x_end;\n    s_rgb_dev->update_to.y = y_end;\n    s_rgb_dev->update_content = (void *) color_data;\n    s_rgb_dev->update_st.ena = 1;\n    /* Wait for the driver to finish updating the window to avoid screen tearing effect.\n     * This issue is on the ESP32 QEMU target (making this loop necessary) but not on the ESP32-C3. */\n    while (s_rgb_dev->update_st.ena == 1) {}\n\n    (void) rgb_panel;\n    return ESP_OK;\n}\n\nstatic esp_err_t rgb_qemu_invert_color(esp_lcd_panel_t *panel, bool invert_color_data)\n{\n    return ESP_ERR_NOT_SUPPORTED;\n}\n\nstatic esp_err_t rgb_qemu_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y)\n{\n    return ESP_ERR_NOT_SUPPORTED;\n}\n\nstatic esp_err_t rgb_qemu_swap_xy(esp_lcd_panel_t *panel, bool swap_axes)\n{\n    return ESP_ERR_NOT_SUPPORTED;\n}\n\nstatic esp_err_t rgb_qemu_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap)\n{\n    return ESP_ERR_NOT_SUPPORTED;\n}\n\nstatic esp_err_t rgb_qemu_disp_on_off(esp_lcd_panel_t *panel, bool on_off)\n{\n    return ESP_ERR_NOT_SUPPORTED;\n}\n"
  },
  {
    "path": "esp_lcd_qemu_rgb/src/esp_lcd_qemu_rgb_struct.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdint.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* Organization of the RGB QEMU panel registers */\ntypedef volatile struct rgb_qemu_dev_s {\n    union {\n        struct {\n            uint32_t minor: 16;\n            uint32_t major: 16;\n        };\n        uint32_t val;\n    } version;\n    union {\n        struct {\n            uint32_t height: 16;\n            uint32_t width: 16;\n        };\n        uint32_t val;\n    } size;\n    union {\n        struct {\n            uint32_t y: 16;\n            uint32_t x: 16;\n        };\n        uint32_t val;\n    } update_from;\n    union {\n        struct {\n            uint32_t y: 16;\n            uint32_t x: 16;\n        };\n        uint32_t val;\n    } update_to;\n    /* Address of the buffer containing the new pixels of the area defined above */\n    void *update_content;\n    union {\n        struct {\n            uint32_t ena: 1;\n            uint32_t reserved: 31;\n        };\n        uint32_t val;\n    } update_st;\n    uint32_t bpp;\n} rgb_qemu_dev_t;\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_linenoise/.build-test-rules.yml",
    "content": "esp_linenoise/test_apps:\n  enable:\n    - if: IDF_TARGET == \"linux\"\n      reason: \"Sufficient to test on Linux target\"\n  disable:\n    - if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR <= 4\n      reason: \"those versions of esp-idf do not support eventfd for linux target\"\n\nesp_linenoise/examples/basic_line_reading:\n  enable:\n    - if: IDF_TARGET == \"esp32\"\n      reason: \"Sufficient to run on esp32 target\"\n  disable:\n    - if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR <= 2\n      reason: \"UART component renamed to esp_driver_uart from 5.3 onwards\"\n\nesp_linenoise/examples/history_usage:\n  enable:\n    - if: IDF_TARGET == \"linux\"\n      reason: \"Sufficient to run on linux target\"\n  disable:\n    - if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR <= 4\n      reason: \"those versions of esp-idf do not support eventfd for linux target\"\n\nesp_linenoise/examples/completion:\n  enable:\n    - if: IDF_TARGET == \"esp32\"\n      reason: \"Sufficient to run on esp32 target\"\n  disable:\n    - if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR <= 2\n      reason: \"UART component renamed to esp_driver_uart from 5.3 onwards\"\n\nesp_linenoise/examples/multi_instance:\n  enable:\n    - if: IDF_TARGET == \"esp32\"\n      reason: \"Sufficient to run on esp32 target\"\n  disable:\n    - if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR <= 2\n      reason: \"UART component renamed to esp_driver_uart from 5.3 onwards\""
  },
  {
    "path": "esp_linenoise/CMakeLists.txt",
    "content": "idf_component_register(SRCS\n                        \"linenoise/linenoise.c\"\n                        \"src/esp_linenoise.c\"\n                        \"src/esp_linenoise_internals.c\"\n                       PRIV_INCLUDE_DIRS\n                        \"private_include\"\n                       PRIV_REQUIRES vfs\n                       INCLUDE_DIRS\n                        \"include\"\n                        \".\"\n)\n\n"
  },
  {
    "path": "esp_linenoise/Kconfig",
    "content": "menu \"esp_linenoise configuration\"\n    config ESP_LINENOISE_MAX_INSTANCE_NB\n        int \"Maximum number of esp_linenoise instances that can be created simultaneously\"\n        range 1 32\n        default 5\n        help\n            Specifies the maximum number of esp_linenoise instances that can be created simultaneously.\n            This limitation applies only when esp_linenoise_abort is used, and the following note is\n            relevant in that context.\n\n            A dynamic memory allocation is performed when the first esp_linenoise instance is created and is\n            freed once the last instance is deleted. The allocated memory size is proportional to the value\n            set in this configuration. Therefore, it is recommended to keep this value as low as possible\n            to reduce memory consumption while ensuring the application’s functional requirements are met.\nendmenu\n"
  },
  {
    "path": "esp_linenoise/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright Espressif Systems\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "esp_linenoise/README.md",
    "content": "# esp_linenoise (Multi-Instance Line Editor)\n\n`esp_linenoise` is an enhanced version of the [linenoise](https://github.com/antirez/linenoise) line editing library, adapted for Espressif's IDF Extra Components ecosystem. It now supports **multi-instance usage**, making it ideal for applications that require multiple input contexts—such as multiple UART consoles, shells, or network sessions.\n\n## ✨ Features\n\n- Independent instances\n- Configurable history, prompt, and line-editing behavior per instance\n- Support for completion and hint callbacks\n- IDF-style memory and error handling\n\n## 🛠️ Usage Example\n\n```c\nesp_linenoise_config_t config;\nesp_linenoise_get_instance_config_default(&config);\nesp_linenoise_handle_t handle;\nconst esp_err_t ret = esp_linenoise_create_instance(&config, &handle);\nconst size_t buffer_size = 128;\nchar buffer[128];\nconst char *line = esp_linenoise_get_line(&handle, buffer, buffer_size);\nconst esp_err_t ret_val = esp_linenoise_delete_instance(&handle);\n```\n\n## 📚 API Highlights\n\n| Function | Description |\n|----------|-------------|\n| `esp_linenoise_create_instance()` / `esp_linenoise_delete_instance()` | Create or destroy a linenoise |\n| `esp_linenoise_get_line()` | Read a line from a given instance |\n\nThe user can pass to the configuration structure or set via setter functions, custom read and write functions\nthat will used by esp_linenoise in place of the default read / write.\n\nThe user can provide a custom set of file descriptors that esp_linenoise will use in place of the default\nstandard input file descriptors (STDIN_FILENO, STDOUT_FILENO).\n\nFor full API details, see [`esp_linenoise.h`](https://github.com/espressif/idf-extra-components/blob/master/esp_linenoise/include/esp_linenoise.h).\n\n## 🧪 Build & Test\n\nFor detailed information concerning the integration of idf components into an idf project, please refer to [esp component manager documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html).\n\n## 📄 License\n\nApache 2.0. See `LICENSE` file.\n"
  },
  {
    "path": "esp_linenoise/examples/basic_line_reading/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.22)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(basic_line_reading)"
  },
  {
    "path": "esp_linenoise/examples/basic_line_reading/README.md",
    "content": "# Basic Line Reading Example\n\nThis example demonstrates how to use esp_linenoise to create an instance, read a line of input, and delete the instance.\n\n## Key Features\n- Create a linenoise instance\n- Read a line from the user\n- Delete the instance\n\n## Source\nSee main/basic_line_reading.c for implementation.\n"
  },
  {
    "path": "esp_linenoise/examples/basic_line_reading/main/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.22)\n\nidf_build_get_property(target IDF_TARGET)\nset(priv_requires esp_linenoise)\n\nif(NOT \"${target}\" STREQUAL \"linux\")\n    list(APPEND priv_requires esp_driver_uart)\nendif()\n\nidf_component_register(\n    SRCS \"basic_line_reading.c\" \"../../utils/common_io.c\"\n    INCLUDE_DIRS \".\" \"../../utils\"\n    PRIV_REQUIRES ${priv_requires}\n)\n"
  },
  {
    "path": "esp_linenoise/examples/basic_line_reading/main/basic_line_reading.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include <stdio.h>\n#include \"esp_linenoise.h\"\n#include \"common_io.h\"\n\nvoid app_main(void)\n{\n    common_init_io();\n\n    esp_linenoise_config_t config;\n    esp_linenoise_handle_t handle;\n    esp_linenoise_get_instance_config_default(&config);\n    config.prompt = \"esp_linenoise> \";\n    ESP_ERROR_CHECK(esp_linenoise_create_instance(&config, &handle));\n\n    bool dumb_mode = false;\n    esp_linenoise_is_dumb_mode(handle, &dumb_mode);\n    if (dumb_mode) {\n        printf(\"Running in dumb mode\\n\");\n    } else {\n        printf(\"Running in normal mode\\n\");\n    }\n\n    char buffer[128];\n    const esp_err_t ret_val = esp_linenoise_get_line(handle, buffer, sizeof(buffer));\n    if (ret_val == ESP_OK) {\n        printf(\"You entered: %s\\n\", buffer);\n    } else {\n        printf(\"No input received\\n\");\n    }\n\n    ESP_ERROR_CHECK(esp_linenoise_delete_instance(handle));\n    common_deinit_io();\n\n    printf(\"end of example\\n\");\n}\n"
  },
  {
    "path": "esp_linenoise/examples/basic_line_reading/main/idf_component.yml",
    "content": "dependencies:\n  espressif/esp_linenoise: \"*\"\n"
  },
  {
    "path": "esp_linenoise/examples/basic_line_reading/pytest_basic_line_reading.py",
    "content": "# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.utils import idf_parametrize\nimport glob\nfrom pathlib import Path\n\n\n@pytest.mark.generic\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that did not build\"\n)\n@idf_parametrize('target', ['esp32'], indirect=['target'])\ndef test_examples_basic_line_reading(dut: Dut) -> None:\n    message = \"test_msg\"\n    prompt = \"esp_linenoise> \"\n    dut.expect(prompt, timeout=10)\n    dut.write(message + '\\n')\n    dut.expect(\"end of example\", timeout=10)\n"
  },
  {
    "path": "esp_linenoise/examples/completion/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.22)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(completion)"
  },
  {
    "path": "esp_linenoise/examples/completion/README.md",
    "content": "# esp_linenoise Completion Example\n\nThis example demonstrates how to use esp_linenoise with tab-completion:\n- Register a completion callback function\n- Suggest command completions as the user types\n- Complete commands with the TAB key\n\n## How it works\n- Type the beginning of a command (e.g., \"h\") and press TAB\n- Available completions are displayed or auto-completed\n- Commands: help, history, clear, exit, status, config, reset\n\n## Build & Run\nSee the top-level README for build instructions. This example is portable for ESP-IDF and Linux.\n"
  },
  {
    "path": "esp_linenoise/examples/completion/main/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.22)\n\nidf_build_get_property(target IDF_TARGET)\nset(priv_requires esp_linenoise)\n\nif(NOT \"${target}\" STREQUAL \"linux\")\n    list(APPEND priv_requires esp_driver_uart)\nendif()\n\nidf_component_register(\n    SRCS \"completion.c\" \"../../utils/common_io.c\"\n    INCLUDE_DIRS \".\" \"../../utils\"\n    PRIV_REQUIRES ${priv_requires}\n)"
  },
  {
    "path": "esp_linenoise/examples/completion/main/completion.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include \"common_io.h\"\n#include \"esp_linenoise.h\"\n#include <stdio.h>\n#include <string.h>\n\n// List of commands for completion\nstatic const char *commands[] = {\n    \"help\",\n    \"history\",\n    \"clear\",\n    \"exit\",\n    \"status\",\n    \"config\",\n    \"reset\",\n    NULL\n};\n\n// Completion callback function\nstatic void completion_callback(const char *buf, void *cb_ctx, esp_linenoise_completion_cb_t cb)\n{\n    for (int i = 0; commands[i] != NULL; i++) {\n        if (strncmp(buf, commands[i], strlen(buf)) == 0) {\n            cb(cb_ctx, commands[i]);\n        }\n    }\n}\n\nvoid app_main(void)\n{\n    common_init_io();\n\n    esp_linenoise_config_t config;\n    esp_linenoise_get_instance_config_default(&config);\n    config.prompt = \"completion> \";\n    config.completion_cb = completion_callback;\n\n    esp_linenoise_handle_t handle;\n    esp_err_t err = esp_linenoise_create_instance(&config, &handle);\n    if (err != ESP_OK) {\n        printf(\"Failed to create linenoise instance\\n\");\n        return;\n    }\n\n    printf(\"Tab completion example. Try typing 'h' and press TAB.\\n\");\n    printf(\"Available commands: help, history, clear, exit, status, config, reset\\n\");\n\n    char line[256];\n    while (1) {\n        err = esp_linenoise_get_line(handle, line, sizeof(line));\n        if (err != ESP_OK) {\n            break;\n        }\n\n        if (strlen(line) > 0) {\n            printf(\"You entered: %s\\n\", line);\n            esp_linenoise_history_add(handle, line);\n\n            if (strcmp(line, \"exit\") == 0) {\n                break;\n            }\n        }\n    }\n\n    esp_linenoise_delete_instance(handle);\n    common_deinit_io();\n\n    printf(\"end of example\\n\");\n}\n"
  },
  {
    "path": "esp_linenoise/examples/completion/main/idf_component.yml",
    "content": "dependencies:\n  espressif/esp_linenoise: \"*\"\n"
  },
  {
    "path": "esp_linenoise/examples/completion/pytest_completion.py",
    "content": "# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.utils import idf_parametrize\nimport glob\nfrom pathlib import Path\n\n\n@pytest.mark.generic\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that did not build\"\n)\n@idf_parametrize('target', ['esp32'], indirect=['target'])\ndef test_examples_completion(dut: Dut) -> None:\n    message = \"exit\"\n    prompt = \"completion> \"\n    dut.expect(prompt, timeout=10)\n    dut.write(message + '\\n')\n    dut.expect(\"end of example\", timeout=10)\n"
  },
  {
    "path": "esp_linenoise/examples/history_usage/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.22)\n\n# Use custom partition table for SPIFFS storage (ESP32 targets only)\nif(NOT \"$ENV{IDF_TARGET}\" STREQUAL \"linux\")\n    set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/components/spiffs)\n    set(SDKCONFIG_DEFAULTS \"sdkconfig.defaults\")\nendif()\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(history_usage)"
  },
  {
    "path": "esp_linenoise/examples/history_usage/README.md",
    "content": "# esp_linenoise History Usage Example\n\nThis example demonstrates how to use esp_linenoise with input history:\n- Enable and configure history length\n- Load and save history to a file\n- Add new entries to history after each input\n\n## How it works\n- Prompts the user for input with `history> `\n- After each line, adds it to the history and saves to disk\n- Loads history from disk on startup\n\n## Build & Run\nSee the top-level README for build instructions. This example is portable for ESP-IDF and Linux.\n"
  },
  {
    "path": "esp_linenoise/examples/history_usage/main/CMakeLists.txt",
    "content": "idf_build_get_property(target IDF_TARGET)\nset(priv_requires esp_linenoise)\n\nif(NOT \"${target}\" STREQUAL \"linux\")\n    list(APPEND priv_requires spiffs)\nendif()\n\nidf_component_register(\n    SRCS \"history_usage.c\"\n    INCLUDE_DIRS \".\"\n    PRIV_REQUIRES ${priv_requires}\n)\n"
  },
  {
    "path": "esp_linenoise/examples/history_usage/main/history_usage.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include \"esp_linenoise.h\"\n#include <stdio.h>\n#include <stdlib.h>\n\n#if CONFIG_IDF_TARGET_LINUX\n#define HISTORY_PATH \"linenoise_history.txt\"\n#else\n#include \"esp_spiffs.h\"\n#define STORAGE_MOUNT_POINT \"/storage\"\n#define HISTORY_PATH STORAGE_MOUNT_POINT \"/linenoise_history.txt\"\n#endif\n\n#define HISTORY_LEN 10\n\n#if !CONFIG_IDF_TARGET_LINUX\nstatic void init_filesystem(void)\n{\n    esp_vfs_spiffs_conf_t conf = {\n        .base_path = STORAGE_MOUNT_POINT,\n        .partition_label = \"storage\",\n        .max_files = 2,\n        .format_if_mount_failed = true,\n    };\n\n    esp_err_t ret = esp_vfs_spiffs_register(&conf);\n    if (ret != ESP_OK) {\n        if (ret == ESP_FAIL) {\n            printf(\"Failed to mount or format filesystem\\n\");\n        } else if (ret == ESP_ERR_NOT_FOUND) {\n            printf(\"Failed to find SPIFFS partition\\n\");\n        } else {\n            printf(\"Failed to initialize SPIFFS (%s)\\n\", esp_err_to_name(ret));\n        }\n        return;\n    }\n\n    size_t total = 0, used = 0;\n    ret = esp_spiffs_info(\"storage\", &total, &used);\n    if (ret == ESP_OK) {\n        printf(\"SPIFFS partition size: total: %d, used: %d\\n\", total, used);\n    }\n}\n#endif\n\nvoid app_main(void)\n{\n#if !CONFIG_IDF_TARGET_LINUX\n    init_filesystem();\n#endif\n\n    esp_linenoise_config_t config;\n    esp_linenoise_handle_t handle;\n    esp_linenoise_get_instance_config_default(&config);\n    config.prompt = \"esp_linenoise> \";\n    ESP_ERROR_CHECK(esp_linenoise_create_instance(&config, &handle));\n\n    /* create a fake history saved in filename_history */\n    FILE *fp = fopen(HISTORY_PATH, \"w\");\n    if (fp == NULL) {\n        printf(\"Failed to create history file\\n\");\n        return;\n    }\n    fputs(\"first command line\\n\", fp);\n    fputs(\"second command line\\n\", fp);\n    fclose(fp);\n\n    ESP_ERROR_CHECK(esp_linenoise_history_set_max_len(handle, HISTORY_LEN));\n    ESP_ERROR_CHECK(esp_linenoise_history_load(handle,  HISTORY_PATH));\n\n    ESP_ERROR_CHECK(esp_linenoise_history_add(handle, \"random command line 1\"));\n    ESP_ERROR_CHECK(esp_linenoise_history_add(handle, \"random command line 2\"));\n    ESP_ERROR_CHECK(esp_linenoise_history_save(handle, HISTORY_PATH));\n\n    fp = fopen(HISTORY_PATH, \"r\");\n    if (fp == NULL) {\n        printf(\"Failed to create history file\\n\");\n        return;\n    }\n\n    char buffer[64];\n    while (fgets(buffer, sizeof(buffer), fp) != NULL) {\n        printf(\"History entry: %s\", buffer);\n    }\n    fclose(fp);\n\n    printf(\"end of example\\n\");\n}\n"
  },
  {
    "path": "esp_linenoise/examples/history_usage/main/idf_component.yml",
    "content": "dependencies:\n  espressif/esp_linenoise: \"*\"\n"
  },
  {
    "path": "esp_linenoise/examples/history_usage/partitions.csv",
    "content": "# Name,   Type, SubType, Offset,  Size, Flags\nnvs,      data, nvs,     0x9000,  0x6000,\nphy_init, data, phy,     0xf000,  0x1000,\nfactory,  app,  factory, 0x10000, 1M,\nstorage,  data, spiffs,  ,        0x10000,\n"
  },
  {
    "path": "esp_linenoise/examples/history_usage/pytest_history_usage.py",
    "content": "# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.utils import idf_parametrize\nimport glob\nfrom pathlib import Path\n\n\n@pytest.mark.host_test\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that did not build\"\n)\n@idf_parametrize('target', ['linux'], indirect=['target'])\ndef test_examples_history_usage(dut: Dut) -> None:\n    dut.expect(\"end of example\", timeout=10)\n"
  },
  {
    "path": "esp_linenoise/examples/history_usage/sdkconfig.defaults",
    "content": ""
  },
  {
    "path": "esp_linenoise/examples/history_usage/sdkconfig.defaults.esp32",
    "content": "# Use custom partition table with SPIFFS partition\nCONFIG_PARTITION_TABLE_CUSTOM=y\nCONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions.csv\"\n"
  },
  {
    "path": "esp_linenoise/examples/multi_instance/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.22)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(multi_instance)"
  },
  {
    "path": "esp_linenoise/examples/multi_instance/README.md",
    "content": "# esp_linenoise Multi-Instance Example\n\nThis example demonstrates how to use multiple esp_linenoise instances:\n- Create separate instances with different configurations\n- Maintain independent history for each instance\n- Switch between instances at runtime\n- Save separate history files for each context\n\n## How it works\n- Two instances are created: \"user\" and \"admin\"\n- Type commands in either mode\n- Type 'switch' to toggle between user and admin mode\n- Each mode maintains its own command history\n- Type 'exit' to quit\n\n## Build & Run\nSee the top-level README for build instructions. This example is portable for ESP-IDF and Linux.\n"
  },
  {
    "path": "esp_linenoise/examples/multi_instance/main/CMakeLists.txt",
    "content": "\nidf_build_get_property(target IDF_TARGET)\nset(priv_requires esp_linenoise)\n\nif(NOT \"${target}\" STREQUAL \"linux\")\n    list(APPEND priv_requires esp_driver_uart vfs)\nendif()\n\nidf_component_register(\n    SRCS \"multi_instance.c\" \"../../utils/common_io.c\"\n    INCLUDE_DIRS \".\" \"../../utils\"\n    PRIV_REQUIRES ${priv_requires}\n)\n"
  },
  {
    "path": "esp_linenoise/examples/multi_instance/main/idf_component.yml",
    "content": "dependencies:\n  espressif/esp_linenoise: \"*\"\n"
  },
  {
    "path": "esp_linenoise/examples/multi_instance/main/multi_instance.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include \"common_io.h\"\n#include \"esp_linenoise.h\"\n#include <stdio.h>\n#include <string.h>\n\n#define HISTORY_PATH_1 \"history_instance1.txt\"\n#define HISTORY_PATH_2 \"history_instance2.txt\"\n#define HISTORY_LEN 5\n\nvoid app_main(void)\n{\n    common_init_io();\n\n    // Create first instance for \"user\" commands\n    esp_linenoise_config_t config1;\n    esp_linenoise_get_instance_config_default(&config1);\n    config1.prompt = \"user> \";\n    config1.history_max_length = HISTORY_LEN;\n\n    esp_linenoise_handle_t handle1;\n    esp_err_t err = esp_linenoise_create_instance(&config1, &handle1);\n    if (err != ESP_OK) {\n        printf(\"Failed to create first linenoise instance\\n\");\n        return;\n    }\n\n    // Create second instance for \"admin\" commands\n    esp_linenoise_config_t config2;\n    esp_linenoise_get_instance_config_default(&config2);\n    config2.prompt = \"admin> \";\n    config2.history_max_length = HISTORY_LEN;\n\n    esp_linenoise_handle_t handle2;\n    err = esp_linenoise_create_instance(&config2, &handle2);\n    if (err != ESP_OK) {\n        printf(\"Failed to create second linenoise instance\\n\");\n        esp_linenoise_delete_instance(handle1);\n        return;\n    }\n\n    char line[256];\n    bool use_first = true;\n\n    while (1) {\n        esp_linenoise_handle_t current_handle = use_first ? handle1 : handle2;\n        const char *mode = use_first ? \"user\" : \"admin\";\n\n        printf(\"Current mode: %s\\n\", mode);\n        err = esp_linenoise_get_line(current_handle, line, sizeof(line));\n        if (err != ESP_OK) {\n            break;\n        }\n\n        if (strlen(line) > 0) {\n            if (strcmp(line, \"exit\") == 0) {\n                break;\n            } else if (strcmp(line, \"switch\") == 0) {\n                use_first = !use_first;\n                printf(\"Switched to %s mode\\n\\n\", use_first ? \"user\" : \"admin\");\n            } else {\n                printf(\"[%s] You entered: %s\\n\", mode, line);\n                esp_linenoise_history_add(current_handle, line);\n            }\n        }\n\n        memset(line, 0, sizeof(line));\n    }\n\n    // Save separate histories\n    esp_linenoise_history_save(handle1, HISTORY_PATH_1);\n    esp_linenoise_history_save(handle2, HISTORY_PATH_2);\n\n    // Cleanup\n    esp_linenoise_delete_instance(handle1);\n    esp_linenoise_delete_instance(handle2);\n    common_deinit_io();\n\n    printf(\"end of example\\n\");\n}\n"
  },
  {
    "path": "esp_linenoise/examples/multi_instance/pytest_multi_instance.py",
    "content": "# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.utils import idf_parametrize\nimport glob\nfrom pathlib import Path\n\n\n@pytest.mark.generic\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that did not build\"\n)\n@idf_parametrize('target', ['esp32'], indirect=['target'])\ndef test_examples_multi_instance(dut: Dut) -> None:\n    dut.expect_exact(\"Current mode: user\", timeout=10)\n    dut.write(\"test\")\n    dut.expect_exact(\"Current mode: user\", timeout=10)\n    dut.write(\"switch\")\n    dut.expect_exact(\"Current mode: admin\", timeout=10)\n    dut.write(\"test\")\n    dut.expect_exact(\"Current mode: admin\", timeout=10)\n    dut.write(\"exit\")\n    dut.expect_exact(\"end of example\", timeout=10)\n"
  },
  {
    "path": "esp_linenoise/examples/utils/README.md",
    "content": "# Common I/O for esp_linenoise Examples\n\nThis folder provides functions to configure and select the input/output file descriptors for esp_linenoise examples.\n- On ESP-IDF, it configures UART for use with linenoise.\n- On Linux, it uses default stdin/stdout.\n\n## Usage\nInclude common_io.h in your example and use:\n- esp_linenoise_get_default_in_fd()\n- esp_linenoise_get_default_out_fd()\n- esp_linenoise_configure_uart() (ESP-IDF only)\n\nThis ensures all examples work on both ESP-IDF and Linux environments.\n"
  },
  {
    "path": "esp_linenoise/examples/utils/common_io.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include \"sdkconfig.h\"\n#include <stdio.h>\n#include <unistd.h>\n#include <string.h>\n#include \"common_io.h\"\n\n#if !CONFIG_IDF_TARGET_LINUX\n#include \"driver/uart.h\"\n#include \"driver/uart_vfs.h\"\n#include \"esp_vfs_dev.h\"\n#include \"esp_log.h\"\n\nstatic int s_uart_fd = -1;\n#endif // !CONFIG_IDF_TARGET_LINUX\n\n// init UART and VFS, and set up stdin/stdout to use UART0 as POSIX fd\nvoid common_init_io(void)\n{\n#ifndef CONFIG_IDF_TARGET_LINUX\n    const uart_config_t uart_config = {\n        .baud_rate = 115200,\n        .data_bits = UART_DATA_8_BITS,\n        .parity    = UART_PARITY_DISABLE,\n        .stop_bits = UART_STOP_BITS_1,\n        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE\n    };\n    uart_param_config(UART_NUM_0, &uart_config);\n    uart_driver_install(UART_NUM_0, 1024, 0, 0, NULL, 0);\n    uart_vfs_dev_use_driver(UART_NUM_0);\n    s_uart_fd = fileno(stdin); // stdin now routed to UART0\n#endif\n}\n\n// Deinit UART and VFS routing used by esp_linenoise examples\nvoid common_deinit_io(void)\n{\n#ifndef CONFIG_IDF_TARGET_LINUX\n    if (s_uart_fd >= 0) {\n        uart_vfs_dev_use_nonblocking(UART_NUM_0);\n        uart_driver_delete(UART_NUM_0);\n        s_uart_fd = -1;\n    }\n#endif\n}\n\n// Return a POSIX fd for UART (ESP-IDF only)\nint common_open_uart_fd(void)\n{\n#ifndef CONFIG_IDF_TARGET_LINUX\n    if (s_uart_fd < 0) {\n        common_init_io();\n    }\n    return s_uart_fd;\n#else\n    return fileno(stdin);\n#endif\n}\n\n// Portable input fd for linenoise\nint common_get_default_in_fd(void)\n{\n#ifndef CONFIG_IDF_TARGET_LINUX\n    return common_open_uart_fd();\n#else\n    return fileno(stdin);\n#endif\n}\n\n// Portable output fd for linenoise\nint common_get_default_out_fd(void)\n{\n#ifndef CONFIG_IDF_TARGET_LINUX\n    return common_open_uart_fd();\n#else\n    return fileno(stdout);\n#endif\n}\n"
  },
  {
    "path": "esp_linenoise/examples/utils/common_io.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief Initialize common I/O functionality.\n *\n * This function performs the necessary initialization for common I/O operations.\n * It should be called before using any I/O related functions in the application.\n */\nvoid common_init_io(void);\n\n/**\n * @brief Deinitialize common I/O functionality.\n *\n * This function performs the necessary cleanup for common I/O operations.\n * It should be called when the application is done using any I/O related functions.\n */\nvoid common_deinit_io(void);\n\n/**\n * @brief Return a POSIX fd for UART (ESP-IDF only)\n */\nint common_open_uart_fd(void);\n\n/**\n * @brief Return a portable input fd for linenoise\n */\nint common_get_default_in_fd(void);\n\n/**\n * @brief Return a portable output fd for linenoise\n */\nint common_get_default_out_fd(void);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_linenoise/idf_component.yml",
    "content": "version: \"1.0.4\"\ndescription: \"ESP Linenoise - Line editing C library\"\nurl: https://github.com/espressif/idf-extra-components/tree/master/esp_linenoise\nlicense: Apache-2.0\nsbom:\n  manifests:\n    - path: sbom_esp_linenoise.yml\n      dest: ."
  },
  {
    "path": "esp_linenoise/include/esp_linenoise.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <sys/types.h>\n#include <unistd.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include \"esp_err.h\"\n\n/*\n * IMPORTANT: This library is not thread safe.\n * Multiple threads operating on one esp_linenoise instance\n * can yield unexpected behavior from the esp_linenoise library.\n *\n * An esp_linenoise instance is to be used by one thread only.\n */\n\n/**\n * @brief Callback type used to report a completion candidate to esp_linenoise\n *\n * This callback is invoked by `esp_linenoise_completion_t` for each possible\n * completion string.\n *\n * @note When esp_linenoise calls `esp_linenoise_completion_t`, it provides\n * `esp_linenoise_add_completion` as the `esp_linenoise_completion_cb_t`.\n * This allows user code to return completion candidates back into\n * esp_linenoise.\n *\n * @note esp_linenoise also passes an opaque pointer of type\n * `esp_linenoise_completions_t` as the `cb_ctx`. User code must forward\n * this `cb_ctx` unchanged when invoking the callback. This design hides\n * the internal structure of esp_linenoise from the user.\n *\n * @param cb_ctx Opaque context pointer provided by esp_linenoise. Must be\n *               passed unchanged when calling the callback.\n * @param str A candidate completion string.\n */\ntypedef void (*esp_linenoise_completion_cb_t)(void *cb_ctx, const char *str);\n\n/**\n * @brief User-provided callback type for generating command completions.\n *\n * This function is called by esp_linenoise when the user requests tab\n * completion. The implementation should analyze the input string and invoke\n * the provided completion callback (`cb`) for each possible completion.\n *\n * configuration. Allows the completion function to access application-specific state.\n * @param str The current input string typed by the user.\n * @param cb_ctx Opaque pointer provided by esp_linenoise. This must be\n * forwarded unchanged when calling the completion callback.\n * @param cb Callback function to be invoked once for each candidate\n * completion string discovered by this function.\n */\ntypedef void (*esp_linenoise_completion_t)(const char *str, void *cb_ctx, esp_linenoise_completion_cb_t cb);\n\n/**\n * @brief Callback function for providing inline hints during input.\n *\n * @param str Input string from the user.\n * @param color Pointer to an integer to set the hint text color (e.g., ANSI color code).\n * @param bold Pointer to an integer to set bold attribute (non-zero for bold).\n * @return A dynamically allocated hint string, or NULL if no hint is available.\n */\ntypedef char *(*esp_linenoise_hints_t)(const char *str, int *color, int *bold);\n\n/**\n * @brief Callback function to free hint strings returned by the hints callback.\n *\n * @param ptr Pointer to the hint string to be freed.\n */\ntypedef void (*esp_linenoise_free_hints_t)( void *ptr);\n\n/**\n * @brief Function pointer type for reading bytes.\n *\n * @param fd File descriptor.\n * @param buf Buffer to store the read bytes.\n * @param count Number of bytes to read.\n * @return Number of bytes read, or -1 on error.\n */\ntypedef ssize_t (*esp_linenoise_read_bytes_t)(int fd, void *buf, size_t count);\n\n/**\n * @brief Function pointer type for writing bytes.\n *\n * @param fd File descriptor.\n * @param buf Buffer containing bytes to write.\n * @param count Number of bytes to write.\n * @return Number of bytes written, or -1 on error.\n */\ntypedef ssize_t (*esp_linenoise_write_bytes_t)(int fd, const void *buf, size_t count);\n\n/**\n * @brief Structure defining the parameters needed by a linenoise\n * instance\n */\ntypedef struct esp_linenoise_config {\n    const char *prompt; /*!< Prompt string displayed to the user */\n    size_t max_cmd_line_length; /*!< Maximum length (in bytes) of the input command line */\n    int history_max_length; /*!< Maximum number of entries to store in command history */\n    int in_fd; /*!< File descriptor to read input from (e.g., STDIN_FILENO) */\n    int out_fd; /*!< File descriptor to write output to (e.g., STDOUT_FILENO) */\n    bool allow_multi_line; /*!< Whether to allow multi-line input (true to enable) */\n    bool allow_empty_line; /*!< Whether to allow accepting an empty line as valid input */\n    bool allow_dumb_mode; /*!< Whether to allow running in dumb terminal mode (without advanced features) */\n    esp_linenoise_completion_t completion_cb; /*!< Callback function for handling input completions */\n    esp_linenoise_hints_t hints_cb; /*!< Callback function to provide input hints (e.g., usage suggestions) */\n    esp_linenoise_free_hints_t free_hints_cb; /*!< Callback function to free hints returned by `hints_cb` */\n    esp_linenoise_read_bytes_t read_bytes_cb; /*!< Function used to read bytes from the input stream */\n    esp_linenoise_write_bytes_t write_bytes_cb; /*!< Function used to write bytes to the output stream */\n    char **history; /*!< Pointer to the history buffer (used internally; typically initialized to NULL) */\n} esp_linenoise_config_t;\n\n/**\n * @brief Opaque handle to a linenoise instance.\n */\ntypedef struct esp_linenoise_instance *esp_linenoise_handle_t;\n\n/**\n * @brief Probe the terminal to check weather it supports escape sequences\n *\n * @param handle The linenoise handle used to check\n * @return int 0 if the terminal supports escape sequences\n */\nint esp_linenoise_probe(esp_linenoise_handle_t handle);\n\n/**\n * @brief Returns the default parameters for creating a linenoise instance.\n *\n * @param[out] config esp_linenoise_config_t structure to populate with default values.\n */\nvoid esp_linenoise_get_instance_config_default(esp_linenoise_config_t *config);\n\n/**\n * @brief Creates a new linenoise instance.\n *\n * @param config Pointer to the configuration parameters for the instance.\n * @param[out] out_handle Handle to the created instance, or NULL on failure.\n * @return ESP_OK if instance created successfully,\n */\nesp_err_t esp_linenoise_create_instance(const esp_linenoise_config_t *config, esp_linenoise_handle_t *out_handle);\n\n/**\n * @brief Destroys a linenoise instance and frees associated memory.\n *\n * @param handle Handle to the instance to delete.\n * @return ESP_OK on success, or error code on failure.\n */\nesp_err_t esp_linenoise_delete_instance(esp_linenoise_handle_t handle);\n\n/**\n * @brief Reads a line of input from the user into a buffer.\n *\n * @note In the event where the input line matches or exceeds\n * the size of the buffer passed in parameter, the function\n * will stop registering newly received characters until new line\n * is received. Then, the function will return cmd_line_length - 1\n * characters (the last character being the nullterm '\\0')\n * This behavior applies whether the dumb mode is on or off.\n *\n * @param handle Handle to the linenoise instance.\n * @param cmd_line_buffer Buffer to store the input line.\n * @param cmd_line_length Length of the command line buffer.\n * @return ESP_OK on success.\n *         ESP_FAIL if empty line returned and allow_empty_line is set to false.\n *         ESP_ERR_INVALID_ARG if cmd_line_buffer is NULL or cmd_line_length\n *         is equal to 0 or superior to the value of max_cmd_line_length.\n */\nesp_err_t esp_linenoise_get_line(esp_linenoise_handle_t handle, char *cmd_line_buffer, size_t cmd_line_length);\n\n/**\n * @brief Triggers an internal mechanism to return from esp_linenoise_get_line.\n *\n * @note This function has no effect if the field read_bytes_cb of\n * esp_linenoise_config_t is populate with a custom read function.\n * In that case, it is the user responsibility to handle the way to\n * return from the custom read it provided to linenoise.\n *\n * @param handle Handle to the linenoise instance.\n * @return esp_err_t ESP_OK on success, other on failures.\n */\nesp_err_t esp_linenoise_abort(esp_linenoise_handle_t handle);\n\n/**\n * @brief Adds a line to the instance's history.\n *\n * @param handle Handle to the linenoise instance.\n * @param line The line to add to history.\n * @return ESP_OK on success, or error code on failure.\n */\nesp_err_t esp_linenoise_history_add(esp_linenoise_handle_t handle, const char *line);\n\n/**\n * @brief Saves the history to a file.\n *\n * @param handle Handle to the linenoise instance.\n * @param filename Path to the history file.\n * @return ESP_OK on success, or error code on failure.\n */\nesp_err_t esp_linenoise_history_save(esp_linenoise_handle_t handle, const char *filename);\n\n/**\n * @brief Loads history from a file.\n *\n * @param handle Handle to the linenoise instance.\n * @param filename Path to the history file.\n * @return ESP_OK on success, or error code on failure.\n */\nesp_err_t esp_linenoise_history_load(esp_linenoise_handle_t handle, const char *filename);\n\n/**\n * @brief Sets the maximum number of entries in the history.\n *\n * @param handle Handle to the linenoise instance.\n * @param len Maximum number of entries.\n * @return ESP_OK on success, or error code on failure.\n */\nesp_err_t esp_linenoise_history_set_max_len(esp_linenoise_handle_t handle, int len);\n\n/**\n * @brief Frees the history associated with the instance.\n *\n * @param handle Handle to the linenoise instance.\n * @return ESP_OK on success, or error code on failure.\n */\nesp_err_t esp_linenoise_history_free(esp_linenoise_handle_t handle);\n\n/**\n * @brief Clears the terminal screen for the instance.\n *\n * @param handle Handle to the linenoise instance.\n * @return ESP_OK on success, or error code on failure.\n */\nesp_err_t esp_linenoise_clear_screen(esp_linenoise_handle_t handle);\n\n/**\n * @brief Sets whether an empty line is allowed to be returned.\n *\n * @param handle Handle to the linenoise instance.\n * @param empty_line true to allow empty lines, false to disallow.\n * @return ESP_OK on success, or error code on failure.\n */\nesp_err_t esp_linenoise_set_empty_line(esp_linenoise_handle_t handle, bool empty_line);\n\n/**\n * @brief Checks whether the instance allows returning an empty line.\n *\n * @param handle Handle to the linenoise instance.\n * @param is_empty_line Pointer to bool that will be set with result.\n * @return ESP_OK on success, or error code on failure.\n */\nesp_err_t esp_linenoise_is_empty_line(esp_linenoise_handle_t handle, bool *is_empty_line);\n\n/**\n * @brief Enables or disables multi-line editing.\n *\n * @param handle Handle to the linenoise instance.\n * @param multi_line true to enable multi-line input, false to disable.\n * @return ESP_OK on success, or error code on failure.\n */\nesp_err_t esp_linenoise_set_multi_line(esp_linenoise_handle_t handle, bool multi_line);\n\n/**\n * @brief Checks if multi-line editing is enabled.\n *\n * @param handle Handle to the linenoise instance.\n * @param is_multi_line Pointer to bool that will be set with result.\n * @return ESP_OK on success, or error code on failure.\n */\nesp_err_t esp_linenoise_is_multi_line(esp_linenoise_handle_t handle, bool *is_multi_line);\n\n/**\n * @brief Enables or disables dumb mode (disables line editing features).\n *\n * @param handle Handle to the linenoise instance.\n * @param dumb_mode true to enable dumb mode, false to disable.\n * @return ESP_OK on success, or error code on failure.\n */\nesp_err_t esp_linenoise_set_dumb_mode(esp_linenoise_handle_t handle, bool dumb_mode);\n\n/**\n * @brief Checks if dumb mode is enabled.\n *\n * @param handle Handle to the linenoise instance.\n * @param is_dumb_mode Pointer to bool that will be set with result.\n * @return ESP_OK on success, or error code on failure.\n */\nesp_err_t esp_linenoise_is_dumb_mode(esp_linenoise_handle_t handle, bool *is_dumb_mode);\n\n/**\n * @brief Sets the maximum length of the command line buffer.\n *\n * @param handle Handle to the linenoise instance.\n * @param length Maximum length in bytes.\n * @return ESP_OK on success, or error code on failure.\n */\nesp_err_t esp_linenoise_set_max_cmd_line_length(esp_linenoise_handle_t handle, size_t length);\n\n/**\n * @brief Gets the maximum allowed command line buffer length.\n *\n * @param handle Handle to the linenoise instance.\n * @param max_cmd_line_length Pointer to receive the max length.\n * @return ESP_OK on success, or error code on failure.\n */\nesp_err_t esp_linenoise_get_max_cmd_line_length(esp_linenoise_handle_t handle, size_t *max_cmd_line_length);\n\n/**\n * @brief Sets the prompt used by the esp_linenoise instance.\n *\n * @param handle Handle to the linenoise instance.\n * @param prompt Prompt to be set.\n * @return ESP_OK on success, or error code on failure.\n */\nesp_err_t esp_linenoise_set_prompt(esp_linenoise_handle_t handle, const char *prompt);\n\n/**\n * @brief Gets the current esp_linenoise instance prompt.\n *\n * @param handle Handle to the linenoise instance.\n * @param prompt esp_linenoise instance current prompt.\n * @return ESP_OK on success, or error code on failure.\n */\nesp_err_t esp_linenoise_get_prompt(esp_linenoise_handle_t handle, const char **prompt);\n\n/**\n * @brief Return the output file descriptor used by esp_linenoise\n *\n * @param handle The esp_linenoise handle from which to get\n * the file descriptor\n * @param fd Return value containing the output file descriptor\n * @return ESP_OK on success, ESP_ERR_INVALID_ARG otherwise\n */\nesp_err_t esp_linenoise_get_out_fd(esp_linenoise_handle_t handle, int *fd);\n\n/**\n * @brief Return the input file descriptor used by esp_linenoise\n *\n * @param handle The esp_linenoise handle from which to get\n * the file descriptor\n * @param fd Return value containing the input file descriptor\n * @return ESP_OK on success, ESP_ERR_INVALID_ARG otherwise\n */\nesp_err_t esp_linenoise_get_in_fd(esp_linenoise_handle_t handle, int *fd);\n\n/**\n * @brief Return the read function used by linenoise\n *\n * @param handle The esp_linenoise handle from which to get\n * the file descriptor\n * @param read_func Return the read_func as set in the configuration structure\n * of the given esp_linenoise instance\n * @return ESP_OK on success, ESP_ERR_INVALID_ARG otherwise\n */\nesp_err_t esp_linenoise_get_read(esp_linenoise_handle_t handle, esp_linenoise_read_bytes_t *read_func);\n\n/**\n * @brief Return the write function used by linenoise\n *\n * @param handle The esp_linenoise handle from which to get\n * the file descriptor\n * @param write_func Return the write_func as set in the configuration structure\n * of the given esp_linenoise instance\n * @return ESP_OK on success, ESP_ERR_INVALID_ARG otherwise\n */\nesp_err_t esp_linenoise_get_write(esp_linenoise_handle_t handle, esp_linenoise_write_bytes_t *write_func);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_linenoise/linenoise/linenoise.c",
    "content": "/* linenoise.c -- guerrilla line editing library against the idea that a\n * line editing lib needs to be 20,000 lines of C code.\n *\n * You can find the latest source code at:\n *\n *   http://github.com/antirez/linenoise\n *\n * Does a number of crazy assumptions that happen to be true in 99.9999% of\n * the 2010 UNIX computers around.\n *\n * ------------------------------------------------------------------------\n *\n * Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com>\n * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *  *  Redistributions of source code must retain the above copyright\n *     notice, this list of conditions and the following disclaimer.\n *\n *  *  Redistributions in binary form must reproduce the above copyright\n *     notice, this list of conditions and the following disclaimer in the\n *     documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n * ------------------------------------------------------------------------\n *\n * References:\n * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html\n * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html\n *\n * Todo list:\n * - Filter bogus Ctrl+<char> combinations.\n * - Win32 support\n *\n * Bloat:\n * - History search like Ctrl+r in readline?\n *\n * List of escape sequences used by this program, we do everything just\n * with three sequences. In order to be so cheap we may have some\n * flickering effect with some slow terminal, but the lesser sequences\n * the more compatible.\n *\n * EL (Erase Line)\n *    Sequence: ESC [ n K\n *    Effect: if n is 0 or missing, clear from cursor to end of line\n *    Effect: if n is 1, clear from beginning of line to cursor\n *    Effect: if n is 2, clear entire line\n *\n * CUF (CUrsor Forward)\n *    Sequence: ESC [ n C\n *    Effect: moves cursor forward n chars\n *\n * CUB (CUrsor Backward)\n *    Sequence: ESC [ n D\n *    Effect: moves cursor backward n chars\n *\n * The following is used to get the terminal width if getting\n * the width with the TIOCGWINSZ ioctl fails\n *\n * DSR (Device Status Report)\n *    Sequence: ESC [ 6 n\n *    Effect: reports the current cusor position as ESC [ n ; m R\n *            where n is the row and m is the column\n *\n * When multi line mode is enabled, we also use an additional escape\n * sequence. However multi line editing is disabled by default.\n *\n * CUU (Cursor Up)\n *    Sequence: ESC [ n A\n *    Effect: moves cursor up of n chars.\n *\n * CUD (Cursor Down)\n *    Sequence: ESC [ n B\n *    Effect: moves cursor down of n chars.\n *\n * When linenoiseClearScreen() is called, two additional escape sequences\n * are used in order to clear the screen and position the cursor at home\n * position.\n *\n * CUP (Cursor position)\n *    Sequence: ESC [ H\n *    Effect: moves the cursor to upper left corner\n *\n * ED (Erase display)\n *    Sequence: ESC [ 2 J\n *    Effect: clear the whole screen\n *\n */\n\n#include <fcntl.h>\n#include \"esp_linenoise_private.h\"\n#include \"esp_linenoise.h\"\n#include \"linenoise.h\"\n#include \"esp_err.h\"\n\nstatic esp_linenoise_instance_t *s_linenoise_instance = NULL;\nstatic linenoiseCompletionCallback *s_completion_cb = NULL;\n\nstatic void completion_default_cb(const char *str, void *cb_ctx, esp_linenoise_completion_cb_t cb)\n{\n    /* unused because incompatible with legacy code */\n    (void)cb;\n\n    if (!s_completion_cb) {\n        return;\n    }\n    s_completion_cb(str, (linenoiseCompletions *)cb_ctx);\n}\n\nstatic inline __attribute__((always_inline))\nesp_linenoise_instance_t *linenoise_get_static_instance(void)\n{\n    if (!s_linenoise_instance) {\n        s_linenoise_instance = esp_linenoise_create_instance_static();\n    }\n    return s_linenoise_instance;\n}\n\n__attribute__((weak)) void linenoiseSetReadCharacteristics(void)\n{\n    linenoiseSetReadFunction(read);\n\n    /* By default linenoise uses blocking reads */\n    int fd_in = s_linenoise_instance->config.in_fd;\n    int flags = fcntl(fd_in, F_GETFL);\n    flags &= ~O_NONBLOCK;\n    (void)fcntl(fd_in, F_SETFL, flags);\n}\n\nvoid linenoiseAddCompletion(linenoiseCompletions *lc, const char *str)\n{\n    esp_linenoise_add_completion(lc, str);\n}\n\nvoid linenoiseSetMultiLine(int ml)\n{\n    esp_linenoise_instance_t *instance = linenoise_get_static_instance();\n    /* since we get the static instance, the input validation will always\n     * yield a positive result, it is not necessary to check the return value */\n    (void)esp_linenoise_set_multi_line(instance, (bool)ml);\n}\n\nvoid linenoiseSetDumbMode(int set)\n{\n    esp_linenoise_instance_t *instance = linenoise_get_static_instance();\n    /* since we get the static instance, the input validation will always\n     * yield a positive result, it is not necessary to check the return value */\n    (void)esp_linenoise_set_dumb_mode(instance, (bool)set);\n}\n\nbool linenoiseIsDumbMode(void)\n{\n    esp_linenoise_instance_t *instance = linenoise_get_static_instance();\n    bool is_dump_mode = false;\n    /* since we get the static instance, the input validation will always\n     * yield a positive result, it is not necessary to check the return value */\n    (void)esp_linenoise_is_dumb_mode(instance, &is_dump_mode);\n    return is_dump_mode;\n}\n\nvoid linenoiseAllowEmpty(bool val)\n{\n    esp_linenoise_instance_t *instance = linenoise_get_static_instance();\n    /* since we get the static instance, the input validation will always\n     * yield a positive result, it is not necessary to check the return value */\n    (void)esp_linenoise_set_empty_line(instance, (bool)val);\n}\n\nvoid linenoiseSetWriteFunction(linenoiseWriteBytesFn write_fn)\n{\n    esp_linenoise_instance_t *instance = linenoise_get_static_instance();\n    if (write_fn != NULL) {\n        instance->config.write_bytes_cb = write_fn;\n    }\n}\n\nvoid linenoiseSetReadFunction(linenoiseReadBytesFn read_fn)\n{\n    esp_linenoise_instance_t *instance = linenoise_get_static_instance();\n    if (read_fn != NULL) {\n        instance->config.read_bytes_cb = read_fn;\n    }\n}\n\n/* Register a callback function to be called for tab-completion. */\nvoid linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn)\n{\n    esp_linenoise_instance_t *instance = linenoise_get_static_instance();\n    if (fn != NULL) {\n        s_completion_cb = fn;\n        instance->config.completion_cb = completion_default_cb;\n    }\n}\n\n/* Register a hits function to be called to show hits to the user at the\n * right of the prompt. */\nvoid linenoiseSetHintsCallback(linenoiseHintsCallback *fn)\n{\n    esp_linenoise_instance_t *instance = linenoise_get_static_instance();\n    if (fn != NULL) {\n        instance->config.hints_cb = fn;\n    }\n}\n\n/* Register a function to free the hints returned by the hints callback\n * registered with linenoiseSetHintsCallback(). */\nvoid linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn)\n{\n    esp_linenoise_instance_t *instance = linenoise_get_static_instance();\n    if (fn != NULL) {\n        instance->config.free_hints_cb = fn;\n    }\n}\n\n/* Clear the screen. Used to handle ctrl+l */\nvoid linenoiseClearScreen(void)\n{\n    esp_linenoise_instance_t *instance = linenoise_get_static_instance();\n    (void)esp_linenoise_clear_screen(instance);\n}\n\nint linenoiseProbe(void)\n{\n    esp_linenoise_instance_t *instance = linenoise_get_static_instance();\n\n    linenoiseSetReadCharacteristics();\n\n    return esp_linenoise_probe(instance);\n}\n\n/* The high level function that is the main API of the linenoise library. */\nchar *linenoise(const char *prompt)\n{\n    esp_linenoise_instance_t *instance = linenoise_get_static_instance();\n\n    /* update the default prompt value set when the static linenoise\n     * instance was created */\n    const char *prompt_copy = instance->config.prompt;\n    instance->config.prompt = prompt;\n\n    size_t cmd_line_length = 0;\n    esp_err_t ret_val = esp_linenoise_get_max_cmd_line_length(instance, &cmd_line_length);\n    if (ret_val != ESP_OK) {\n        cmd_line_length = ESP_LINENOISE_COMMAND_MAX_LEN;\n    }\n    char *cmd_line = calloc(1, cmd_line_length);\n    if (!cmd_line) {\n        return NULL;\n    }\n\n    ret_val = esp_linenoise_get_line(instance, cmd_line, cmd_line_length);\n    if (ret_val != ESP_OK) {\n        free(cmd_line);\n        return NULL;\n    }\n\n    /* reset the prompt to its default value */\n    instance->config.prompt = prompt_copy;\n\n    /* return the line */\n    return cmd_line;\n}\n\n/* This is just a wrapper the user may want to call in order to make sure\n * the linenoise returned buffer is freed with the same allocator it was\n * created with. Useful when the main program is using an alternative\n * allocator. */\nvoid linenoiseFree(void *ptr)\n{\n    free(ptr);\n}\n\nvoid linenoiseHistoryFree(void)\n{\n    esp_linenoise_instance_t *instance = linenoise_get_static_instance();\n    (void)esp_linenoise_history_free(instance);\n}\n\n/* This is the API call to add a new entry in the linenoise history.\n * It uses a fixed array of char pointers that are shifted (memmoved)\n * when the history max length is reached in order to remove the older\n * entry and make room for the new one, so it is not exactly suitable for huge\n * histories, but will work well for a few hundred of entries.\n *\n * Using a circular buffer is smarter, but a bit more complex to handle. */\nint linenoiseHistoryAdd(const char *line)\n{\n    esp_linenoise_instance_t *instance = linenoise_get_static_instance();\n    const esp_err_t ret_val = esp_linenoise_history_add(instance, line);\n    if (ret_val != ESP_OK) {\n        return -1;\n    }\n    return 0;\n}\n\n/* Set the maximum length for the history. This function can be called even\n * if there is already some history, the function will make sure to retain\n * just the latest 'len' elements if the new history length value is smaller\n * than the amount of items already inside the history. */\nint linenoiseHistorySetMaxLen(int len)\n{\n    esp_linenoise_instance_t *instance = linenoise_get_static_instance();\n    const esp_err_t ret_val = esp_linenoise_history_set_max_len(instance, len);\n    if (ret_val != ESP_OK) {\n        return 0;\n    }\n    return 1;\n}\n\n/* Save the history in the specified file. On success 0 is returned\n * otherwise -1 is returned. */\nint linenoiseHistorySave(const char *filename)\n{\n    esp_linenoise_instance_t *instance = linenoise_get_static_instance();\n    const esp_err_t ret_val = esp_linenoise_history_save(instance, filename);\n    if (!ret_val) {\n        return -1;\n    }\n    return 0;\n}\n\n/* Load the history from the specified file. If the file does not exist\n * zero is returned and no operation is performed.\n *\n * If the file exists and the operation succeeded 0 is returned, otherwise\n * on error -1 is returned. */\nint linenoiseHistoryLoad(const char *filename)\n{\n    esp_linenoise_instance_t *instance = linenoise_get_static_instance();\n    const esp_err_t ret_val = esp_linenoise_history_load(instance, filename);\n    if (ret_val != ESP_OK) {\n        return -1;\n    }\n    return 0;\n}\n\n/* Set line maximum length. If len configeter is smaller than\n * ESP_LINENOISE_MINIMAL_MAX_LINE, -1 is returned\n * otherwise 0 is returned. */\nint linenoiseSetMaxLineLen(size_t len)\n{\n    esp_linenoise_instance_t *instance = linenoise_get_static_instance();\n    esp_err_t ret_val = esp_linenoise_set_max_cmd_line_length(instance, len);\n    if (ret_val != ESP_OK) {\n        return -1;\n    }\n    return 0;\n}\n"
  },
  {
    "path": "esp_linenoise/linenoise/linenoise.h",
    "content": "/* linenoise.h -- VERSION 1.0\n *\n * Guerrilla line editing library against the idea that a line editing lib\n * needs to be 20,000 lines of C code.\n *\n * See linenoise.c for more information.\n *\n * ------------------------------------------------------------------------\n *\n * Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>\n * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *  *  Redistributions of source code must retain the above copyright\n *     notice, this list of conditions and the following disclaimer.\n *\n *  *  Redistributions in binary form must reproduce the above copyright\n *     notice, this list of conditions and the following disclaimer in the\n *     documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#pragma once\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n\ntypedef struct esp_linenoise_completions linenoiseCompletions;\n\ntypedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);\ntypedef char *(linenoiseHintsCallback)(const char *, int *color, int *bold);\ntypedef void(linenoiseFreeHintsCallback)(void *);\ntypedef ssize_t (*linenoiseReadBytesFn)(int fd, void *buf, size_t count);\ntypedef ssize_t (*linenoiseWriteBytesFn)(int fd, const void *buf, size_t count);\n\nvoid linenoiseSetCompletionCallback(linenoiseCompletionCallback *);\nvoid linenoiseSetHintsCallback(linenoiseHintsCallback *);\nvoid linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);\nvoid linenoiseAddCompletion(linenoiseCompletions *, const char *);\nvoid linenoiseSetReadFunction(linenoiseReadBytesFn read_fn);\nvoid linenoiseSetWriteFunction(linenoiseWriteBytesFn write_fn);\nvoid linenoiseSetReadCharacteristics(void);\n\nint linenoiseProbe(void);\nchar *linenoise(const char *prompt);\nvoid linenoiseFree(void *ptr);\nint linenoiseHistoryAdd(const char *line);\nint linenoiseHistorySetMaxLen(int len);\nint linenoiseHistorySave(const char *filename);\nint linenoiseHistoryLoad(const char *filename);\nvoid linenoiseHistoryFree(void);\nvoid linenoiseClearScreen(void);\nvoid linenoiseSetMultiLine(int ml);\nvoid linenoiseSetDumbMode(int set);\nbool linenoiseIsDumbMode(void);\nvoid linenoiseAllowEmpty(bool);\nint linenoiseSetMaxLineLen(size_t len);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_linenoise/private_include/esp_linenoise_private.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdlib.h>\n#include <string.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/semphr.h\"\n#include \"esp_linenoise.h\"\n\n#define ESP_LINENOISE_DEFAULT_PROMPT \">\"\n#define ESP_LINENOISE_DEFAULT_HISTORY_MAX_LENGTH 100\n#define ESP_LINENOISE_DEFAULT_MAX_LINE 4096\n#define ESP_LINENOISE_MINIMAL_MAX_LINE 64\n#define ESP_LINENOISE_COMMAND_MAX_LEN 32\n#define ESP_LINENOISE_PASTE_KEY_DELAY 30 /* Delay, in milliseconds, between two characters being pasted from clipboard */\n\nenum KEY_ACTION {\n    KEY_NULL = 0,       /* NULL */\n    CTRL_A = 1,         /* Ctrl+a */\n    CTRL_B = 2,         /* Ctrl-b */\n    CTRL_C = 3,         /* Ctrl-c */\n    CTRL_D = 4,         /* Ctrl-d */\n    CTRL_E = 5,         /* Ctrl-e */\n    CTRL_F = 6,         /* Ctrl-f */\n    CTRL_H = 8,         /* Ctrl-h */\n    TAB = 9,            /* Tab */\n    CTRL_K = 11,        /* Ctrl+k */\n    CTRL_L = 12,        /* Ctrl+l */\n    ENTER = 10,         /* Enter */\n    CTRL_N = 14,        /* Ctrl-n */\n    CTRL_P = 16,        /* Ctrl-p */\n    CTRL_T = 20,        /* Ctrl-t */\n    CTRL_U = 21,        /* Ctrl+u */\n    CTRL_W = 23,        /* Ctrl+w */\n    ESC = 27,           /* Escape */\n    UNIT_SEP = 31,      /* ctrl-_ */\n    BACKSPACE =  127    /* Backspace */\n};\n\ntypedef struct esp_linenoise_state {\n    char *buffer; /* Edited line buffer. */\n    size_t buffer_length; /* Edited line buffer size. */\n    size_t prompt_length; /* Prompt length. */\n    size_t cur_cursor_position; /* Current cursor position. */\n    size_t old_cursor_position; /* Previous refresh cursor position. */\n    size_t len; /* Current edited line length. */\n    size_t columns; /* Number of columns in terminal. */\n    size_t max_rows_used; /* Maximum num of rows used so far (multiline mode) */\n    int history_index; /* The history index we are currently editing. */\n    int history_length; /* The current length of the history*/\n    SemaphoreHandle_t mux;\n    int abort_read_fd;\n} esp_linenoise_state_t;\n\ntypedef struct esp_linenoise_instance {\n    esp_linenoise_config_t config;\n    esp_linenoise_state_t state;\n} esp_linenoise_instance_t;\n\n/**\n * @brief Stores a list of completion strings.\n */\ntypedef struct esp_linenoise_completions {\n    size_t len;   /**< Number of completions. */\n    char **cvec;  /**< Array of completion strings. */\n} esp_linenoise_completions_t;\n\n\ninline __attribute__((always_inline))\nesp_linenoise_instance_t *esp_linenoise_create_instance_static(void)\n{\n    esp_linenoise_instance_t *instance = malloc(sizeof(esp_linenoise_instance_t));\n    assert(instance != NULL);\n\n    esp_linenoise_get_instance_config_default(&instance->config);\n\n    /* set the state part of the esp_linenoise_instance_t to 0 to init all values to 0 (or NULL) */\n    memset(&instance->state, 0x00, sizeof(esp_linenoise_state_t));\n\n    return instance;\n}\n\n/**\n * @brief This function is used by the callback function registered by the user\n * in order to add completion options given the input string when the\n * user typed <tab>. See the example.c source code for a very easy to\n * understand example.\n *\n * @param ctx opaque pointer interpreted in line completion structure being\n * filled by the function\n * @param str completed command to add to lc\n */\nvoid esp_linenoise_add_completion(void *ctx, const char *str);\n\n/**\n * @brief esp_linenoise default read function.\n *\n * @note This function waits for available data on the file descriptor\n * provided as parameter on on the eventfd using select. It either returns\n * the data read from the file descriptor or a new line character if data was\n * read from the eventfd first. This new line will trigger the esp_linenoise_get_line\n * to return.\n *\n * @param fd file descriptor from which to read\n * @param buf buffer used to store the read data\n * @param count size of the buffer\n * @return ssize_t size of the data read\n */\nssize_t esp_linenoise_default_read_bytes(int fd, void *buf, size_t count);\n\n/**\n * @brief Sets the eventfd used to return from esp_linenoise_default_read_bytes.\n *\n * @note This function is only implemented if esp_linenoise_abort is used.\n *\n * @param instance linenoise instance associated with the eventfd to create\n * @return esp_err_t ESP_OK on success, other errors on failures\n */\n__attribute__((weak)) esp_err_t esp_linenoise_set_event_fd(esp_linenoise_instance_t *instance);\n\n/**\n * @brief Remove the eventfd used to return from esp_linenoise_default_read_bytes.\n *\n * @note This function is only implemented if esp_linenoise_abort is used.\n *\n * @param instance linenoise instance associated with the eventfd to create\n * @return esp_err_t ESP_OK on success, other errors on failures\n */\n__attribute__((weak)) esp_err_t esp_linenoise_remove_event_fd(esp_linenoise_instance_t *instance);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_linenoise/sbom_esp_linenoise.yml",
    "content": "name: esp_linenoise\ndescription: Line editing C library\nurl: https://github.com/espressif/idf-extra-components/tree/master/esp_linenoise\nversion: 1.0.0\ncpe: cpe:2.3:a:espressif:esp_linenoise:{}:*:*:*:*:*:*:*\nsupplier: 'Organization: Espressif Systems'"
  },
  {
    "path": "esp_linenoise/src/esp_linenoise.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <unistd.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdio.h>\n#include \"sdkconfig.h\"\n#if !CONFIG_IDF_TARGET_LINUX\n// On Linux, we don't need __fbufsize (see comments below), and\n// __fbufsize not available on MacOS (which is also considered \"Linux\" target)\n#include <stdio_ext.h> // for __fbufsize\n#endif // !CONFIG_IDF_TARGET_LINUX\n#include <stddef.h>\n#include <errno.h>\n#include <string.h>\n#include <ctype.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <sys/fcntl.h>\n#include <sys/time.h>\n#include <assert.h>\n#include \"esp_err.h\"\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/semphr.h\"\n#include \"esp_linenoise.h\"\n#include \"esp_linenoise_private.h\"\n\nstatic ssize_t esp_linenoise_default_write_bytes(int fd, const void *buf, size_t count)\n{\n    const int nb_bytes_written = write(fd, buf, count);\n    if (nb_bytes_written == count) {\n        fsync(fd);\n    }\n    return nb_bytes_written;\n}\n\n__attribute__((weak)) ssize_t esp_linenoise_default_read_bytes(int fd, void *buf, size_t count)\n{\n    return read(fd, buf, count);\n}\n\n/* Debugging macro. */\n#if 0\nFILE *lndebug_fp = NULL;\n#define lndebug(...) \\\n    do { \\\n        if (lndebug_fp == NULL) { \\\n            lndebug_fp = fopen(\"/tmp/lndebug.txt\",\"a\"); \\\n            fprintf(lndebug_fp, \\\n            \"[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\\n\", \\\n            (int)state->len,(int)state->cur_cursor_position,(int)state->old_cursor_position,prompt_length,rows,rpos, \\\n            (int)state->max_rows_used,old_rows); \\\n        } \\\n        fprintf(lndebug_fp, \", \" __VA_ARGS__); \\\n        fflush(lndebug_fp); \\\n    } while (0)\n#else\n#define lndebug(fmt, ...)\n#endif\n\n/* We define a very simple \"append buffer\" structure, that is an heap\n * allocated string where we can append to. This is useful in order to\n * write all the escape sequences in a buffer and flush them to the standard\n * output in a single call, to avoid flickering effects. */\ntypedef struct append_buffer {\n    char *b;\n    int len;\n} append_buffer_t;\n\nstatic void esp_linenoise_append_buffer_init(append_buffer_t *ab)\n{\n    ab->b = NULL;\n    ab->len = 0;\n}\n\nstatic void esp_linenoise_append_buffer_append(append_buffer_t *ab, const char *s, int len)\n{\n    char *new = realloc(ab->b, ab->len + len);\n\n    if (new == NULL) {\n        return;\n    }\n    memcpy(new + ab->len, s, len);\n    ab->b = new;\n    ab->len += len;\n}\n\nstatic void esp_linenoise_append_buffer_free(append_buffer_t *ab)\n{\n    free(ab->b);\n}\n\n/* Helper of esp_linenoise_refresh_single_line() and esp_linenoise_refresh_multi_line() to show hints\n * to the right of the prompt. */\nstatic void esp_linenoise_refresh_show_hints(append_buffer_t *ab, esp_linenoise_instance_t *instance)\n{\n\n    esp_linenoise_state_t state = instance->state;\n    esp_linenoise_config_t config = instance->config;\n    char seq[64];\n\n    if (config.hints_cb && state.prompt_length + state.len < state.columns) {\n\n        int color = -1, bold = 0;\n        char *hint = config.hints_cb(state.buffer, &color, &bold);\n        if (hint) {\n            int hintlen = strlen(hint);\n            int hintmaxlen = state.columns - (state.prompt_length + state.len);\n\n            if (hintlen > hintmaxlen) {\n                hintlen = hintmaxlen;\n            }\n\n            if (bold == 1 && color == -1) {\n                color = 37;\n            }\n\n            if (color != -1 || bold != 0) {\n                snprintf(seq, 64, \"\\033[%d;%d;49m\", bold, color);\n                esp_linenoise_append_buffer_append(ab, seq, strlen(seq));\n            }\n\n            esp_linenoise_append_buffer_append(ab, hint, hintlen);\n\n            if (color != -1 || bold != 0) {\n                esp_linenoise_append_buffer_append(ab, \"\\033[0m\", 4);\n            }\n\n            /* Call the function to free the hint returned. */\n            if (config.free_hints_cb) {\n                config.free_hints_cb(hint);\n            }\n        }\n    }\n}\n\n/* Single line low level line refresh.\n *\n * Rewrite the currently edited line accordingly to the buffer content,\n * cursor position, and number of columns of the terminal. */\nstatic void esp_linenoise_refresh_single_line(esp_linenoise_instance_t *instance)\n{\n    esp_linenoise_config_t *config = &instance->config;\n    esp_linenoise_state_t *state = &instance->state;\n\n    char seq[64];\n    size_t prompt_length = state->prompt_length;\n    int fd = instance->config.out_fd;\n    char *buf = state->buffer;\n    size_t len = state->len;\n    size_t cur_cursor_position = state->cur_cursor_position;\n    append_buffer_t ab;\n\n    while ((prompt_length + cur_cursor_position) >= state->columns) {\n        buf++;\n        len--;\n        cur_cursor_position--;\n    }\n    while (prompt_length + len > state->columns) {\n        len--;\n    }\n\n    esp_linenoise_append_buffer_init(&ab);\n    /* Cursor to left edge */\n    snprintf(seq, 64, \"\\r\");\n    esp_linenoise_append_buffer_append(&ab, seq, strlen(seq));\n    /* Write the prompt and the current buffer content */\n    esp_linenoise_append_buffer_append(&ab, config->prompt, strlen(config->prompt));\n    esp_linenoise_append_buffer_append(&ab, buf, len);\n    /* Show hits if any. */\n    esp_linenoise_refresh_show_hints(&ab, instance);\n    /* Erase to right */\n    snprintf(seq, 64, \"\\x1b[0K\");\n    esp_linenoise_append_buffer_append(&ab, seq, strlen(seq));\n    /* Move cursor to original position. */\n    snprintf(seq, 64, \"\\r\\x1b[%dC\", (int)(cur_cursor_position + prompt_length));\n    esp_linenoise_append_buffer_append(&ab, seq, strlen(seq));\n    if (config->write_bytes_cb(fd, ab.b, ab.len) == -1) {} /* Can't recover from write error. */\n    esp_linenoise_append_buffer_free(&ab);\n}\n\n/* Multi line low level line refresh.\n *\n * Rewrite the currently edited line accordingly to the buffer content,\n * cursor position, and number of columns of the terminal. */\nstatic void esp_linenoise_refresh_multi_line(esp_linenoise_instance_t *instance)\n{\n    esp_linenoise_config_t *config = &instance->config;\n    esp_linenoise_state_t *state = &instance->state;\n\n    char seq[64];\n    int prompt_length = state->prompt_length;\n    int rows = (prompt_length + state->len + state->columns - 1) / state->columns; /* rows used by current buf. */\n    int rpos = (prompt_length + state->old_cursor_position + state->columns) / state->columns; /* cursor relative row. */\n    int rpos2; /* rpos after refresh. */\n    int col; /* column position, zero-based. */\n    int old_rows = state->max_rows_used;\n    int j;\n    int fd = instance->config.out_fd;\n    append_buffer_t ab;\n\n    /* Update max_rows_used if needed. */\n    if (rows > (int)state->max_rows_used) {\n        state->max_rows_used = rows;\n    }\n\n    /* First step: clear all the lines used before. To do so start by\n     * going to the last row. */\n    esp_linenoise_append_buffer_init(&ab);\n    if (old_rows - rpos > 0) {\n        lndebug(\"go down %d\", old_rows - rpos);\n        snprintf(seq, 64, \"\\x1b[%dB\", old_rows - rpos);\n        esp_linenoise_append_buffer_append(&ab, seq, strlen(seq));\n    }\n\n    /* Now for every row clear it, go up. */\n    for (j = 0; j < old_rows - 1; j++) {\n        lndebug(\"clear+up\");\n        snprintf(seq, 64, \"\\r\\x1b[0K\\x1b[1A\");\n        esp_linenoise_append_buffer_append(&ab, seq, strlen(seq));\n    }\n\n    /* Clean the top line. */\n    lndebug(\"clear\");\n    snprintf(seq, 64, \"\\r\\x1b[0K\");\n    esp_linenoise_append_buffer_append(&ab, seq, strlen(seq));\n\n    /* Write the prompt and the current buffer content */\n    esp_linenoise_append_buffer_append(&ab, config->prompt, strlen(config->prompt));\n    esp_linenoise_append_buffer_append(&ab, state->buffer, state->len);\n\n    /* Show hits if any. */\n    esp_linenoise_refresh_show_hints(&ab, instance);\n\n    /* If we are at the very end of the screen with our prompt, we need to\n     * emit a newline and move the prompt to the first column. */\n    if (state->cur_cursor_position &&\n            state->cur_cursor_position == state->len &&\n            (state->cur_cursor_position + prompt_length) % state->columns == 0) {\n        lndebug(\"<newline>\");\n        esp_linenoise_append_buffer_append(&ab, \"\\n\", 1);\n        snprintf(seq, 64, \"\\r\");\n        esp_linenoise_append_buffer_append(&ab, seq, strlen(seq));\n        rows++;\n        if (rows > (int)state->max_rows_used) {\n            state->max_rows_used = rows;\n        }\n    }\n\n    /* Move cursor to right position. */\n    rpos2 = (prompt_length + state->cur_cursor_position + state->columns) / state->columns; /* current cursor relative row. */\n    lndebug(\"rpos2 %d\", rpos2);\n\n    /* Go up till we reach the expected position. */\n    if (rows - rpos2 > 0) {\n        lndebug(\"go-up %d\", rows - rpos2);\n        snprintf(seq, 64, \"\\x1b[%dA\", rows - rpos2);\n        esp_linenoise_append_buffer_append(&ab, seq, strlen(seq));\n    }\n\n    /* Set column. */\n    col = (prompt_length + (int)state->cur_cursor_position) % (int)state->columns;\n    lndebug(\"set col %d\", 1 + col);\n    if (col) {\n        snprintf(seq, 64, \"\\r\\x1b[%dC\", col);\n    } else {\n        snprintf(seq, 64, \"\\r\");\n    }\n    esp_linenoise_append_buffer_append(&ab, seq, strlen(seq));\n\n    lndebug(\"\\n\");\n    state->old_cursor_position = state->cur_cursor_position;\n\n    if (config->write_bytes_cb(fd, ab.b, ab.len) == -1) {} /* Can't recover from write error. */\n    esp_linenoise_append_buffer_free(&ab);\n}\n\n/* Calls the two low level functions esp_linenoise_refresh_single_line() or\n * esp_linenoise_refresh_multi_line() according to the selected mode. */\nstatic void esp_linenoise_refresh_line(esp_linenoise_instance_t *instance)\n{\n    if (instance->config.allow_multi_line) {\n        esp_linenoise_refresh_multi_line(instance);\n    } else {\n        esp_linenoise_refresh_single_line(instance);\n    }\n}\n\n/* Use the ESC [6n escape sequence to query the horizontal cursor position\n * and return it. On error -1 is returned, on success the position of the\n * cursor. */\nstatic int esp_linenoise_get_cursor_position(esp_linenoise_instance_t *instance)\n{\n    esp_linenoise_config_t *config = &instance->config;\n\n    char buf[ESP_LINENOISE_COMMAND_MAX_LEN] = { 0 };\n    int columns = 0;\n    int rows = 0;\n    int i = 0;\n    const int out_fd = instance->config.out_fd;\n    const int in_fd = instance->config.in_fd;\n    /* The following ANSI escape sequence is used to get from the TTY the\n     * cursor position. */\n    const char get_cursor_cmd[] = \"\\x1b[6n\";\n\n    /* Send the command to the TTY on the other end of the UART.\n     * Let's use unistd's write function. Thus, data sent through it are raw\n     * reducing the overhead compared to using fputs, fprintf, etc... */\n    const int num_written = config->write_bytes_cb(out_fd, get_cursor_cmd, sizeof(get_cursor_cmd));\n    if (num_written != sizeof(get_cursor_cmd)) {\n        return -1;\n    }\n\n    /* The other end will send its response which format is ESC [ rows ; columns R\n     * We don't know exactly how many bytes we have to read, thus, perform a\n     * read for each byte.\n     * Stop right before the last character of the buffer, to be able to NULL\n     * terminate it. */\n    while (i < sizeof(buf) - 1) {\n        /* Keep using unistd's functions. Here, using `read` instead of `fgets`\n         * or `fgets` guarantees us that we we can read a byte regardless on\n         * whether the sender sent end of line character(s) (CR, CRLF, LF). */\n        if (config->read_bytes_cb(in_fd, buf + i, 1) != 1 || buf[i] == 'R') {\n            /* If we couldn't read a byte from in_fd or if 'R' was received,\n             * the transmission is finished. */\n            break;\n        }\n\n        /* For some reasons, it is possible that we receive new line character\n         * after querying the cursor position on some UART. Let's ignore them,\n         * this will not affect the rest of the program. */\n        if (buf[i] != '\\n') {\n            i++;\n        }\n    }\n\n    /* NULL-terminate the buffer, this is required by `sscanf`. */\n    buf[i] = '\\0';\n\n    /* Parse the received data to get the position of the cursor. */\n    if (buf[0] != ESC || buf[1] != '[' || sscanf(buf + 2, \"%d;%d\", &rows, &columns) != 2) {\n        return -1;\n    }\n    return columns;\n}\n\n/* Try to get the number of columns in the current terminal, or assume 80\n * if it fails. */\nstatic int esp_linenoise_get_columns(esp_linenoise_instance_t *instance)\n{\n    esp_linenoise_config_t *config = &instance->config;\n\n    int start = 0;\n    int columns = 0;\n    int written = 0;\n    char seq[ESP_LINENOISE_COMMAND_MAX_LEN] = { 0 };\n    const int fd = instance->config.out_fd;\n\n    /* The following ANSI escape sequence is used to tell the TTY to move\n     * the cursor to the most-right position. */\n    const char move_cursor_right[] = \"\\x1b[999C\";\n    const size_t cmd_len = sizeof(move_cursor_right);\n\n    /* This one is used to set the cursor position. */\n    const char set_cursor_pos[] = \"\\x1b[%dD\";\n\n    /* Get the initial position so we can restore it later. */\n    start = esp_linenoise_get_cursor_position(instance);\n    if (start == -1) {\n        goto failed;\n    }\n\n    /* Send the command to go to right margin. Use `write` function instead of\n     * `fwrite` for the same reasons explained in `esp_linenoise_get_cursor_position()` */\n    if (config->write_bytes_cb(fd, move_cursor_right, cmd_len) != cmd_len) {\n        goto failed;\n    }\n\n    /* After sending this command, we can get the new position of the cursor,\n     * we'd get the size, in columns, of the opened TTY. */\n    columns = esp_linenoise_get_cursor_position(instance);\n    if (columns == -1) {\n        goto failed;\n    }\n\n    /* Restore the position of the cursor back. */\n    if (columns > start) {\n        /* Generate the move cursor command. */\n        written = snprintf(seq, ESP_LINENOISE_COMMAND_MAX_LEN, set_cursor_pos, columns - start);\n\n        /* If `written` is equal or bigger than ESP_LINENOISE_COMMAND_MAX_LEN, it\n         * means that the output has been truncated because the size provided\n         * is too smalstate. */\n        assert (written < ESP_LINENOISE_COMMAND_MAX_LEN);\n\n        /* Send the command with `write`, which is not buffered. */\n        if (config->write_bytes_cb(fd, seq, written) == -1) {\n            /* Can't recover... */\n        }\n    }\n    return columns;\n\nfailed:\n    return 80;\n}\n\n/* Beep, used for completion when there is nothing to complete or when all\n * the choices were already shown. */\nstatic void esp_linenoise_make_beep_sound(esp_linenoise_instance_t *instance)\n{\n    esp_linenoise_config_t *config = &instance->config;\n\n    char bip_screen_str[] = \"\\x7\";\n    (void)config->write_bytes_cb(instance->config.out_fd, bip_screen_str, sizeof(bip_screen_str));\n}\n\n/* Free a list of completion option populated by linenoiseAddCompletion(). */\nstatic void free_completions(esp_linenoise_completions_t *lc)\n{\n    size_t i;\n    for (i = 0; i < lc->len; i++) {\n        free(lc->cvec[i]);\n    }\n    if (lc->cvec != NULL) {\n        free(lc->cvec);\n    }\n}\n\n/* This is an helper function for esp_linenoise_edit() and is called when the\n * user types the <tab> key in order to complete the string currently in the\n * input.\n *\n * The state of the editing is encapsulated into the pointed esp_linenoise_state\n * structure as described in the structure definition. */\nstatic int esp_linenoise_complete_line(esp_linenoise_instance_t *instance)\n{\n    esp_linenoise_config_t *config = &instance->config;\n    esp_linenoise_state_t *state = &instance->state;\n\n    esp_linenoise_completions_t lc = { 0, NULL };\n    int nread, nwritten;\n    char c = 0;\n    int in_fd = instance->config.in_fd;\n\n    config->completion_cb(state->buffer, &lc, esp_linenoise_add_completion);\n    if (lc.len == 0) {\n        esp_linenoise_make_beep_sound(instance);\n    } else {\n        size_t stop = 0, i = 0;\n\n        while (!stop) {\n            /* Show completion or original buffer */\n            if (i < lc.len) {\n                esp_linenoise_state_t saved = *state;\n\n                state->len = state->cur_cursor_position = strlen(lc.cvec[i]);\n                state->buffer = lc.cvec[i];\n                esp_linenoise_refresh_line(instance);\n                state->len = saved.len;\n                state->cur_cursor_position = saved.cur_cursor_position;\n                state->buffer = saved.buffer;\n            } else {\n                esp_linenoise_refresh_line(instance);\n            }\n\n            nread = config->read_bytes_cb(in_fd, &c, 1);\n            if (nread <= 0) {\n                free_completions(&lc);\n                return -1;\n            }\n\n            switch (c) {\n            case TAB: /* tab */\n                i = (i + 1) % (lc.len + 1);\n                if (i == lc.len) {\n                    esp_linenoise_make_beep_sound(instance);\n                }\n                break;\n            case ESC: /* escape */\n                /* Re-show original buffer */\n                if (i < lc.len) {\n                    esp_linenoise_refresh_line(instance);\n                }\n                stop = 1;\n                break;\n            default:\n                /* Update buffer and return */\n                if (i < lc.len) {\n                    nwritten = snprintf(state->buffer, state->buffer_length, \"%s\", lc.cvec[i]);\n                    state->len = state->cur_cursor_position = nwritten;\n                }\n                stop = 1;\n                break;\n            }\n        }\n    }\n\n    free_completions(&lc);\n    return c; /* Return last read character */\n}\n\n/* =========================== Line editing ================================= */\n\n/* Insert the character 'c' at cursor current position.\n *\n * On error writing to the terminal -1 is returned, otherwise 0. */\nstatic int esp_linenoise_edit_insert(esp_linenoise_instance_t *instance, char c)\n{\n    esp_linenoise_config_t *config = &instance->config;\n    esp_linenoise_state_t *state = &instance->state;\n\n    int fd = instance->config.out_fd;\n    if (state->len < state->buffer_length) {\n        if (state->len == state->cur_cursor_position) {\n            state->buffer[state->cur_cursor_position] = c;\n            state->cur_cursor_position++;\n            state->len++;\n            state->buffer[state->len] = '\\0';\n            if ((!config->allow_multi_line && state->prompt_length + state->len < state->columns && !config->hints_cb)) {\n                /* Avoid a full update of the line in the\n                 * trivial case. */\n                if (config->write_bytes_cb(fd, &c, 1) == -1) {\n                    return -1;\n                }\n            } else {\n                esp_linenoise_refresh_line(instance);\n            }\n        } else {\n            memmove(state->buffer + state->cur_cursor_position + 1, state->buffer + state->cur_cursor_position, state->len - state->cur_cursor_position);\n            state->buffer[state->cur_cursor_position] = c;\n            state->len++;\n            state->cur_cursor_position++;\n            state->buffer[state->len] = '\\0';\n            esp_linenoise_refresh_line(instance);\n        }\n    }\n    return 0;\n}\n\nstatic int esp_linenoise_insert_pasted_char(esp_linenoise_instance_t *instance, char c)\n{\n    esp_linenoise_config_t *config = &instance->config;\n    esp_linenoise_state_t *state = &instance->state;\n    int fd = instance->config.out_fd;\n\n    if (state->len < state->buffer_length && state->len == state->cur_cursor_position) {\n        state->buffer[state->cur_cursor_position] = c;\n        state->cur_cursor_position++;\n        state->len++;\n        state->buffer[state->len] = '\\0';\n        if (config->write_bytes_cb(fd, &c, 1) == -1) {\n            return -1;\n        }\n    }\n    return 0;\n}\n\n/* Move cursor on the left. */\nstatic void esp_linenoise_edit_move_left(esp_linenoise_instance_t *instance)\n{\n    esp_linenoise_state_t *state = &instance->state;\n    if (state->cur_cursor_position > 0) {\n        state->cur_cursor_position--;\n        esp_linenoise_refresh_line(instance);\n    }\n}\n\n/* Move cursor on the right. */\nstatic void esp_linenoise_edit_move_right(esp_linenoise_instance_t *instance)\n{\n    esp_linenoise_state_t *state = &instance->state;\n    if (state->cur_cursor_position != state->len) {\n        state->cur_cursor_position++;\n        esp_linenoise_refresh_line(instance);\n    }\n}\n\n/* Move cursor to the start of the line. */\nstatic void esp_linenoise_edit_move_home(esp_linenoise_instance_t *instance)\n{\n    esp_linenoise_state_t *state = &instance->state;\n    if (state->cur_cursor_position != 0) {\n        state->cur_cursor_position = 0;\n        esp_linenoise_refresh_line(instance);\n    }\n}\n\n/* Move cursor to the end of the line. */\nstatic void esp_linenoise_edit_move_end(esp_linenoise_instance_t *instance)\n{\n    esp_linenoise_state_t *state = &instance->state;\n    if (state->cur_cursor_position != state->len) {\n        state->cur_cursor_position = state->len;\n        esp_linenoise_refresh_line(instance);\n    }\n}\n\n/* Substitute the currently edited line with the next or previous history\n * entry as specified by 'dir'. */\n#define esp_LINENOISE_HISTORY_NEXT 0\n#define esp_LINENOISE_HISTORY_PREV 1\nstatic void esp_linenoise_edit_history_next(esp_linenoise_instance_t *instance, int dir)\n{\n    esp_linenoise_config_t *config = &instance->config;\n    esp_linenoise_state_t *state = &instance->state;\n\n    if (state->history_length - state->history_index >= 1) {\n        /* Update the current history entry before to\n         * overwrite it with the next one. */\n        char *buffer_copy = strdup(state->buffer);\n        if (!buffer_copy) {\n            return;\n        }\n        free(config->history[state->history_index]);\n        config->history[state->history_index] = buffer_copy;\n        /* Show the new entry */\n        state->history_index += (dir == esp_LINENOISE_HISTORY_PREV) ? 1 : -1;\n        if (state->history_index < 0) {\n            state->history_index = 0;\n            return;\n        } else if (state->history_index >= state->history_length) {\n            state->history_index = state->history_length - 1;\n            return;\n        }\n        strncpy(state->buffer, config->history[state->history_index], state->buffer_length);\n        state->buffer[state->buffer_length - 1] = '\\0';\n        state->len = state->cur_cursor_position = strlen(state->buffer);\n        esp_linenoise_refresh_line(instance);\n    }\n}\n\n/* Delete the character at the right of the cursor without altering the cursor\n * position. Basically this is what happens with the \"Delete\" keyboard key. */\nstatic void esp_linenoise_edit_delete(esp_linenoise_instance_t *instance)\n{\n    esp_linenoise_state_t *state = &instance->state;\n\n    if (state->len > 0 && state->cur_cursor_position < state->len) {\n        memmove(state->buffer + state->cur_cursor_position, state->buffer + state->cur_cursor_position + 1, state->len - state->cur_cursor_position - 1);\n        state->len--;\n        state->buffer[state->len] = '\\0';\n        esp_linenoise_refresh_line(instance);\n    }\n}\n\n/* Backspace implementation. */\nstatic void esp_linenoise_edit_backspace(esp_linenoise_instance_t *instance)\n{\n    esp_linenoise_state_t *state = &instance->state;\n\n    if (state->cur_cursor_position > 0 && state->len > 0) {\n        memmove(state->buffer + state->cur_cursor_position - 1, state->buffer + state->cur_cursor_position, state->len - state->cur_cursor_position);\n        state->cur_cursor_position--;\n        state->len--;\n        state->buffer[state->len] = '\\0';\n        esp_linenoise_refresh_line(instance);\n    }\n}\n\n/* Delete the previous word, maintaining the cursor at the start of the\n * current word. */\nstatic void esp_linenoise_edit_delete_prev_word(esp_linenoise_instance_t *instance)\n{\n    esp_linenoise_state_t *state = &instance->state;\n\n    size_t old_pos = state->cur_cursor_position;\n    size_t diff;\n\n    while (state->cur_cursor_position > 0 && state->buffer[state->cur_cursor_position - 1] == ' ') {\n        state->cur_cursor_position--;\n    }\n    while (state->cur_cursor_position > 0 && state->buffer[state->cur_cursor_position - 1] != ' ') {\n        state->cur_cursor_position--;\n    }\n    diff = old_pos - state->cur_cursor_position;\n    memmove(state->buffer + state->cur_cursor_position, state->buffer + old_pos, state->len - old_pos + 1);\n    state->len -= diff;\n    esp_linenoise_refresh_line(instance);\n}\n\nstatic uint32_t get_millis(void)\n{\n    struct timeval tv = { 0 };\n    gettimeofday(&tv, NULL);\n    return tv.tv_sec * 1000 + tv.tv_usec / 1000;\n}\n\nstatic inline size_t esp_linenoise_prompt_len_ignore_escape_seq(const char *prompt)\n{\n    size_t prompt_length = 0;\n    bool in_escape_sequence = false;\n\n    for (; *prompt != '\\0'; ++prompt) {\n        if (*prompt == '\\033') {\n            in_escape_sequence = true;\n        } else if (in_escape_sequence && *prompt == 'm') {\n            in_escape_sequence = false;\n        } else if (!in_escape_sequence) {\n            ++prompt_length;\n        }\n    }\n\n    return prompt_length;\n}\n\n/* This function is the core of the line editing capability of linenoise.\n * It expects 'fd' to be already in \"raw mode\" so that every key pressed\n * will be returned ASAP to read().\n *\n * The resulting string is put into 'buf' when the user type enter, or\n * when ctrl+d is typed.\n *\n * The function returns the length of the current buffer. */\nstatic int esp_linenoise_edit(esp_linenoise_instance_t *instance, char *buffer, size_t buffer_length)\n{\n    esp_linenoise_config_t *config = &instance->config;\n    esp_linenoise_state_t *state = &instance->state;\n\n    uint32_t t1 = 0;\n    int out_fd = instance->config.out_fd;\n    int in_fd = instance->config.in_fd;\n\n    /* Populate the linenoise state that we pass to functions implementing\n     * specific editing functionalities. */\n    state->buffer = buffer;\n    state->buffer_length = buffer_length;\n    state->prompt_length = strlen(config->prompt);\n    state->old_cursor_position = state->cur_cursor_position = 0;\n    state->len = 0;\n    state->columns = esp_linenoise_get_columns(instance);\n    state->max_rows_used = 0;\n    state->history_index = 0;\n\n    /* Buffer starts empty. */\n    state->buffer[0] = '\\0';\n    state->buffer_length--; /* Make sure there is always space for the nulterm */\n\n    /* The latest history entry is always our current buffer, that\n     * initially is just an empty string. */\n    const esp_err_t ret_val = esp_linenoise_history_add(instance, \"\");\n    if (ret_val != ESP_OK) {\n        return -1;\n    }\n\n    if (config->write_bytes_cb(out_fd, config->prompt, state->prompt_length) == -1) {\n        return -1;\n    }\n\n    /* If the prompt has been registered with ANSI escape sequences\n     * for terminal colors then we remove them from the prompt length\n     * calculation. */\n    state->prompt_length = esp_linenoise_prompt_len_ignore_escape_seq(config->prompt);\n\n    while (1) {\n        char c;\n\n        /**\n         * To determine whether the user is pasting data or typing itself, we\n         * need to calculate how many milliseconds elapsed between two key\n         * presses. Indeed, if there is less than ESP_LINENOISE_PASTE_KEY_DELAY\n         * (typically 30-40ms), then a paste is being performed, else, the\n         * user is typing.\n         * NOTE: pressing a key down without releasing it will also spend\n         * about 40ms (or even more)\n         */\n        t1 = get_millis();\n        int nread = config->read_bytes_cb(in_fd, &c, 1);\n        if (nread <= 0) {\n            return state->len;\n        }\n\n        if ( (get_millis() - t1) < ESP_LINENOISE_PASTE_KEY_DELAY && c != ENTER) {\n            /* Pasting data, insert characters without formatting.\n            * This can only be performed when the cursor is at the end of the\n            * line. */\n            if (esp_linenoise_insert_pasted_char(instance, c)) {\n                return -1;\n            }\n            continue;\n        }\n\n        /* Only autocomplete when the callback is set. It returns < 0 when\n         * there was an error reading from fd. Otherwise it will return the\n         * character that should be handled next. */\n        if (c == 9 && config->completion_cb != NULL) {\n            int c2 = esp_linenoise_complete_line(instance);\n            /* Return on errors */\n            if (c2 < 0) {\n                return state->len;\n            }\n            /* Read next character when 0 */\n            if (c2 == 0) {\n                continue;\n            }\n            c = c2;\n        }\n\n        switch (c) {\n        case ENTER:    /* enter */\n            state->history_length--;\n            free(config->history[state->history_length]);\n            if (config->allow_multi_line) {\n                esp_linenoise_edit_move_end(instance);\n            }\n            if (config->hints_cb) {\n                /* Force a refresh without hints to leave the previous\n                 * line as the user typed it after a newline. */\n                esp_linenoise_hints_t hc = config->hints_cb;\n                config->hints_cb = NULL;\n                esp_linenoise_refresh_line(instance);\n                config->hints_cb = hc;\n            }\n            return (int)state->len;\n        case CTRL_C:     /* ctrl-c */\n            errno = EAGAIN;\n            return -1;\n        case BACKSPACE:   /* backspace */\n        case CTRL_H:     /* ctrl-h */\n            esp_linenoise_edit_backspace(instance);\n            break;\n        case CTRL_D:     /* ctrl-d, remove char at right of cursor, or if the\n                            line is empty, act as end-of-file. */\n            if (state->len > 0) {\n                esp_linenoise_edit_delete(instance);\n            } else {\n                state->history_length--;\n                free(config->history[state->history_length]);\n                return -1;\n            }\n            break;\n        case CTRL_T:    /* ctrl-t, swaps current character with previous. */\n            if (state->cur_cursor_position > 0 && state->cur_cursor_position < state->len) {\n                int aux = state->buffer[state->cur_cursor_position - 1];\n                state->buffer[state->cur_cursor_position - 1] = state->buffer[state->cur_cursor_position];\n                state->buffer[state->cur_cursor_position] = aux;\n                if (state->cur_cursor_position != state->len - 1) {\n                    state->cur_cursor_position++;\n                }\n                esp_linenoise_refresh_line(instance);\n            }\n            break;\n        case CTRL_B:     /* ctrl-b */\n            esp_linenoise_edit_move_left(instance);\n            break;\n        case CTRL_F:     /* ctrl-f */\n            esp_linenoise_edit_move_right(instance);\n            break;\n        case CTRL_P:    /* ctrl-p */\n            esp_linenoise_edit_history_next(instance, esp_LINENOISE_HISTORY_PREV);\n            break;\n        case CTRL_N:    /* ctrl-n */\n            esp_linenoise_edit_history_next(instance, esp_LINENOISE_HISTORY_NEXT);\n            break;\n        case CTRL_U: /* Ctrl+u, delete the whole line. */\n            state->buffer[0] = '\\0';\n            state->cur_cursor_position = state->len = 0;\n            esp_linenoise_refresh_line(instance);\n            break;\n        case CTRL_K: /* Ctrl+k, delete from current to end of line. */\n            state->buffer[state->cur_cursor_position] = '\\0';\n            state->len = state->cur_cursor_position;\n            esp_linenoise_refresh_line(instance);\n            break;\n        case CTRL_A: /* Ctrl+a, go to the start of the line */\n            esp_linenoise_edit_move_home(instance);\n            break;\n        case CTRL_E: /* ctrl+e, go to the end of the line */\n            esp_linenoise_edit_move_end(instance);\n            break;\n        case CTRL_L: /* ctrl+l, clear screen */\n            (void)esp_linenoise_clear_screen(instance);\n            esp_linenoise_refresh_line(instance);\n            break;\n        case CTRL_W: /* ctrl+w, delete previous word */\n            esp_linenoise_edit_delete_prev_word(instance);\n            break;\n        case ESC: {     /* escape sequence */\n            /* ESC [ sequences. */\n            char seq[3];\n            int r = config->read_bytes_cb(in_fd, seq, 1);\n            if (r != 1) {\n                return -1;\n            }\n            if (seq[0] == '[') {\n                int r = config->read_bytes_cb(in_fd, seq + 1, 1);\n                if (r != 1) {\n                    return -1;\n                }\n                if (seq[1] >= '0' && seq[1] <= '9') {\n                    /* Extended escape, read additional byte. */\n                    r = config->read_bytes_cb(in_fd, seq + 2, 1);\n                    if (r != 1) {\n                        return -1;\n                    }\n                    if (seq[2] == '~') {\n                        switch (seq[1]) {\n                        case '3': /* Delete key. */\n                            esp_linenoise_edit_delete(instance);\n                            break;\n                        }\n                    }\n                } else {\n                    switch (seq[1]) {\n                    case 'A': /* Up */\n                        esp_linenoise_edit_history_next(instance, esp_LINENOISE_HISTORY_PREV);\n                        break;\n                    case 'B': /* Down */\n                        esp_linenoise_edit_history_next(instance, esp_LINENOISE_HISTORY_NEXT);\n                        break;\n                    case 'C': /* Right */\n                        esp_linenoise_edit_move_right(instance);\n                        break;\n                    case 'D': /* Left */\n                        esp_linenoise_edit_move_left(instance);\n                        break;\n                    case 'H': /* Home */\n                        esp_linenoise_edit_move_home(instance);\n                        break;\n                    case 'F': /* End*/\n                        esp_linenoise_edit_move_end(instance);\n                        break;\n                    }\n                }\n            }\n            /* ESC O sequences. */\n            else if (seq[0] == 'O') {\n                int r = config->read_bytes_cb(in_fd, seq + 1, 1);\n                if (r != 1) {\n                    return -1;\n                }\n                switch (seq[1]) {\n                case 'H': /* Home */\n                    esp_linenoise_edit_move_home(instance);\n                    break;\n                case 'F': /* End*/\n                    esp_linenoise_edit_move_end(instance);\n                    break;\n                }\n            }\n            break;\n        }\n        default:\n            if (esp_linenoise_edit_insert(instance, c)) {\n                return -1;\n            }\n            break;\n        }\n        fsync(instance->config.out_fd);\n    }\n    return state->len;\n}\n\nstatic int esp_linenoise_raw(esp_linenoise_instance_t *instance, char *buffer, size_t buffer_length)\n{\n    esp_linenoise_config_t *config = &instance->config;\n\n    int count;\n\n    if (buffer_length == 0) {\n        errno = EINVAL;\n        return -1;\n    }\n\n    count = esp_linenoise_edit(instance, buffer, buffer_length);\n    config->write_bytes_cb(config->out_fd, \"\\n\", 1);\n    return count;\n}\n\nstatic int esp_linenoise_dumb(esp_linenoise_instance_t *instance, char *buffer, size_t buffer_length)\n{\n    esp_linenoise_config_t *config = &instance->config;\n\n    config->write_bytes_cb(instance->config.out_fd, config->prompt, strlen(config->prompt));\n\n    size_t count = 0;\n    const int in_fd = instance->config.in_fd;\n    char c = 'c';\n\n    // leave the last character free so the user can null terminate the string if needed,\n    // also, this is to be consistent with esp_linenoise_edit()\n    bool exit_loop = false;\n    while (!exit_loop) {\n        int nread = config->read_bytes_cb(in_fd, &c, 1);\n        if (nread < 0) {\n            exit_loop = true;\n            count = nread;\n            continue;\n        }\n        if (c == '\\n') {\n            exit_loop = true;\n            continue;\n        }\n        // if the number of bytes are reached, wait for the user to input\n        // a new line character to return, just like in esp_linenoise_edit()\n        if (count >= buffer_length - 1) {\n            continue;\n        } else if (c == BACKSPACE || c == CTRL_H) {\n            if (count > 0) {\n                buffer[count - 1] = 0;\n                count--;\n\n                /* Only erase symbol echoed from in_fd. */\n                char erase_symbol_str[] = \"\\x08\";\n                config->write_bytes_cb(instance->config.out_fd, erase_symbol_str, sizeof(erase_symbol_str)); /* Windows CMD: erase symbol under cursor */\n            } else {\n                /* Consume backspace if the command line is empty to avoid erasing the prompt */\n                continue;\n            }\n\n        } else if (c <= UNIT_SEP) {\n            /* Consume all character that are non printable (the backspace\n             * case is handled above) */\n            continue;\n        } else {\n            buffer[count] = c;\n            ++count;\n        }\n        config->write_bytes_cb(instance->config.out_fd, &c, 1); /* echo */\n    }\n    config->write_bytes_cb(instance->config.out_fd, \"\\n\", 1);\n\n    // null terminate the string\n    buffer[count + 1] = '\\0';\n\n    return count;\n}\n\nstatic void esp_linenoise_sanitize(char *src)\n{\n    char *dst = src;\n    for (int c = *src; c != 0; src++, c = *src) {\n        if (isprint(c)) {\n            *dst = c;\n            ++dst;\n        }\n    }\n    *dst = 0;\n}\n\nint esp_linenoise_probe(esp_linenoise_handle_t handle)\n{\n    esp_linenoise_instance_t *instance = (esp_linenoise_instance_t *)handle;\n\n    /* Make sure we are in non blocking mode before performing the terminal probing */\n    int fd_in = instance->config.in_fd;\n    int out_fd = instance->config.out_fd;\n    int old_flags = fcntl(fd_in, F_GETFL);\n    int new_flags = old_flags | O_NONBLOCK;\n    int res = fcntl(fd_in, F_SETFL, new_flags);\n    if (res != 0) {\n        return -1;\n    }\n\n    /* Device status request */\n    char status_request_str[] = \"\\x1b[5n\";\n    instance->config.write_bytes_cb(out_fd, status_request_str, sizeof(status_request_str));\n\n    /* Try to read response */\n    int timeout_ms = 500;\n    const int retry_ms = 10;\n    size_t read_bytes = 0;\n    while (timeout_ms > 0 && read_bytes < 4) { // response is ESC[0n or ESC[3n\n        usleep(retry_ms * 1000);\n        timeout_ms -= retry_ms;\n        char c;\n        int cb = instance->config.read_bytes_cb(fd_in, &c, 1);\n        if (cb < 0) {\n            continue;\n        }\n        if (read_bytes == 0 && c != ESC) {\n            /* invalid response, try again until the timeout triggers */\n            continue;\n        }\n        read_bytes += cb;\n    }\n\n    /* Switch back to whatever mode we had before the function call */\n    res = fcntl(fd_in, F_SETFL, old_flags);\n    if (res != 0) {\n        return -1;\n    }\n\n    if (read_bytes < 4) {\n        return -2;\n    }\n\n    return 0;\n}\n\n#define ESP_LINENOISE_CHECK_INSTANCE(handle)    \\\n    if(handle == NULL) {                        \\\n        return ESP_ERR_INVALID_ARG;             \\\n}\n\nvoid esp_linenoise_get_instance_config_default(esp_linenoise_config_t *config)\n{\n    *config = (esp_linenoise_config_t) {\n        .prompt = ESP_LINENOISE_DEFAULT_PROMPT,\n        .max_cmd_line_length = ESP_LINENOISE_DEFAULT_MAX_LINE,\n        .history_max_length = ESP_LINENOISE_DEFAULT_HISTORY_MAX_LENGTH,\n        .in_fd = STDIN_FILENO,\n        .out_fd = STDOUT_FILENO,\n        .allow_multi_line = false,  /* Multi line mode. Default is single line. */\n        .allow_empty_line = true, /* Allow linenoise to return an empty string. On by default */\n        .allow_dumb_mode = false, /* Dumb mode where line editing is disabled. Off by default */\n        .completion_cb = NULL,\n        .hints_cb = NULL,\n        .free_hints_cb = NULL,\n        .write_bytes_cb = esp_linenoise_default_write_bytes,\n        .read_bytes_cb = esp_linenoise_default_read_bytes,\n        .history = NULL,\n    };\n}\n\nesp_err_t esp_linenoise_create_instance(const esp_linenoise_config_t *config, esp_linenoise_handle_t *out_handle)\n{\n    if (!config || !out_handle) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    /* make sure the history is NULL since the linenoise library will allocate it */\n    if (config->history != NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    esp_linenoise_instance_t *instance = malloc(sizeof(esp_linenoise_instance_t));\n    if (!instance) {\n        return ESP_ERR_NO_MEM;\n    }\n\n    instance->config = *config;\n\n    /* set the state part of the esp_linenoise_instance_t to 0 to\n     * init all values to 0 (or NULL) */\n    memset(&instance->state, 0x00, sizeof(esp_linenoise_state_t));\n\n    if (instance->config.in_fd == -1) {\n        instance->config.in_fd = STDIN_FILENO;\n    }\n    if (instance->config.out_fd == -1) {\n        instance->config.out_fd = STDOUT_FILENO;\n    }\n    if (!instance->config.prompt) {\n        instance->config.prompt = ESP_LINENOISE_DEFAULT_PROMPT;\n    }\n    if (!instance->config.max_cmd_line_length) {\n        instance->config.max_cmd_line_length = ESP_LINENOISE_DEFAULT_MAX_LINE;\n    }\n    if (!instance->config.history_max_length) {\n        instance->config.history_max_length = ESP_LINENOISE_DEFAULT_HISTORY_MAX_LENGTH;\n    }\n    if (instance->config.write_bytes_cb == NULL) {\n        instance->config.write_bytes_cb = esp_linenoise_default_write_bytes;\n    }\n    if ((instance->config.read_bytes_cb == NULL) ||\n            (instance->config.read_bytes_cb == esp_linenoise_default_read_bytes)) {\n        /* since we are using the default read function, make sure\n         * blocking read are set */\n        int flags = fcntl(instance->config.in_fd, F_GETFL, 0);\n        flags &= ~O_NONBLOCK;\n        fcntl(instance->config.in_fd, F_SETFL, flags);\n        instance->config.read_bytes_cb = esp_linenoise_default_read_bytes;\n\n        if (esp_linenoise_set_event_fd != NULL) {\n            const esp_err_t ret_val = esp_linenoise_set_event_fd(instance);\n            if (ret_val != ESP_OK) {\n                free(instance);\n                return ret_val;\n            }\n        } else {\n            /* make sure the state->mux is set to NULL */\n            instance->state.mux = NULL;\n        }\n    }\n\n    const int probe_status = esp_linenoise_probe(instance);\n    if (probe_status == 0) {\n        /* escape sequences supported*/\n        instance->config.allow_dumb_mode = false;\n    } else {\n        /* error during the probing or escape sequences not supported */\n        instance->config.allow_dumb_mode = true;\n\n        char buf[256];\n        int len = snprintf(buf, sizeof(buf),\n                           \"\\r\\n\"\n                           \"Your terminal application does not support escape sequences.\\n\\n\"\n                           \"Line editing and history features are disabled.\\n\\n\"\n                           \"On Windows, try using Windows Terminal or Putty instead.\\r\\n\");\n\n        instance->config.write_bytes_cb(instance->config.out_fd, buf, len);\n    }\n\n    *out_handle =  (esp_linenoise_handle_t)instance;\n\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_delete_instance(esp_linenoise_handle_t handle)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n\n    esp_linenoise_instance_t *instance = (esp_linenoise_instance_t *)handle;\n\n    // free the history first since it was allocated by linenoise\n    esp_err_t ret_val = esp_linenoise_history_free(handle);\n    if (ret_val != ESP_OK) {\n        return ret_val;\n    }\n\n    // delete the mutex in the state and close the eventfd\n    // if it was created\n    if ((instance->config.write_bytes_cb == esp_linenoise_default_write_bytes) &&\n            (esp_linenoise_remove_event_fd != NULL)) {\n        ret_val = esp_linenoise_remove_event_fd(instance);\n        if (ret_val != ESP_OK) {\n            return ret_val;\n        }\n    }\n    // reset the memory\n    memset(instance, 0x00, sizeof(esp_linenoise_instance_t));\n\n    // free the instance\n    free(instance);\n\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_get_line(esp_linenoise_handle_t handle, char *cmd_line_buffer, size_t cmd_line_length)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n\n    if (cmd_line_buffer == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    esp_linenoise_instance_t *instance = (esp_linenoise_instance_t *)handle;\n    esp_linenoise_config_t *config = &instance->config;\n    esp_linenoise_state_t *state = &instance->state;\n\n    if ((cmd_line_length == 0) || (cmd_line_length > config->max_cmd_line_length)) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    /* take the mutex, it will be released only when esp_linenoise_raw\n     * or esp_linenoise_dumb returns */\n    if (state->mux != NULL) {\n        (void)xSemaphoreTake(state->mux, portMAX_DELAY);\n    }\n\n    int count = 0;\n    if (!config->allow_dumb_mode) {\n        count = esp_linenoise_raw(instance, cmd_line_buffer, cmd_line_length);\n    } else {\n        count = esp_linenoise_dumb(instance, cmd_line_buffer, cmd_line_length);\n    }\n\n    esp_err_t ret_val = ESP_OK;\n    if (count > 0) {\n        esp_linenoise_sanitize(cmd_line_buffer);\n    } else if (count == 0 && config->allow_empty_line) {\n        /* will return an empty (0-length) string */\n    } else {\n        ret_val = ESP_FAIL;\n    }\n\n    /* release the mutex, signaling that esp_linenoise_get_line returned */\n    if (state->mux != NULL) {\n        xSemaphoreGive(state->mux);\n    }\n\n    return ret_val;\n}\n\nvoid esp_linenoise_add_completion(void *ctx, const char *str)\n{\n    if ((ctx == NULL) || str == NULL) {\n        return;\n    }\n\n    esp_linenoise_completions_t *lc = (esp_linenoise_completions_t *)ctx;\n\n    size_t len = strlen(str);\n    char *copy, **cvec;\n\n    copy = malloc(len + 1);\n    if (copy == NULL) {\n        return;\n    }\n    memcpy(copy, str, len + 1);\n    cvec = realloc(lc->cvec, sizeof(char *) * (lc->len + 1));\n    if (cvec == NULL) {\n        free(copy);\n        return;\n    }\n\n    cvec[lc->len] = copy;  // Store copy in new slot before updating struct\n    lc->cvec = cvec;\n    lc->len++;\n}\n\nesp_err_t esp_linenoise_history_add(esp_linenoise_handle_t handle, const char *line)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n\n    if (line == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    esp_linenoise_config_t *config = &((esp_linenoise_instance_t *)handle)->config;\n    esp_linenoise_state_t *state = &((esp_linenoise_instance_t *)handle)->state;\n\n    if (config->history_max_length == 0) {\n        return ESP_ERR_NO_MEM;\n    }\n\n    /* Initialization on first calstate. */\n    if (config->history == NULL) {\n        config->history = malloc(sizeof(char *) * config->history_max_length);\n        if (config->history == NULL) {\n            return ESP_ERR_NO_MEM;\n        }\n        memset(config->history, 0, (sizeof(char *) * config->history_max_length));\n\n        state->history_length = 0;\n    }\n\n    /* Don't add duplicated lines. */\n    if ((state->history_length == 0) ||\n            (strcmp(config->history[state->history_length - 1], line) != 0)) {\n\n        /* Add an heap allocated copy of the line in the history.\n        * If we reached the max length, remove the older line. */\n        char *line_copy = strdup(line);\n        if (!line_copy) {\n            return ESP_ERR_NO_MEM;\n        }\n        if (state->history_length == config->history_max_length) {\n            free(config->history[0]);\n            memmove(config->history, config->history + 1, sizeof(char *) * (config->history_max_length - 1));\n            state->history_length--;\n        }\n        config->history[state->history_length] = line_copy;\n        state->history_length++;\n    }\n\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_history_save(esp_linenoise_handle_t handle, const char *filename)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n\n    if (filename == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    esp_linenoise_instance_t *instance = (esp_linenoise_instance_t *)handle;\n    FILE *fp;\n    int j;\n\n    fp = fopen(filename, \"w\");\n    if (fp == NULL) {\n        return ESP_FAIL;\n    }\n\n    for (j = 0; j < instance->state.history_length; j++) {\n        fprintf(fp, \"%s\\n\", instance->config.history[j]);\n    }\n\n    fclose(fp);\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_history_load(esp_linenoise_handle_t handle, const char *filename)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n\n    if (filename == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    esp_linenoise_instance_t *instance = (esp_linenoise_instance_t *)handle;\n\n    FILE *fp = fopen(filename, \"r\");\n    if (fp == NULL) {\n        return ESP_FAIL;\n    }\n\n    char *buf = calloc(1, instance->config.max_cmd_line_length);\n    if (buf == NULL) {\n        fclose(fp);\n        return ESP_ERR_NO_MEM;\n    }\n\n    while (fgets(buf, instance->config.max_cmd_line_length, fp) != NULL) {\n        char *p;\n\n        p = strchr(buf, '\\r');\n        if (!p) {\n            p = strchr(buf, '\\n');\n        }\n        if (p) {\n            *p = '\\0';\n        }\n        const esp_err_t ret_val = esp_linenoise_history_add(handle, buf);\n        if (ret_val != ESP_OK) {\n            free(buf);\n            fclose(fp);\n            return ret_val;\n        }\n    }\n\n    free(buf);\n    fclose(fp);\n\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_history_set_max_len(esp_linenoise_handle_t handle, int new_length)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n\n    esp_linenoise_config_t *config = &((esp_linenoise_instance_t *)handle)->config;\n    esp_linenoise_state_t *state = &((esp_linenoise_instance_t *)handle)->state;\n\n    if (new_length == config->history_max_length) {\n        /* the requested history size is the same as the current\n         * one, return ok without changing anything */\n        return ESP_OK;\n    }\n    if (new_length < 1) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    char **new_history;\n    if (config->history) {\n        int to_copy = state->history_length;\n\n        new_history = malloc(sizeof(char *) * new_length);\n        if (new_history == NULL) {\n            return ESP_ERR_NO_MEM;\n        }\n\n        /* If we can't copy everything, free the elements we'll not use. */\n        if (new_length < to_copy) {\n            int j;\n\n            for (j = 0; j < to_copy - new_length; j++) {\n                free(config->history[j]);\n            }\n            to_copy = new_length;\n        }\n        memset(new_history, 0, sizeof(char *) * new_length);\n        memcpy(new_history, config->history + (state->history_length - to_copy), sizeof(char *)*to_copy);\n        free(config->history);\n        config->history = new_history;\n    }\n\n    config->history_max_length = new_length;\n\n    if (state->history_length > config->history_max_length) {\n        state->history_length = config->history_max_length;\n    }\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_history_free(esp_linenoise_handle_t handle)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n    esp_linenoise_instance_t *instance = (esp_linenoise_instance_t *)handle;\n\n    if (instance->config.history) {\n        for (int j = 0; j < instance->state.history_length; j++) {\n            free(instance->config.history[j]);\n        }\n        free(instance->config.history);\n    }\n    instance->config.history = NULL;\n    instance->state.history_length = 0;\n\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_clear_screen(esp_linenoise_handle_t handle)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n    esp_linenoise_instance_t *instance = (esp_linenoise_instance_t *)handle;\n    esp_linenoise_config_t *config = &instance->config;\n\n    char erase_screen_str[] = \"\\x1b[H\\x1b[2J\";\n    size_t msg_size = sizeof(erase_screen_str);\n    ssize_t nb_bytes = config->write_bytes_cb(config->out_fd, erase_screen_str, msg_size);\n    if (nb_bytes < 0 || nb_bytes != msg_size) {\n        return ESP_FAIL;\n    }\n\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_set_empty_line(esp_linenoise_handle_t handle, bool empty_line)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n    ((esp_linenoise_instance_t *)handle)->config.allow_empty_line = empty_line;\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_is_empty_line(esp_linenoise_handle_t handle, bool *is_empty_line)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n\n    if (is_empty_line == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    *is_empty_line = ((esp_linenoise_instance_t *)handle)->config.allow_empty_line;\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_set_multi_line(esp_linenoise_handle_t handle, bool multi_line)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n    ((esp_linenoise_instance_t *)handle)->config.allow_multi_line = multi_line;\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_is_multi_line(esp_linenoise_handle_t handle, bool *is_multi_line)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n\n    if (is_multi_line == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    *is_multi_line = ((esp_linenoise_instance_t *)handle)->config.allow_multi_line;\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_set_dumb_mode(esp_linenoise_handle_t handle, bool dumb_mode)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n    ((esp_linenoise_instance_t *)handle)->config.allow_dumb_mode = dumb_mode;\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_is_dumb_mode(esp_linenoise_handle_t handle, bool *is_dumb_mode)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n\n    if (is_dumb_mode == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    *is_dumb_mode = ((esp_linenoise_instance_t *)handle)->config.allow_dumb_mode;\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_set_max_cmd_line_length(esp_linenoise_handle_t handle, size_t length)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n    if (length >= ESP_LINENOISE_MINIMAL_MAX_LINE) {\n        ((esp_linenoise_instance_t *)handle)->config.max_cmd_line_length = length;\n    } else {\n        return ESP_ERR_INVALID_ARG;\n    }\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_get_max_cmd_line_length(esp_linenoise_handle_t handle, size_t *max_cmd_line_length)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n\n    if (max_cmd_line_length == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    *max_cmd_line_length = ((esp_linenoise_instance_t *)handle)->config.max_cmd_line_length;\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_set_prompt(esp_linenoise_handle_t handle, const char *prompt)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n\n    if (prompt == NULL || strlen(prompt) == 0) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    ((esp_linenoise_instance_t *)handle)->config.prompt = prompt;\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_get_prompt(esp_linenoise_handle_t handle, const char **prompt)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n\n    if (prompt == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    *prompt = ((esp_linenoise_instance_t *)handle)->config.prompt;\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_get_out_fd(esp_linenoise_handle_t handle, int *fd)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n\n    if (fd == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    *fd = handle->config.out_fd;\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_get_in_fd(esp_linenoise_handle_t handle, int *fd)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n\n    if (fd == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    *fd = handle->config.in_fd;\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_get_read(esp_linenoise_handle_t handle, esp_linenoise_read_bytes_t *read_func)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n\n    if (read_func == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    *read_func = handle->config.read_bytes_cb;\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_get_write(esp_linenoise_handle_t handle, esp_linenoise_write_bytes_t *write_func)\n{\n    ESP_LINENOISE_CHECK_INSTANCE(handle);\n\n    if (write_func == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    *write_func = handle->config.write_bytes_cb;\n    return ESP_OK;\n}\n"
  },
  {
    "path": "esp_linenoise/src/esp_linenoise_internals.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <unistd.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <fcntl.h>\n#include <sys/param.h>\n#include \"sys/queue.h\"\n#include \"esp_err.h\"\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/semphr.h\"\n#include \"esp_vfs_eventfd.h\"\n#include \"esp_linenoise.h\"\n#include \"esp_linenoise_private.h\"\n\ntypedef struct eventfd_pair {\n    int eventfd;\n    int in_fd;\n    SLIST_ENTRY(eventfd_pair) next_pair;\n} eventfd_pair_t;\n\nstatic const uint64_t s_abort_signal = 1;\nstatic SLIST_HEAD(eventfd_pair_ll, eventfd_pair) s_eventfd_pairs = SLIST_HEAD_INITIALIZER(eventfd_pair);\n\nstatic int esp_linenoise_get_eventfd_from_fd(const int fd)\n{\n    /* find the eventfd to use to abort for the given fd */\n    eventfd_pair_t *eventfd_pair = NULL;\n    SLIST_FOREACH(eventfd_pair, &s_eventfd_pairs, next_pair) {\n        if (eventfd_pair->in_fd == fd) {\n            return eventfd_pair->eventfd;\n        }\n    }\n\n    return -1;\n}\n\nssize_t esp_linenoise_default_read_bytes(int fd, void *buf, size_t count)\n{\n    if ((fcntl(fd, F_GETFL, 0) & O_NONBLOCK) != 0) {\n        /* non blocking read, call read directly */\n        return read(fd, buf, count);\n    }\n\n    fd_set read_fds;\n    FD_ZERO(&read_fds);\n    FD_SET(fd, &read_fds);\n\n    /* find the eventfd to use to abort for the given fd */\n    int max_fd = -1;\n    int abort_read_fd = esp_linenoise_get_eventfd_from_fd(fd);\n    if (abort_read_fd != -1) {\n        FD_SET(abort_read_fd, &read_fds);\n        max_fd = MAX(fd, abort_read_fd);\n    } else {\n        max_fd = fd;\n    }\n\n    /* call select to wait for data to read or an abort signal */\n    int nread = select(max_fd + 1, &read_fds, NULL, NULL, NULL);\n    if (nread < 0) {\n        return -1;\n    }\n\n    if (FD_ISSET(abort_read_fd, &read_fds)) {\n        /* read termination request happened, return */\n        int temp_buf[sizeof(s_abort_signal)];\n        nread = read(abort_read_fd, temp_buf, sizeof(s_abort_signal));\n        if ((nread == sizeof(s_abort_signal)) && (temp_buf[0] == s_abort_signal)) {\n            /* populate the buffer with a new line character, forcing esp_linenoise_raw\n            * or esp_linenoise_dumb to return */\n            nread = 1;\n            memcpy(buf, \"\\n\", 1);\n        }\n    } else if (FD_ISSET(fd, &read_fds)) {\n        /* a read ready triggered the select to return. call the\n        * read function with the number of bytes max_bytes */\n        nread = read(fd, buf, count);\n    }\n    return nread;\n}\n\nesp_err_t esp_linenoise_set_event_fd(esp_linenoise_instance_t *instance)\n{\n    esp_linenoise_config_t *config = &instance->config;\n    esp_linenoise_state_t *state = &instance->state;\n\n    /* Tell linenoise what file descriptor to add to the read file descriptor set,\n     * that will be used to signal a read termination */\n    esp_vfs_eventfd_config_t eventfd_config = {\n        .max_fds = CONFIG_ESP_LINENOISE_MAX_INSTANCE_NB\n    };\n    esp_err_t ret = esp_vfs_eventfd_register(&eventfd_config);\n    int new_eventfd = -1;\n    if (ret != ESP_ERR_INVALID_ARG) {\n        new_eventfd = eventfd(0, 0);\n    } else {\n        /* issue with arg, this should not happen */\n        return ESP_FAIL;\n    }\n\n    /* make sure the FD returned is not -1, which would indicate that eventfd\n     * has reached the maximum number of FDs it can create */\n    if (new_eventfd == -1) {\n        return ESP_FAIL;\n    }\n\n    state->mux = xSemaphoreCreateMutex();\n    if (state->mux == NULL) {\n        close(new_eventfd);\n        return ESP_ERR_NO_MEM;\n    }\n\n    /* one eventfd will be created for a given instance. In order to be able\n     * to use the proper eventfd in the read, couple the created eventfd to\n     * the in_fd from the config of the given instance. */\n    eventfd_pair_t *new_pair = malloc(sizeof(eventfd_pair_t));\n    if (new_pair == NULL) {\n        close(new_eventfd);\n        vSemaphoreDelete(state->mux);\n        return ESP_ERR_NO_MEM;\n    }\n    new_pair->eventfd = new_eventfd;\n    new_pair->in_fd = config->in_fd;\n    SLIST_INSERT_HEAD(&s_eventfd_pairs, new_pair, next_pair);\n\n    xSemaphoreGive(state->mux);\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_remove_event_fd(esp_linenoise_instance_t *instance)\n{\n    esp_linenoise_config_t *config = &instance->config;\n    esp_linenoise_state_t *state = &instance->state;\n\n    /* find the in_fd in the list of eventfd / in_fd pairs.\n     * if found, remove the item from the list, close the eventfd */\n    eventfd_pair_t *cur = NULL;\n    eventfd_pair_t *prev = NULL;\n    SLIST_FOREACH(cur, &s_eventfd_pairs, next_pair) {\n        if (cur->in_fd == config->in_fd) {\n            /* close the eventfd */\n            close(cur->eventfd);\n\n            if (prev == NULL) {\n                /* remove head */\n                SLIST_REMOVE_HEAD(&s_eventfd_pairs, next_pair);\n            } else {\n                /* remove item in the middle of the list */\n                prev->next_pair.sle_next = cur->next_pair.sle_next;\n            }\n\n            /* return from the loop */\n            break;\n        }\n\n        prev = cur;\n    }\n\n    if (cur == NULL) {\n        return ESP_ERR_NOT_FOUND;\n    }\n\n    /* free the item that was removed */\n    free(cur);\n\n    /* free the mutex */\n    vSemaphoreDelete(state->mux);\n\n    /* if the list is empty, it means the last instance of esp_linenoise\n     * running is being deleted. Unregister eventfd to free the heap memory\n     * allocated when calling esp_vfs_eventfd_register */\n    if (SLIST_EMPTY(&s_eventfd_pairs)) {\n        return esp_vfs_eventfd_unregister();\n    }\n\n    return ESP_OK;\n}\n\nesp_err_t esp_linenoise_abort(esp_linenoise_handle_t handle)\n{\n    esp_linenoise_config_t *config = &handle->config;\n    esp_linenoise_state_t *state = &handle->state;\n\n    if (config->read_bytes_cb != esp_linenoise_default_read_bytes) {\n        /* we are not using the default read bytes function provided\\\n         * by esp_linenoise, therefore it is not esp_linenoise responsibility\n         * to trigger the return from esp_linenoise_get_line */\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    /* send the signal to force esp_linenoise_default_read_bytes\n     * to return */\n    int abort_read_fd = esp_linenoise_get_eventfd_from_fd(config->in_fd);\n    if (abort_read_fd == -1) {\n        return ESP_FAIL;\n    }\n\n    int nwrite = write(abort_read_fd, &s_abort_signal, sizeof(s_abort_signal));\n    if (nwrite != sizeof(s_abort_signal)) {\n        return ESP_FAIL;\n    }\n\n    /* wait for esp_linenoise_get_line to signal it returned */\n    (void)xSemaphoreTake(state->mux, portMAX_DELAY);\n\n    /* mutex acquired successfully, esp_linenoise_get_line returned\n     * we can release the mutex directly so it can be taken again\n     * when esp_linenoise_get_line is called again */\n    xSemaphoreGive(state->mux);\n\n    return ESP_OK;\n}\n"
  },
  {
    "path": "esp_linenoise/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.22)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(esp_linenoise_test)\n"
  },
  {
    "path": "esp_linenoise/test_apps/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"test_esp_linenoise_get_set.c\"\n                            \"test_esp_linenoise_behavioral.c\"\n                            \"test_linenoise_legacy.c\"\n                            \"test_utils.c\"\n                            \"test_main.c\"\n                    PRIV_INCLUDE_DIRS \".\" \"include\"\n                    PRIV_REQUIRES unity\n                    WHOLE_ARCHIVE)\n"
  },
  {
    "path": "esp_linenoise/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/esp_linenoise:\n    version: \"*\"\n    override_path: \"../..\"\n"
  },
  {
    "path": "esp_linenoise/test_apps/main/include/test_utils.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <sys/time.h>\n\n#define CMD_LINE_LENGTH 32 /* set to the value of ESP_LINENOISE_COMMAND_MAX_LEN */\n\n#define COMPOUND_LITERAL(x) ((char[]){(char)x, '\\0'})\nenum KEY_ACTION {\n    KEY_NULL = 0,       /* NULL */\n    CTRL_A = 1,         /* Ctrl+a */\n    CTRL_B = 2,         /* Ctrl-b */\n    CTRL_C = 3,         /* Ctrl-c */\n    CTRL_D = 4,         /* Ctrl-d */\n    CTRL_E = 5,         /* Ctrl-e */\n    CTRL_F = 6,         /* Ctrl-f */\n    CTRL_H = 8,         /* Ctrl-h */\n    TAB = 9,            /* Tab */\n    CTRL_K = 11,        /* Ctrl+k */\n    CTRL_L = 12,        /* Ctrl+l */\n    ENTER = 10,         /* Enter */\n    CTRL_N = 14,        /* Ctrl-n */\n    CTRL_P = 16,        /* Ctrl-p */\n    CTRL_T = 20,        /* Ctrl-t */\n    CTRL_U = 21,        /* Ctrl+u */\n    CTRL_W = 23,        /* Ctrl+w */\n    ESC = 27,           /* Escape */\n    UNIT_SEP = 31,      /* ctrl-_ */\n    BACKSPACE =  127    /* Backspace */\n};\n\ntypedef struct command {\n    const char *request;\n    const char *response;\n} command_t;\n\nextern const command_t commands[];\nextern const size_t commands_count;\n\ninline __attribute__((always_inline))\nuint32_t get_millis(void)\n{\n    struct timeval tv = { 0 };\n    gettimeofday(&tv, NULL);\n    return tv.tv_sec * 1000 + tv.tv_usec / 1000;\n}\n\ninline __attribute__((always_inline))\nvoid wait_ms(int ms)\n{\n    int cur_time = 0;\n    const int timeout = get_millis() + ms;\n    do {\n        cur_time = get_millis();\n    } while (cur_time < timeout);\n}\n\nvoid test_send_characters(int socket_fd, const char *msg);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_linenoise/test_apps/main/test_esp_linenoise_behavioral.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include <stdio.h>\n#include <sys/socket.h>\n#include <pthread.h>\n#include <sys/time.h>\n#include <errno.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"fcntl.h\"\n#include \"unity.h\"\n#include \"esp_linenoise.h\"\n#include \"test_utils.h\"\n\nstatic int s_socket_fd_a[2];\nstatic int s_socket_fd_b[2];\nstatic esp_linenoise_handle_t s_linenoise_hdl;\nstatic char s_line_returned[CMD_LINE_LENGTH] = {0};\n\nstatic bool s_completions_called = false;\nstatic bool s_hint_called = false;\nstatic bool s_free_hint_called = false;\n\nstatic void custom_completion_cb(const char *str, void *cb_ctx, esp_linenoise_completion_cb_t cb)\n{\n    // we just want to see that the callback is indeed called\n    // so flip the s_completions_called to true\n    if (!s_completions_called) {\n        s_completions_called = true;\n    }\n}\n\nstatic char *custom_hint_cb(const char *str, int *color, int *bold)\n{\n    // we just want to see that the callback is indeed called\n    // so flip the s_hint_called to true\n    if (!s_hint_called) {\n        s_hint_called = true;\n    }\n\n    return \"something\";\n}\n\nstatic void custom_free_hint_cb(void *ptr)\n{\n    // we just want to see that the callback is indeed called\n    // so flip the s_free_hint_called to true\n    if (!s_free_hint_called) {\n        s_free_hint_called = true;\n    }\n}\n\nstatic ssize_t custom_read(int fd, void *buf, size_t count)\n{\n    int nread = -1;\n    fd_set rfds;\n    FD_ZERO(&rfds);\n    FD_SET(fd, &rfds);\n    int ret = select(fd + 1, &rfds, NULL, NULL, NULL);\n    if (ret > 0 && FD_ISSET(fd, &rfds)) {\n        nread = read(fd, buf, count);\n    }\n\n    return nread;\n}\n\nstatic ssize_t custom_write(int fd, const void *buf, size_t count)\n{\n    // find the request in the list of commands and send the response\n    for (size_t i = 0; i < commands_count; i++) {\n        if (strstr(commands[i].request, buf) != NULL) {\n            const char *response = commands[i].response;\n            if (response != NULL) {\n                const size_t size = strlen(commands[i].response);\n\n                // write the expected response to the socket, so linenoise\n                // can read the response\n                // conveniently, the socketpair FDs are following each other so\n                // to simulate a write from the device, call write on fd + 1\n                const ssize_t nwrite = write(fd + 1, response, size);\n                TEST_ASSERT_EQUAL(size, nwrite);\n            }\n\n            // return the count like a normal write would do\n            // do not propagate to the socket to not pollute\n            // the buffers\n            return count;\n        }\n    }\n\n    // otherwise just propagate the write\n    return write(fd, buf, count);\n}\n\nstatic void test_instance_setup(int socket_fd[2], pthread_mutex_t *lock, esp_linenoise_config_t *config)\n{\n    // 2 fd are generated, simulating the full-duplex\n    // communication between linenoise and the terminal\n    TEST_ASSERT_EQUAL(0, socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fd));\n\n    // assure that the read will be blocking\n    int flags = fcntl(socket_fd[0], F_GETFL, 0);\n    flags &= ~O_NONBLOCK;\n    fcntl(socket_fd[0], F_SETFL, flags);\n\n    flags = fcntl(socket_fd[1], F_GETFL, 0);\n    flags &= ~O_NONBLOCK;\n    fcntl(socket_fd[0], F_SETFL, flags);\n\n    esp_linenoise_get_instance_config_default(config);\n\n    // all data written by the test on socket_fd[1] will\n    // bbe available for reading on socket_fd[0]. All data\n    // written to socket_fd[0] will be available for reading\n    // on socket_fd[1].\n    config->in_fd = socket_fd[0];\n    config->out_fd = socket_fd[0];\n\n    // redirect read and write calls from linenoise to be able\n    // to e.g., process sequences sent from linenoise and thus\n    // simulate that the terminal supports escape sequences\n    config->read_bytes_cb = custom_read;\n    config->write_bytes_cb = custom_write;\n\n    // take the semaphore\n    pthread_mutex_lock(lock);\n}\n\nstatic void test_instance_teardown(int socket_fd[2], esp_linenoise_handle_t handle, pthread_mutex_t *lock)\n{\n    memset(s_line_returned, 0, CMD_LINE_LENGTH);\n\n    esp_linenoise_delete_instance(handle);\n    close(socket_fd[0]);\n    close(socket_fd[1]);\n\n    // unlock the mutex for the next test\n    pthread_mutex_destroy(lock);\n}\n\ntypedef struct get_line_args {\n    pthread_mutex_t *lock;\n    TaskHandle_t parent_task;\n    esp_linenoise_config_t *config;\n} get_line_args_t;\n\nstatic void get_line_task(void *args)\n{\n    get_line_args_t *task_args = (get_line_args_t *)args;\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_create_instance(task_args->config, &s_linenoise_hdl));\n    TEST_ASSERT_NOT_NULL(s_linenoise_hdl);\n\n    // wait for the instance to properly initialize before unlocking\n    // the mutex so the test can run\n    usleep(100000);\n\n    // release the mutex so the test can start sending data\n    pthread_mutex_unlock(task_args->lock);\n\n    esp_err_t ret_val = esp_linenoise_get_line(s_linenoise_hdl, s_line_returned, CMD_LINE_LENGTH);\n    TEST_ASSERT_EQUAL(ESP_OK, ret_val);\n\n    xTaskNotifyGive(task_args->parent_task);\n\n    vTaskDelete(NULL);\n}\n\ntypedef struct get_line_task_args {\n    esp_linenoise_handle_t handle;\n    TaskHandle_t parent_task;\n    pthread_mutex_t *lock;\n    esp_err_t ret_val;\n    char *buf;\n    size_t buf_size;\n} get_line_task_args_t;\n\nstatic void get_line_task_w_args(void *args)\n{\n    get_line_task_args_t *task_args = (get_line_task_args_t *)args;\n\n    // wait for the instance to properly initialize before unlocking\n    // the mutex so the test can run\n    usleep(100000);\n\n    // release the mutex so the test can start sending data\n    pthread_mutex_unlock(task_args->lock);\n\n    task_args->ret_val = esp_linenoise_get_line(task_args->handle, task_args->buf, task_args->buf_size);\n\n    xTaskNotifyGive(task_args->parent_task);\n    vTaskDelete(NULL);\n}\n\nTEST_CASE(\"esp_linenoise_get_line() returns line read from in_fd\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock, &config);\n\n    get_line_args_t args = { .lock = &lock, .parent_task = xTaskGetCurrentTaskHandle(), .config = &config };\n    xTaskCreate(get_line_task, \"freertos_task\", 2048, &args, 5, NULL);\n\n    // wait until the linenoise instance init is done, and the get line as started\n    // before sending test content\n    pthread_mutex_lock(&lock);\n\n    const char *input_line = \"unit test input\";\n    test_send_characters(s_socket_fd_a[1], input_line);\n\n    // Write newline to trigger prompt output + return from loop\n    test_send_characters(s_socket_fd_a[1], \"\\n\");\n\n    // wait for the task to terminate to continue\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    TEST_ASSERT_NOT_NULL(s_line_returned);\n    TEST_ASSERT_EQUAL_STRING(input_line, s_line_returned);\n\n    test_instance_teardown(s_socket_fd_a, s_linenoise_hdl, &lock);\n}\n\nTEST_CASE(\"custom prompt string appears on output\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock, &config);\n\n    const char *custom_prompt = \">>> \";\n    config.prompt = (char *)custom_prompt;  // cast away const as config expects char*\n\n    get_line_args_t args = { .lock = &lock, .parent_task = xTaskGetCurrentTaskHandle(), .config = &config };\n    xTaskCreate(get_line_task, \"freertos_task\", 2048, &args, 5, NULL);\n\n    // wait until the linenoise instance init is done, and the get line as started\n    // before sending test content\n    pthread_mutex_lock(&lock);\n\n    // Write newline to trigger prompt output + return from loop\n    test_send_characters(s_socket_fd_a[1], \"\\n\");\n\n    // wait for the task to terminate to continue\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    // Verify prompt string is found in output\n    char full_cmd_line[32] = {0};\n    const ssize_t nread = read(s_socket_fd_a[1], full_cmd_line, 32);\n    TEST_ASSERT_NOT_EQUAL(-1, nread);\n\n    TEST_ASSERT_NOT_NULL(strstr(full_cmd_line, custom_prompt));\n\n    test_instance_teardown(s_socket_fd_a, s_linenoise_hdl, &lock);\n}\n\nTEST_CASE(\"cursor left/right and insert edits input correctly\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock, &config);\n\n    get_line_args_t args = { .lock = &lock, .parent_task = xTaskGetCurrentTaskHandle(), .config = &config };\n    xTaskCreate(get_line_task, \"freertos_task\", 2048, &args, 5, NULL);\n\n    // wait until the linenoise instance init is done, and the get line as started\n    // before sending test content\n    pthread_mutex_lock(&lock);\n\n    // Send chars and control sequences:\n    // Step 1: insert 'a', 'b', 'c' => buffer: \"abc\", cursor at end\n    test_send_characters(s_socket_fd_a[1], \"abc\");\n\n    // Step 2: CTRL-B (move cursor left once), cursor between 'b' and 'c'\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_B));\n\n    // Step 3: insert 'X' => buffer: \"abXc\"\n    test_send_characters(s_socket_fd_a[1], \"X\");\n\n    // Step 4: CTRL-F (move cursor right), cursor after 'X'\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_F));\n\n    // Step 5: insert 'Y' => buffer: \"abXcY\"\n    test_send_characters(s_socket_fd_a[1], \"Y\");\n\n    // Step 6: send newline to finish input\n    test_send_characters(s_socket_fd_a[1], \"\\n\");\n\n    // wait for the task to terminate to continue\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    // The line returned should be \"abXcY\"\n    TEST_ASSERT_NOT_NULL(s_line_returned);\n    TEST_ASSERT_EQUAL_STRING(\"abXcY\", s_line_returned);\n\n    test_instance_teardown(s_socket_fd_a, s_linenoise_hdl, &lock);\n}\n\nTEST_CASE(\"CTRL-A moves cursor home, CTRL-E moves cursor end, inserts work correctly\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock, &config);\n\n    get_line_args_t args = { .lock = &lock, .parent_task = xTaskGetCurrentTaskHandle(), .config = &config };\n    xTaskCreate(get_line_task, \"freertos_task\", 2048, &args, 5, NULL);\n\n    // wait until the linenoise instance init is done, and the get line as started\n    // before sending test content\n    pthread_mutex_lock(&lock);\n\n    // ----- Test CTRL-A: move home -----\n    // Insert 'bcd'\n    test_send_characters(s_socket_fd_a[1], \"bcd\");\n\n    // CTRL-A: move cursor to start\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_A));\n\n    // Insert 'a' at beginning → \"abcd\"\n    test_send_characters(s_socket_fd_a[1], \"a\");\n\n    // CTRL-E to move to end\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_E));\n\n    // Insert 'e' at end → \"abcde\"\n    test_send_characters(s_socket_fd_a[1], \"e\");\n\n    // send new line character\n    test_send_characters(s_socket_fd_a[1], \"\\n\");\n\n    // wait for the task to terminate to continue\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    TEST_ASSERT_NOT_NULL(s_line_returned);\n    TEST_ASSERT_EQUAL_STRING(\"abcde\", s_line_returned);\n\n    test_instance_teardown(s_socket_fd_a, s_linenoise_hdl, &lock);\n}\n\nTEST_CASE(\"history navigation with CTRL-P / CTRL-N works correctly\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock, &config);\n\n    get_line_args_t args = { .lock = &lock, .parent_task = xTaskGetCurrentTaskHandle(), .config = &config };\n    xTaskCreate(get_line_task, \"freertos_task\", 2048, &args, 5, NULL);\n\n    // wait until the linenoise instance init is done, and the get line as started\n    // before sending test content\n    pthread_mutex_lock(&lock);\n\n    wait_ms(100);\n\n    // Add history entries in order: \"first\", \"second\", \"third\"\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_history_add(s_linenoise_hdl, \"first\"));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_history_add(s_linenoise_hdl, \"second\"));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_history_add(s_linenoise_hdl, \"third\"));\n\n    wait_ms(100);\n\n    // CTRL-P: get previous history command, should be \"third\"\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_P));\n\n    // CTRL-P: get previous history command, should be \"second\"\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_P));\n\n    // extend the \"second\" line to see if when we go back to it,\n    // it will print the updated line or the former line\n    test_send_characters(s_socket_fd_a[1], \"second\");\n\n    // CTRL-P: get previous history command, should be \"first\"\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_P));\n\n    // CTRL-N: get previous history command, should be \"second\"\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_N));\n\n    // Send newline to accept current line\n    test_send_characters(s_socket_fd_a[1], \"\\n\");\n\n    // wait for the task to terminate to continue\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    // Expect \"third\" as final returned line after navigation\n    TEST_ASSERT_NOT_NULL(s_line_returned);\n    TEST_ASSERT_EQUAL_STRING(\"secondsecond\", s_line_returned);\n\n    test_instance_teardown(s_socket_fd_a, s_linenoise_hdl, &lock);\n}\n\nTEST_CASE(\"backspace erases the character before the cursor\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock, &config);\n\n    get_line_args_t args = { .lock = &lock, .parent_task = xTaskGetCurrentTaskHandle(), .config = &config };\n    xTaskCreate(get_line_task, \"freertos_task\", 2048, &args, 5, NULL);\n\n    // wait until the linenoise instance init is done, and the get line as started\n    // before sending test content\n    pthread_mutex_lock(&lock);\n\n    // Insert \"abc\"\n    test_send_characters(s_socket_fd_a[1], \"abc\");\n\n    // BACKSPACE (127), buffer becomes \"ab\"\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(BACKSPACE));\n\n    // CTRL-H (8), buffer becomes \"a\"\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_H));\n\n    // Insert \"aa\", buffer becomes \"aaa\"\n    test_send_characters(s_socket_fd_a[1], \"aa\");\n\n    // Newline (accept)\n    test_send_characters(s_socket_fd_a[1], \"\\n\");\n\n    // wait for the task to terminate to continue\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    TEST_ASSERT_NOT_NULL(s_line_returned);\n    TEST_ASSERT_EQUAL_STRING(\"aaa\", s_line_returned);\n\n    test_instance_teardown(s_socket_fd_a, s_linenoise_hdl, &lock);\n}\n\nTEST_CASE(\"CTRL-D removes character at the right of the cursor\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock, &config);\n\n    get_line_args_t args = { .lock = &lock, .parent_task = xTaskGetCurrentTaskHandle(), .config = &config };\n    xTaskCreate(get_line_task, \"freertos_task\", 2048, &args, 5, NULL);\n\n    // wait until the linenoise instance init is done, and the get line as started\n    // before sending test content\n    pthread_mutex_lock(&lock);\n\n    // Insert \"abcde\"\n    test_send_characters(s_socket_fd_a[1], \"abcde\");\n\n    // CTRL-B (move cursor left once)\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_B));\n\n    // CTRL-B (move cursor left once)\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_B));\n\n    // CTRL-B (move cursor left once)\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_B));\n\n    // CTRL-D, buffer becomes \"abde\"\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_D));\n\n    // CTRL-D, buffer becomes \"abe\"\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_D));\n\n    // Newline (accept)\n    test_send_characters(s_socket_fd_a[1], \"\\n\");\n\n    // wait for the task to terminate to continue\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    TEST_ASSERT_NOT_NULL(s_line_returned);\n    TEST_ASSERT_EQUAL_STRING(\"abe\", s_line_returned);\n\n    test_instance_teardown(s_socket_fd_a, s_linenoise_hdl, &lock);\n}\n\nTEST_CASE(\"CTRL-T swaps character with previous\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock, &config);\n\n    get_line_args_t args = { .lock = &lock, .parent_task = xTaskGetCurrentTaskHandle(), .config = &config };\n    xTaskCreate(get_line_task, \"freertos_task\", 2048, &args, 5, NULL);\n\n    // wait until the linenoise instance init is done, and the get line as started\n    // before sending test content\n    pthread_mutex_lock(&lock);\n\n    // Insert \"abcde\"\n    test_send_characters(s_socket_fd_a[1], \"abcde\");\n\n    // CTRL-B (move cursor left once)\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_B));\n\n    // CTRL-T (swap characters)\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_T));\n\n    // Newline (accept)\n    test_send_characters(s_socket_fd_a[1], \"\\n\");\n\n    // wait for the task to terminate to continue\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    TEST_ASSERT_NOT_NULL(s_line_returned);\n    TEST_ASSERT_EQUAL_STRING(\"abced\", s_line_returned);\n\n    test_instance_teardown(s_socket_fd_a, s_linenoise_hdl, &lock);\n}\n\nTEST_CASE(\"CTRL-U deletes the whole line\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock, &config);\n\n    get_line_args_t args = { .lock = &lock, .parent_task = xTaskGetCurrentTaskHandle(), .config = &config };\n    xTaskCreate(get_line_task, \"freertos_task\", 2048, &args, 5, NULL);\n\n    // wait until the linenoise instance init is done, and the get line as started\n    // before sending test content\n    pthread_mutex_lock(&lock);\n\n    // Insert \"abcde\"\n    test_send_characters(s_socket_fd_a[1], \"abcde\");\n\n    // CTRL-U (delete all line)\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_U));\n\n    // Insert \"fghij\"\n    test_send_characters(s_socket_fd_a[1], \"fghij\");\n\n    // Newline (accept)\n    test_send_characters(s_socket_fd_a[1], \"\\n\");\n\n    // wait for the task to terminate to continue\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    TEST_ASSERT_NOT_NULL(s_line_returned);\n    TEST_ASSERT_EQUAL_STRING(\"fghij\", s_line_returned);\n\n    test_instance_teardown(s_socket_fd_a, s_linenoise_hdl, &lock);\n}\n\nTEST_CASE(\"CTRL-K deletes from character to end of line\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock, &config);\n\n    get_line_args_t args = { .lock = &lock, .parent_task = xTaskGetCurrentTaskHandle(), .config = &config };\n    xTaskCreate(get_line_task, \"freertos_task\", 2048, &args, 5, NULL);\n\n    // wait until the linenoise instance init is done, and the get line as started\n    // before sending test content\n    pthread_mutex_lock(&lock);\n\n    // Insert \"abcde\"\n    test_send_characters(s_socket_fd_a[1], \"abcde\");\n\n    // CTRL-B (move cursor left once)\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_B));\n\n    // CTRL-B (move cursor left once)\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_B));\n\n    // CTRL-B (move cursor left once)\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_B));\n\n    // CTRL-K (delete from current character on)\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_K));\n\n    // Insert \"abab\"\n    test_send_characters(s_socket_fd_a[1], \"abab\");\n\n    // Newline (accept)\n    test_send_characters(s_socket_fd_a[1], \"\\n\");\n\n    // wait for the task to terminate to continue\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    TEST_ASSERT_NOT_NULL(s_line_returned);\n    TEST_ASSERT_EQUAL_STRING(\"ababab\", s_line_returned);\n\n    test_instance_teardown(s_socket_fd_a, s_linenoise_hdl, &lock);\n}\n\nTEST_CASE(\"CTRL-L clears the screen\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock, &config);\n\n    get_line_args_t args = { .lock = &lock, .parent_task = xTaskGetCurrentTaskHandle(), .config = &config };\n    xTaskCreate(get_line_task, \"freertos_task\", 2048, &args, 5, NULL);\n\n    // wait until the linenoise instance init is done, and the get line as started\n    // before sending test content\n    pthread_mutex_lock(&lock);\n\n    // CTRL-L (clear screen)\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_L));\n\n    // we can't check that the screen is actually cleared but\n    // we can check that the proper command was sent from\n    // linenoise to the terminal\n    // Verify prompt string is found in output\n    wait_ms(100);\n    char full_cmd_line[32] = {0};\n    const char *expect_string = \"screen cleared\";\n    const ssize_t nread = read(s_socket_fd_a[1], full_cmd_line, 32);\n    TEST_ASSERT_NOT_EQUAL(-1, nread);\n    TEST_ASSERT_NOT_NULL(strstr(full_cmd_line, expect_string));\n\n    // Newline (accept)\n    test_send_characters(s_socket_fd_a[1], \"\\n\");\n\n    // wait for the task to terminate to continue\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    test_instance_teardown(s_socket_fd_a, s_linenoise_hdl, &lock);\n}\n\nTEST_CASE(\"CTRL-W removes the previous word\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock, &config);\n\n    get_line_args_t args = { .lock = &lock, .parent_task = xTaskGetCurrentTaskHandle(), .config = &config };\n    xTaskCreate(get_line_task, \"freertos_task\", 2048, &args, 5, NULL);\n\n    // wait until the linenoise instance init is done, and the get line as started\n    // before sending test content\n    pthread_mutex_lock(&lock);\n\n    // Insert \"word_a \"\n    test_send_characters(s_socket_fd_a[1], \"word_a\");\n    test_send_characters(s_socket_fd_a[1], \" \");\n\n    // Insert \"word_b\"\n    test_send_characters(s_socket_fd_a[1], \"word_b\");\n\n    // CTRL-W (removes previous work)\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(CTRL_W));\n\n    // Insert \"word_c\"\n    test_send_characters(s_socket_fd_a[1], \"word_c\");\n\n    // Newline (accept)\n    test_send_characters(s_socket_fd_a[1], \"\\n\");\n\n    // wait for the task to terminate to continue\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    TEST_ASSERT_NOT_NULL(s_line_returned);\n    TEST_ASSERT_EQUAL_STRING(\"word_a word_c\", s_line_returned);\n\n    test_instance_teardown(s_socket_fd_a, s_linenoise_hdl, &lock);\n}\n\nTEST_CASE(\"check completion, hint and free hint callback\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock, &config);\n\n    config.completion_cb = custom_completion_cb;\n    config.hints_cb = custom_hint_cb;\n    config.free_hints_cb = custom_free_hint_cb;\n\n    get_line_args_t args = { .lock = &lock, .parent_task = xTaskGetCurrentTaskHandle(), .config = &config };\n    xTaskCreate(get_line_task, \"freertos_task\", 2048, &args, 5, NULL);\n\n    // wait until the linenoise instance init is done, and the get line as started\n    // before sending test content\n    pthread_mutex_lock(&lock);\n\n    // Insert \"word_a\" this should trigger the hint cb and free hints cb\n    test_send_characters(s_socket_fd_a[1], \"word_a\");\n\n    // TAB: this should trigger the completions cb\n    test_send_characters(s_socket_fd_a[1], COMPOUND_LITERAL(TAB));\n\n    // Newline (accept)\n    test_send_characters(s_socket_fd_a[1], \"\\n\");\n\n    // wait for the task to terminate to continue\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    TEST_ASSERT_EQUAL(true, s_hint_called);\n    TEST_ASSERT_EQUAL(true, s_completions_called);\n    TEST_ASSERT_EQUAL(true, s_free_hint_called);\n\n    test_instance_teardown(s_socket_fd_a, s_linenoise_hdl, &lock);\n}\n\nTEST_CASE(\"check esp_linenoise_get_line return values\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock, &config);\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_create_instance(&config, &s_linenoise_hdl));\n    TEST_ASSERT_NOT_NULL(s_linenoise_hdl);\n\n    const size_t buffer_size = 10;\n    char buffer[buffer_size];\n\n    // pass NULL buffer, expect invalid arg error\n    TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_linenoise_get_line(s_linenoise_hdl, NULL, buffer_size));\n    // pass 0 buffer size, expect invalid arg error\n    TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_linenoise_get_line(s_linenoise_hdl, buffer, 0));\n    // pass buffer size bigger than max cmd line length, expect invalid arg error\n    TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_linenoise_get_line(s_linenoise_hdl, buffer, config.max_cmd_line_length + 1));\n\n    // update the value of allow_empty_line to false and send an empty\n    // line, expect esp_linenoise_get_line to return with ESP_FAIL\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_set_empty_line(s_linenoise_hdl, false));\n\n    get_line_task_args_t args = {\n        .handle = s_linenoise_hdl,\n        .parent_task = xTaskGetCurrentTaskHandle(),\n        .lock = &lock,\n        .ret_val = ESP_OK,\n        .buf = buffer,\n        .buf_size = buffer_size\n    };\n    xTaskCreate(get_line_task_w_args, \"freertos_task\", 2048, &args, 5, NULL);\n\n    // wait until the linenoise instance init is done, and the get line as started\n    // before sending test content\n    pthread_mutex_lock(&lock);\n\n    // Newline (accept)\n    test_send_characters(s_socket_fd_a[1], \"\\n\");\n\n    // wait for the task to terminate to continue\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    // check that esp_linenoise_get_line returned ESP_FAIL\n    TEST_ASSERT_EQUAL(ESP_FAIL, args.ret_val);\n\n    test_instance_teardown(s_socket_fd_a, s_linenoise_hdl, &lock);\n}\n\nTEST_CASE(\"check cmd line is bigger than the buffer\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock, &config);\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_create_instance(&config, &s_linenoise_hdl));\n    TEST_ASSERT_NOT_NULL(s_linenoise_hdl);\n\n    const size_t buffer_size = 10;\n    char buffer[buffer_size];\n\n    // update the value of allow_empty_line to false and send an empty\n    // line, expect esp_linenoise_get_line to return with ESP_FAIL\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_set_empty_line(s_linenoise_hdl, false));\n\n    get_line_task_args_t args = {\n        .handle = s_linenoise_hdl,\n        .parent_task = xTaskGetCurrentTaskHandle(),\n        .lock = &lock,\n        .ret_val = ESP_OK,\n        .buf = buffer,\n        .buf_size = buffer_size\n    };\n    xTaskCreate(get_line_task_w_args, \"freertos_task\", 2048, &args, 5, NULL);\n\n    // wait until the linenoise instance init is done, and the get line as started\n    // before sending test content\n    pthread_mutex_lock(&lock);\n\n    // send more characters than the size of the buffer when linenoise\n    // has dumb mode turned off\n    test_send_characters(s_socket_fd_a[1], \"aaaaaaaaaaa\\n\");\n\n    // wait for the task to terminate to continue\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    // check that esp_linenoise_get_line returned ESP_OK\n    TEST_ASSERT_EQUAL(ESP_OK, args.ret_val);\n    // linenoise should return when size of buffer - 1 is filled\n    TEST_ASSERT_EQUAL(buffer_size - 1, strlen(buffer));\n\n    // reset the buffer and release the mutex\n    pthread_mutex_unlock(&lock);\n    memset(buffer, 0, buffer_size);\n\n    // switch the dumb mode on\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_set_dumb_mode(s_linenoise_hdl, true));\n\n    // repeat the test\n    xTaskCreate(get_line_task_w_args, \"freertos_task\", 2048, &args, 5, NULL);\n\n    // wait until the linenoise instance init is done, and the get line as started\n    // before sending test content\n    pthread_mutex_lock(&lock);\n\n    // send more characters than the size of the buffer when linenoise\n    // has dumb mode turned on\n    test_send_characters(s_socket_fd_a[1], \"aaaaaaaaaaa\\n\");\n\n    // wait for the task to terminate to continue\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    // check that esp_linenoise_get_line returned ESP_OK and the\n    // number of char is equal to buffer_size - 1\n    TEST_ASSERT_EQUAL(ESP_OK, args.ret_val);\n    TEST_ASSERT_EQUAL(buffer_size - 1, strlen(buffer));\n\n    test_instance_teardown(s_socket_fd_a, s_linenoise_hdl, &lock);\n}\n\n/* Mappings from shortkey actions to escape sequences:\n   - Up arrow     : \"\\x1b[A\"\n   - Down arrow   : \"\\x1b[B\"\n   - Right arrow  : \"\\x1b[C\"\n   - Left arrow   : \"\\x1b[D\"\n   - Home         : \"\\x1b[H\" or \"\\x1bOH\"\n   - End          : \"\\x1b[F\" or \"\\x1bOF\"\n   - Delete key   : \"\\x1b[3~\"\n*/\n\nTEST_CASE(\"cursor left/right edits work via escape sequences\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock, &config);\n\n    get_line_args_t args = { .lock = &lock, .parent_task = xTaskGetCurrentTaskHandle(), .config = &config };\n    xTaskCreate(get_line_task, \"freertos_task\", 2048, &args, 5, NULL);\n    pthread_mutex_lock(&lock);\n\n    test_send_characters(s_socket_fd_a[1], \"abc\");       // step 1: insert abc\n    test_send_characters(s_socket_fd_a[1], \"\\x1b[D\");    // step 2: left arrow (cursor between b and c)\n    test_send_characters(s_socket_fd_a[1], \"X\");         // step 3: insert X\n    test_send_characters(s_socket_fd_a[1], \"\\x1b[C\");    // step 4: right arrow\n    test_send_characters(s_socket_fd_a[1], \"Y\");         // step 5: insert Y\n    test_send_characters(s_socket_fd_a[1], \"\\n\");        // finish input\n\n    // wait for the task to terminate to continue\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n    TEST_ASSERT_EQUAL_STRING(\"abXcY\", s_line_returned);\n\n    test_instance_teardown(s_socket_fd_a, s_linenoise_hdl, &lock);\n}\n\n/* Home and End via escape sequences */\nTEST_CASE(\"Home and End keys work via escape sequences\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock, &config);\n\n    get_line_args_t args = { .lock = &lock, .parent_task = xTaskGetCurrentTaskHandle(), .config = &config };\n    xTaskCreate(get_line_task, \"freertos_task\", 2048, &args, 5, NULL);\n    pthread_mutex_lock(&lock);\n\n    test_send_characters(s_socket_fd_a[1], \"bcd\");       // buffer: bcd\n    test_send_characters(s_socket_fd_a[1], \"\\x1b[H\");    // Home key\n    test_send_characters(s_socket_fd_a[1], \"a\");         // -> abcd\n    test_send_characters(s_socket_fd_a[1], \"\\x1b[F\");    // End key\n    test_send_characters(s_socket_fd_a[1], \"e\");         // -> abcde\n    test_send_characters(s_socket_fd_a[1], \"\\n\");\n\n    // wait for the task to terminate to continue\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n    TEST_ASSERT_EQUAL_STRING(\"abcde\", s_line_returned);\n\n    test_instance_teardown(s_socket_fd_a, s_linenoise_hdl, &lock);\n}\n\n/* History navigation with Up/Down arrows */\nTEST_CASE(\"history navigation works via arrow keys\", \"[esp_linenoise][history]\")\n{\n    esp_linenoise_config_t config;\n    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock, &config);\n\n    get_line_args_t args = { .lock = &lock, .parent_task = xTaskGetCurrentTaskHandle(), .config = &config };\n    xTaskCreate(get_line_task, \"freertos_task\", 2048, &args, 5, NULL);\n    pthread_mutex_lock(&lock);\n\n    // add history\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_history_add(s_linenoise_hdl, \"first\"));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_history_add(s_linenoise_hdl, \"second\"));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_history_add(s_linenoise_hdl, \"third\"));\n\n    // navigate\n    test_send_characters(s_socket_fd_a[1], \"\\x1b[A\");    // up -> third\n    test_send_characters(s_socket_fd_a[1], \"\\x1b[A\");    // up -> second\n    test_send_characters(s_socket_fd_a[1], \"second\");    // append text\n    test_send_characters(s_socket_fd_a[1], \"\\x1b[A\");    // up -> first\n    test_send_characters(s_socket_fd_a[1], \"\\x1b[B\");    // down -> secondsecond\n    test_send_characters(s_socket_fd_a[1], \"\\n\");\n\n    // wait for the task to terminate to continue\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n    TEST_ASSERT_EQUAL_STRING(\"secondsecond\", s_line_returned);\n\n    test_instance_teardown(s_socket_fd_a, s_linenoise_hdl, &lock);\n}\n\n/* Delete key via escape sequence */\nTEST_CASE(\"Delete key works via escape sequence\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock, &config);\n\n    get_line_args_t args = { .lock = &lock, .parent_task = xTaskGetCurrentTaskHandle(), .config = &config };\n    xTaskCreate(get_line_task, \"freertos_task\", 2048, &args, 5, NULL);\n    pthread_mutex_lock(&lock);\n\n    test_send_characters(s_socket_fd_a[1], \"abcde\");\n    test_send_characters(s_socket_fd_a[1], \"\\x1b[D\");    // left\n    test_send_characters(s_socket_fd_a[1], \"\\x1b[D\");    // left\n    test_send_characters(s_socket_fd_a[1], \"\\x1b[D\");    // left\n    test_send_characters(s_socket_fd_a[1], \"\\x1b[3~\");   // delete (removes c)\n    test_send_characters(s_socket_fd_a[1], \"\\x1b[3~\");   // delete (removes d)\n    test_send_characters(s_socket_fd_a[1], \"\\n\");\n\n    // wait for the task to terminate to continue\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n    TEST_ASSERT_EQUAL_STRING(\"abe\", s_line_returned);\n\n    test_instance_teardown(s_socket_fd_a, s_linenoise_hdl, &lock);\n}\n\n/* Alternate Home/End sequences using ESC O form */\nTEST_CASE(\"Home and End via ESC O form\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock, &config);\n\n    get_line_args_t args = { .lock = &lock, .parent_task = xTaskGetCurrentTaskHandle(), .config = &config };\n    xTaskCreate(get_line_task, \"freertos_task\", 2048, &args, 5, NULL);\n    pthread_mutex_lock(&lock);\n\n    test_send_characters(s_socket_fd_a[1], \"bcd\");\n    test_send_characters(s_socket_fd_a[1], \"\\x1bOH\");    // ESC O H for home\n    test_send_characters(s_socket_fd_a[1], \"a\");\n    test_send_characters(s_socket_fd_a[1], \"\\x1bOF\");    // ESC O F for end\n    test_send_characters(s_socket_fd_a[1], \"e\");\n    test_send_characters(s_socket_fd_a[1], \"\\n\");\n\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n    TEST_ASSERT_EQUAL_STRING(\"abcde\", s_line_returned);\n\n    test_instance_teardown(s_socket_fd_a, s_linenoise_hdl, &lock);\n}\n\n/* test multi instances */\nTEST_CASE(\"Create and use 2 esp_linenoise instances\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config_a;\n    pthread_mutex_t lock_a = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock_a, &config_a);\n    esp_linenoise_handle_t linenoise_handle_a;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_create_instance(&config_a, &linenoise_handle_a));\n    TEST_ASSERT_NOT_NULL(linenoise_handle_a);\n\n    const size_t buffer_a_size = 32;\n    char buffer_a[buffer_a_size];\n    memset(buffer_a, 0, buffer_a_size);\n\n    get_line_task_args_t args_a = {\n        .handle = linenoise_handle_a,\n        .parent_task = xTaskGetCurrentTaskHandle(),\n        .lock = &lock_a,\n        .ret_val = ESP_OK,\n        .buf = buffer_a,\n        .buf_size = buffer_a_size\n    };\n    xTaskCreate(get_line_task_w_args, \"freertos_task\", 2048, &args_a, 5, NULL);\n    pthread_mutex_lock(&lock_a);\n\n    esp_linenoise_config_t config_b;\n    pthread_mutex_t lock_b = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_b, &lock_b, &config_b);\n    esp_linenoise_handle_t linenoise_handle_b;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_create_instance(&config_b, &linenoise_handle_b));\n    TEST_ASSERT_NOT_NULL(linenoise_handle_b);\n\n    const size_t buffer_b_size = 32;\n    char buffer_b[buffer_b_size];\n    memset(buffer_b, 0, buffer_b_size);\n\n    get_line_task_args_t args_b = {\n        .handle = linenoise_handle_b,\n        .parent_task = xTaskGetCurrentTaskHandle(),\n        .lock = &lock_b,\n        .ret_val = ESP_OK,\n        .buf = buffer_b,\n        .buf_size = buffer_b_size\n    };\n    xTaskCreate(get_line_task_w_args, \"freertos_task\", 2048, &args_b, 5, NULL);\n    pthread_mutex_lock(&lock_b);\n\n    /* send different string to the instances and make sure each instances\n     * get the correct string from the correct stream */\n    const char *test_msg_a = \"test_msg_a\";\n    const char *test_msg_b = \"test_msg_b\";\n    test_send_characters(s_socket_fd_a[1], test_msg_a);\n    test_send_characters(s_socket_fd_a[1], \"\\n\");\n    test_send_characters(s_socket_fd_b[1], test_msg_b);\n    test_send_characters(s_socket_fd_b[1], \"\\n\");\n\n\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    TEST_ASSERT_EQUAL_STRING(test_msg_a, args_a.buf);\n    TEST_ASSERT_EQUAL_STRING(test_msg_b, args_b.buf);\n\n    test_instance_teardown(s_socket_fd_a, linenoise_handle_a, &lock_a);\n    test_instance_teardown(s_socket_fd_b, linenoise_handle_b, &lock_b);\n}\n\nTEST_CASE(\"tests that esp_linenoise_abort actually forces esp_linenoise_get_line to return\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config_a, config_b;\n    pthread_mutex_t lock_a = PTHREAD_MUTEX_INITIALIZER;\n    pthread_mutex_t lock_b = PTHREAD_MUTEX_INITIALIZER;\n\n    test_instance_setup(s_socket_fd_a, &lock_a, &config_a);\n    test_instance_setup(s_socket_fd_b, &lock_b, &config_b);\n\n    /* make sure to use the default read function */\n    config_a.read_bytes_cb = NULL;\n    config_b.read_bytes_cb = NULL;\n\n    esp_linenoise_handle_t linenoise_handle_a;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_create_instance(&config_a, &linenoise_handle_a));\n    TEST_ASSERT_NOT_NULL(linenoise_handle_a);\n\n    const size_t buffer_a_size = 32;\n    char buffer_a[buffer_a_size];\n    memset(buffer_a, 0, buffer_a_size);\n\n    get_line_task_args_t args_a = {\n        .handle = linenoise_handle_a,\n        .parent_task = xTaskGetCurrentTaskHandle(),\n        .lock = &lock_a,\n        .ret_val = ESP_OK,\n        .buf = buffer_a,\n        .buf_size = buffer_a_size\n    };\n    xTaskCreate(get_line_task_w_args, \"freertos_task\", 2048, &args_a, 5, NULL);\n    pthread_mutex_lock(&lock_a);\n\n    esp_linenoise_handle_t linenoise_handle_b;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_create_instance(&config_b, &linenoise_handle_b));\n    TEST_ASSERT_NOT_NULL(linenoise_handle_b);\n\n    const size_t buffer_b_size = 32;\n    char buffer_b[buffer_b_size];\n    memset(buffer_b, 0, buffer_b_size);\n\n    get_line_task_args_t args_b = {\n        .handle = linenoise_handle_b,\n        .parent_task = xTaskGetCurrentTaskHandle(),\n        .lock = &lock_b,\n        .ret_val = ESP_OK,\n        .buf = buffer_b,\n        .buf_size = buffer_b_size\n    };\n    xTaskCreate(get_line_task_w_args, \"freertos_task\", 2048, &args_b, 5, NULL);\n    pthread_mutex_lock(&lock_b);\n\n\n\n    /* send test message to instance */\n    const char dummy_message[] = \"dummy_message\";\n    test_send_characters(s_socket_fd_a[1], dummy_message);\n\n    /* for the esp_linenoise to process the message */\n    vTaskDelay(pdMS_TO_TICKS(100));\n\n    /* call the esp_linenoise_abort on linenoise_handle_a to return from esp_linenoise_get_line */\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_abort(linenoise_handle_a));\n\n    /* wait for the task running the linenoise instance A to return */\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    /* check that the message was processed by the instance A */\n    TEST_ASSERT_EQUAL_STRING(dummy_message, args_a.buf);\n\n\n\n    /* send dummy message to instance B, that should still be running */\n    test_send_characters(s_socket_fd_b[1], dummy_message);\n\n    /* for the esp_linenoise to process the message */\n    vTaskDelay(pdMS_TO_TICKS(100));\n\n    /* call the esp_linenoise_abort on linenoise_handle_a to return from esp_linenoise_get_line */\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_abort(linenoise_handle_b));\n\n    /* wait for the task running the linenoise instance A to return */\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    /* check that the message was processed by the instance B */\n    TEST_ASSERT_EQUAL_STRING(dummy_message, args_b.buf);\n\n\n\n    /* start instance A and repeat test to make sure it is possible to restart an instance\n     * even after aborting it */\n    xTaskCreate(get_line_task_w_args, \"freertos_task\", 2048, &args_a, 5, NULL);\n    pthread_mutex_lock(&lock_a);\n    test_send_characters(s_socket_fd_a[1], dummy_message);\n    vTaskDelay(pdMS_TO_TICKS(100));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_abort(linenoise_handle_a));\n    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);\n\n    test_instance_teardown(s_socket_fd_a, linenoise_handle_a, &lock_a);\n    test_instance_teardown(s_socket_fd_b, linenoise_handle_b, &lock_b);\n}\n"
  },
  {
    "path": "esp_linenoise/test_apps/main/test_esp_linenoise_get_set.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include <stdio.h>\n#include \"unity.h\"\n#include \"esp_linenoise.h\"\n#include \"esp_err.h\"\n\nstatic esp_linenoise_handle_t get_linenoise_instance_default_config(void)\n{\n    esp_linenoise_config_t config;\n    esp_linenoise_get_instance_config_default(&config);\n    esp_linenoise_handle_t h;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_create_instance(&config, &h));\n    TEST_ASSERT_NOT_NULL(h);\n    return h;\n}\n\nTEST_CASE(\"set and get multi-line mode\", \"[esp_linenoise]\")\n{\n    esp_linenoise_handle_t h = get_linenoise_instance_default_config();\n\n    bool is_multi_line = false;\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_set_multi_line(h, true));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_is_multi_line(h, &is_multi_line));\n    TEST_ASSERT_TRUE(is_multi_line);\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_set_multi_line(h, false));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_is_multi_line(h, &is_multi_line));\n    TEST_ASSERT_FALSE(is_multi_line);\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_delete_instance(h));\n}\n\nTEST_CASE(\"set and get dumb mode\", \"[esp_linenoise]\")\n{\n    esp_linenoise_handle_t h = get_linenoise_instance_default_config();\n\n    bool is_dumb_mode = false;\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_set_dumb_mode(h, true));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_is_dumb_mode(h, &is_dumb_mode));\n    TEST_ASSERT_TRUE(is_dumb_mode);\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_set_dumb_mode(h, false));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_is_dumb_mode(h, &is_dumb_mode));\n    TEST_ASSERT_FALSE(is_dumb_mode);\n\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_delete_instance(h));\n}\n\nTEST_CASE(\"set and get empty line flag\", \"[esp_linenoise]\")\n{\n    esp_linenoise_handle_t h = get_linenoise_instance_default_config();\n\n    bool is_empty_line = false;\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_set_empty_line(h, true));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_is_empty_line(h, &is_empty_line));\n    TEST_ASSERT_TRUE(is_empty_line);\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_set_empty_line(h, false));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_is_empty_line(h, &is_empty_line));\n    TEST_ASSERT_FALSE(is_empty_line);\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_delete_instance(h));\n}\n\nTEST_CASE(\"set and get prompt\", \"[esp_linenoise]\")\n{\n    esp_linenoise_handle_t h = get_linenoise_instance_default_config();\n\n    const char *test_prompt = \"test\";\n    const char *ret_prompt = NULL;\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_set_prompt(h, test_prompt));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_get_prompt(h, &ret_prompt));\n    TEST_ASSERT_TRUE(strcmp(test_prompt, ret_prompt) == 0);\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_delete_instance(h));\n}\n\nTEST_CASE(\"default max line length and max history length\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    esp_linenoise_get_instance_config_default(&config);\n    TEST_ASSERT_GREATER_THAN(0, config.max_cmd_line_length);\n    TEST_ASSERT_GREATER_THAN(0, config.history_max_length);\n}\n\nTEST_CASE(\"set and get max command line length\", \"[esp_linenoise]\")\n{\n    esp_linenoise_handle_t h = get_linenoise_instance_default_config();\n\n    size_t max_cmd_line_len = 0;\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_set_max_cmd_line_length(h, 1024));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_get_max_cmd_line_length(h, &max_cmd_line_len));\n    TEST_ASSERT_EQUAL(1024, max_cmd_line_len);\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_delete_instance(h));\n}\n\nTEST_CASE(\"add and free history\", \"[esp_linenoise]\")\n{\n    esp_linenoise_handle_t h = get_linenoise_instance_default_config();\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_history_add(h, \"entry1\"));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_history_set_max_len(h, 5));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_history_add(h, \"entry2\"));\n    esp_linenoise_history_free(h);\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_delete_instance(h));\n}\n\nTEST_CASE(\"save and load history to file\", \"[esp_linenoise]\")\n{\n    esp_linenoise_handle_t h = get_linenoise_instance_default_config();\n\n    const char *filename = \"/tmp/test_esp_linenoise_history.txt\";\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_history_add(h, \"one\"));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_history_add(h, \"two\"));\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_history_save(h, filename));\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_history_free(h));\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_history_load(h, filename));\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_delete_instance(h));\n}\n\nTEST_CASE(\"get out_fd and in_fd\", \"[esp_linenoise]\")\n{\n    const int test_out_fd = 5;\n    const int test_in_fd = 6;\n    esp_linenoise_config_t config;\n    esp_linenoise_get_instance_config_default(&config);\n    config.out_fd = test_out_fd;\n    config.in_fd = test_in_fd;\n\n    esp_linenoise_handle_t h;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_create_instance(&config, &h));\n    TEST_ASSERT_NOT_NULL(h);\n\n    int in_fd = -1;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_get_in_fd(h, &in_fd));\n    TEST_ASSERT_EQUAL(test_in_fd, in_fd);\n    int out_fd = -1;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_get_out_fd(h, &out_fd));\n    TEST_ASSERT_EQUAL(test_out_fd, out_fd);\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_delete_instance(h));\n}\n\nstatic ssize_t test_read(int fd, void *buf, size_t count)\n{\n    (void)fd;\n    (void)buf;\n    (void)count;\n    return -1;\n}\n\nstatic ssize_t test_write(int fd, const void *buf, size_t count)\n{\n    (void)fd;\n    (void)buf;\n    (void)count;\n    return -1;\n}\n\n\nTEST_CASE(\"get read_func and write_func\", \"[esp_linenoise]\")\n{\n    esp_linenoise_config_t config;\n    esp_linenoise_get_instance_config_default(&config);\n    config.read_bytes_cb = test_read;\n    config.write_bytes_cb = test_write;\n\n    esp_linenoise_handle_t h;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_create_instance(&config, &h));\n    TEST_ASSERT_NOT_NULL(h);\n\n    esp_linenoise_read_bytes_t read_ret;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_get_read(h, &read_ret));\n    TEST_ASSERT_EQUAL(test_read, read_ret);\n    esp_linenoise_write_bytes_t write_ret;\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_get_write(h, &write_ret));\n    TEST_ASSERT_EQUAL(test_write, write_ret);\n\n    TEST_ASSERT_EQUAL(ESP_OK, esp_linenoise_delete_instance(h));\n}\n"
  },
  {
    "path": "esp_linenoise/test_apps/main/test_linenoise_legacy.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include <stdio.h>\n#include <unistd.h>\n#include <sys/socket.h>\n#include <pthread.h>\n#include <sys/time.h>\n#include <errno.h>\n#include \"fcntl.h\"\n#include \"unity.h\"\n#include \"linenoise/linenoise.h\"\n#include \"test_utils.h\"\n\nstatic int s_socket_fd[2];\nstatic int s_original_stdin_fd = -1;\nstatic int s_original_stdout_fd = -1;\nstatic char *s_returned_line = NULL;\nstatic pthread_mutex_t s_lock = PTHREAD_MUTEX_INITIALIZER;\n\nstatic bool s_completions_called = false;\nstatic bool s_hint_called = false;\nstatic bool s_free_hint_called = false;\n\nvoid custom_legacy_completion_cb(const char *str, linenoiseCompletions *lc)\n{\n    // we just want to see that the callback is indeed called\n    // so flip the s_completions_called to true\n    if (!s_completions_called) {\n        s_completions_called = true;\n    }\n}\n\nchar *custom_legacy_hint_cb(const char *str, int *color, int *bold)\n{\n    // we just want to see that the callback is indeed called\n    // so flip the s_hint_called to true\n    if (!s_hint_called) {\n        s_hint_called = true;\n    }\n\n    return \"something\";\n}\n\nvoid custom_legacy_free_hint_cb(void *ptr)\n{\n    // we just want to see that the callback is indeed called\n    // so flip the s_free_hint_called to true\n    if (!s_free_hint_called) {\n        s_free_hint_called = true;\n    }\n}\n\nssize_t custom_legacy_write(int fd, const void *buf, size_t count)\n{\n    // printf(\"writing : \");\n    // for (size_t i = 0; i < count; i++) {\n    //     printf(\"(%x, %c) \", *((char*)buf + i), *((char*)buf + i));\n    // }\n    // printf(\"\\n\");\n\n    // find the request in the list of commands and send the response\n    for (size_t i = 0; i < commands_count; i++) {\n        if (strstr(commands[i].request, buf) != NULL) {\n            const char *response = commands[i].response;\n            if (response != NULL) {\n                const size_t size = strlen(commands[i].response);\n\n                // write the expected response to the socket, so linenoise\n                // can read the response\n                const ssize_t nwrite = write(s_socket_fd[1], response, size);\n                TEST_ASSERT_EQUAL(size, nwrite);\n            }\n\n            // return the count like a normal write would do\n            // do not propagate to the socket to not pollute\n            // the buffers\n            return count;\n        }\n    }\n\n    // otherwise just propagate the write\n    return write(fd, buf, count);\n}\n\nstatic void test_setup(int socket_fd[2], pthread_mutex_t *s_lock)\n{\n    // 2 fd are generated, simulating the full-duplex\n    // communication between linenoise and the terminal\n    socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fd);\n\n    // redirect stdin and stdout since legacy linenoise uses\n    // stdin and stdout only as default streams\n    s_original_stdin_fd = dup(STDIN_FILENO);\n    s_original_stdout_fd = dup(STDOUT_FILENO);\n    TEST_ASSERT(dup2(s_socket_fd[0], STDIN_FILENO) >= 0);\n    TEST_ASSERT(dup2(s_socket_fd[0], STDOUT_FILENO) >= 0);\n    close(s_socket_fd[0]);\n\n    // assure that the read will be blocking\n    int flags = fcntl(STDIN_FILENO, F_GETFL, 0);\n    flags &= ~O_NONBLOCK;\n    fcntl(STDIN_FILENO, F_SETFL, flags);\n\n    linenoiseSetCompletionCallback(custom_legacy_completion_cb);\n    linenoiseSetHintsCallback(custom_legacy_hint_cb);\n    linenoiseSetFreeHintsCallback(custom_legacy_free_hint_cb);\n    /* don't set the custom read, since we don't need it. also it tests that the default\n     * read is used by linenoise */\n    linenoiseSetWriteFunction(custom_legacy_write);\n\n    const int is_dumb_mode = linenoiseProbe();\n    if (is_dumb_mode) {\n        printf(\"running dumb mode\\n\");\n        linenoiseSetDumbMode(1);\n    } else {\n        printf(\"running normal mode\\n\");\n        linenoiseSetDumbMode(0);\n    }\n\n    // take the semaphore\n    pthread_mutex_lock(s_lock);\n}\n\nstatic void test_teardown(int socket_fd[2])\n{\n    memset(s_returned_line, 0, CMD_LINE_LENGTH);\n\n    // Restore the default streams\n    dup2(s_original_stdin_fd, STDIN_FILENO);\n    dup2(s_original_stdout_fd, STDOUT_FILENO);\n    close(s_original_stdin_fd);\n    close(s_original_stdout_fd);\n\n    close(socket_fd[0]);\n    close(socket_fd[1]);\n\n    // unlock the mutex for the next test\n    pthread_mutex_unlock(&s_lock);\n}\n\nstatic void *get_line_task(void *arg)\n{\n    char *prompt = (char *)arg;\n\n    // wait for the instance to properly initialize before unlocking\n    // the mutex so the test can run\n    usleep(100000);\n\n    // release the mutex so the test can start sending data\n    pthread_mutex_unlock(&s_lock);\n\n    s_returned_line = linenoise(prompt);\n    return NULL;\n}\n\nTEST_CASE(\"legacy linenoise() returns line read from stdin and writes to stdout\", \"[linenoise]\")\n{\n    test_setup(s_socket_fd, &s_lock);\n\n    pthread_t thread_id;\n    char *prompt = \">>>\";\n    TEST_ASSERT_EQUAL(0, pthread_create(&thread_id, NULL, get_line_task, prompt));\n\n    // wait until the linenoise instance init is done, and the get line as started\n    // before sending test content\n    pthread_mutex_lock(&s_lock);\n\n    const char *input_line = \"unit test input\";\n    test_send_characters(s_socket_fd[1], input_line);\n\n    // Write newline to trigger prompt output + return from loop\n    test_send_characters(s_socket_fd[1], \"\\n\");\n\n    TEST_ASSERT_EQUAL(0, pthread_join(thread_id, NULL));\n\n    /* verify that the string was processed properly by linenoise() */\n    TEST_ASSERT_NOT_NULL(s_returned_line);\n    TEST_ASSERT_NOT_NULL(strstr(input_line, s_returned_line));\n\n    // Verify prompt string is found in output\n    char full_cmd_line[32] = {0};\n    const ssize_t nread = read(s_socket_fd[1], full_cmd_line, 32);\n    TEST_ASSERT_NOT_EQUAL(-1, nread);\n\n    TEST_ASSERT_NOT_NULL(strstr(full_cmd_line, prompt));\n\n    test_teardown(s_socket_fd);\n}\n\nTEST_CASE(\"legacy check completion, hint and free hint callback\", \"[linenoise]\")\n{\n    test_setup(s_socket_fd, &s_lock);\n\n    pthread_t thread_id;\n    char *prompt = \">>>\";\n    TEST_ASSERT_EQUAL(0, pthread_create(&thread_id, NULL, get_line_task, prompt));\n\n    // wait until the linenoise instance init is done, and the get line as started\n    // before sending test content\n    pthread_mutex_lock(&s_lock);\n\n    // Insert \"word_a\" this should trigger the hint cb and free hints cb\n    test_send_characters(s_socket_fd[1], \"word_a\");\n\n    // TAB: this should trigger the completions cb\n    test_send_characters(s_socket_fd[1], COMPOUND_LITERAL(TAB));\n\n    // Newline (accept)\n    test_send_characters(s_socket_fd[1], \"\\n\");\n\n    // Wait for loop to finish\n    TEST_ASSERT_EQUAL(0, pthread_join(thread_id, NULL));\n\n    TEST_ASSERT_EQUAL(true, s_hint_called);\n    TEST_ASSERT_EQUAL(true, s_completions_called);\n    TEST_ASSERT_EQUAL(true, s_free_hint_called);\n\n    test_teardown(s_socket_fd);\n}\n"
  },
  {
    "path": "esp_linenoise/test_apps/main/test_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"unity.h\"\n#include \"unity_test_runner.h\"\n#include \"esp_heap_caps.h\"\n#include \"unity_test_utils_memory.h\"\n\nvoid setUp(void)\n{\n    unity_utils_record_free_mem();\n}\n\nvoid tearDown(void)\n{\n    unity_utils_evaluate_leaks_direct(0);\n}\n\nvoid app_main(void)\n{\n    printf(\"Running linenoise component tests\\n\");\n    unity_run_menu();\n}\n"
  },
  {
    "path": "esp_linenoise/test_apps/main/test_utils.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include <unistd.h>\n#include <stdio.h>\n#include \"unity.h\"\n#include \"test_utils.h\"\n\n// list of commands that the linenoise tests need\n// to intercept and potentially answer for linenoise to\n// behave as expected\nconst command_t commands[] = {\n    {\"\\x1b[5n\", \"\\x1b[0n\"}, // probe for escape sequence support\n    {\"\\x1b[H\\x1b[2J\", \"screen cleared\"}, // clear screen request, the response will be analyzed in the concerned test\n    {\"\\x1b[6n\", \"\\x1b[10;50R\"}, // request for rows, cols\n    {\"\\x1b[999C\", NULL}, // move the cursor right, no response needed\n};\n\nconst size_t commands_count = sizeof(commands) / sizeof(command_t);\n\nvoid test_send_characters(int socket_fd, const char *msg)\n{\n    // wait to simulate that the user is doing the input\n    // and prevent linenoise to detect the incoming character(s)\n    // as pasted\n    wait_ms(100);\n\n    const size_t msg_len = strlen(msg);\n    const int nwrite = write(socket_fd, msg, msg_len);\n    TEST_ASSERT_EQUAL(msg_len, nwrite);\n}\n"
  },
  {
    "path": "esp_linenoise/test_apps/pytest_linenoise.py",
    "content": "import pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.utils import idf_parametrize\nimport glob\nfrom pathlib import Path\n\n\n\n@pytest.mark.host_test\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that did not build\"\n)\n@idf_parametrize('target', ['linux'], indirect=['target'])\ndef test_esp_linenoise(dut: Dut) -> None:\n    dut.run_all_single_board_cases()\n"
  },
  {
    "path": "esp_linenoise/test_apps/sdkconfig.defaults",
    "content": "CONFIG_ESP_TASK_WDT_EN=n\nCONFIG_VFS_SUPPORT_IO=n"
  },
  {
    "path": "esp_schedule/.build-test-rules.yml",
    "content": "# ESP Schedule build test rules\n# This file can be empty - the component will be built with default rules"
  },
  {
    "path": "esp_schedule/CMakeLists.txt",
    "content": "set(component_srcs \"src/esp_schedule.c\"\n                   \"src/esp_schedule_nvs.c\")\n\nidf_component_register(SRCS \"${component_srcs}\"\n                       INCLUDE_DIRS \"include\"\n                       PRIV_INCLUDE_DIRS \"src\"\n                       PRIV_REQUIRES nvs_flash esp_netif)\n"
  },
  {
    "path": "esp_schedule/Kconfig",
    "content": "menu \"ESP Schedule Configuration\"\n\n    config ESP_SCHEDULE_ENABLE_DAYLIGHT\n        bool \"Enable Daylight (Sunrise/Sunset) Schedules\"\n        default y\n        help\n            Enable support for sunrise and sunset based schedules.\n\n            This feature allows scheduling based on astronomical calculations\n            for sunrise and sunset times at specific geographical locations.\n\n            Disabling this option will:\n            - Remove sunrise/sunset schedule types from the API\n            - Save memory by excluding solar calculation code\n            - Reduce binary size (by about 11500 bytes)\n\n            If disabled, ESP_SCHEDULE_TYPE_SUNRISE and ESP_SCHEDULE_TYPE_SUNSET\n            will not be available.\n\nendmenu\n"
  },
  {
    "path": "esp_schedule/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "esp_schedule/README.md",
    "content": "# ESP Scheduling\n\n[![Component Registry](https://components.espressif.com/components/espressif/esp_schedule/badge.svg)](https://components.espressif.com/components/espressif/esp_schedule)\n\nThis component is used to implement scheduling for:\n\n- **One-shot events** with a relative time difference (e.g., 30 seconds into the future)\n- **Periodic events** based on a certain time[^1] on days of the week (e.g., every Monday or Wednesday)\n- **Periodic/one-shot events** on a certain time[^1] based on the date:\n  - e.g., *(periodic)* every 23rd of January to April\n  - e.g., *(one-shot)* 9th of August, 2026\n- **Periodic events** at an offset from sunrise/sunset\n\n[^1]: By default, the time is w.r.t. UTC. If the timezone has been set, then the time is w.r.t. the specified timezone.\n\n## Example Usage\n\nSee the comprehensive example in [`examples/get_started/`](examples/get_started/) for a complete demonstration of all ESP Schedule features, including:\n\n- **Days of Week Scheduling** - Recurring events on specific weekdays\n- **Date-based Scheduling** - Monthly and yearly recurring events\n- **Relative Scheduling** - One-time delayed events\n- **Solar Scheduling** - Sunrise/sunset based events with location coordinates and day-of-week filtering\n- **Schedule Persistence** - NVS storage and recovery\n- **Callback Handling** - Trigger and timestamp callbacks\n- **Schedule Management** - Create, edit, enable, and disable schedules\n\nThe example includes detailed documentation, build instructions, and demonstrates all schedule types with practical use cases.\n"
  },
  {
    "path": "esp_schedule/examples/get_started/CMakeLists.txt",
    "content": "# The following lines of boilerplate have to be in your project's CMakeLists\n# in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(esp_schedule_example)\n"
  },
  {
    "path": "esp_schedule/examples/get_started/README.md",
    "content": "# ESP Schedule Example\n\n## Overview\n\nThis example demonstrates how to use the ESP Schedule component to create different types of schedules for ESP32 applications. The example shows four main schedule types:\n\n1. **Days of Week Schedule** - Triggers on specific days of the week at specified times\n2. **Date Schedule** - Triggers on specific dates (day and month combinations)\n3. **Relative Schedule** - Triggers after a specified number of seconds from creation\n4. **Solar Schedule** - Triggers at sunrise or sunset with optional offset\n\n## Schedule Types Demonstrated\n\n### 1. Days of Week Schedule (`ESP_SCHEDULE_TYPE_DAYS_OF_WEEK`)\n- Triggers every Monday, Wednesday, and Friday at 14:30 (2:30 PM)\n- Useful for recurring weekly events like meetings, reminders, or automated tasks\n\n### 2. Date Schedule (`ESP_SCHEDULE_TYPE_DATE`)\n- Triggers every month on the 15th at 09:00 (9:00 AM)\n- Useful for monthly recurring events like bill payments, reports, or maintenance tasks\n- Can be configured to repeat every year for annual events\n\n### 3. Relative Schedule (`ESP_SCHEDULE_TYPE_RELATIVE`)\n- Triggers 60 seconds after creation (one minute timer)\n- Useful for one-time delayed actions like turning off a device after a timeout\n- Has a validity period (2 minutes in this example)\n\n### 4. Solar Schedule (`ESP_SCHEDULE_TYPE_SUNRISE` / `ESP_SCHEDULE_TYPE_SUNSET`)\n- **Sunrise Schedule**: Triggers exactly at sunrise for a specific location (weekdays only)\n- **Sunset Schedule**: Triggers 30 minutes before sunset for a specific location (weekdays only)\n- Uses latitude/longitude coordinates to calculate solar times with day-of-week filtering\n- Perfect for automatic lighting control, irrigation systems, or other location-based automation\n- Supports both day-of-week patterns and specific date patterns for solar events\n- Requires `CONFIG_ESP_SCHEDULE_ENABLE_DAYLIGHT=y` to be enabled\n\n## Features Demonstrated\n\n- **Schedule Creation**: How to create schedules with different trigger types\n- **Schedule Persistence**: Schedules are stored in NVS and persist across reboots\n- **Network Provisioning**: Automatic WiFi provisioning via BLE or SoftAP for network connectivity with QR code display\n- **Time Synchronization**: Robust SNTP time sync with threshold validation for accurate real-world scheduling\n- **Callback Functions**: Both trigger callbacks (when schedule fires) and timestamp callbacks (when next trigger time updates)\n- **Schedule Management**: Enable, disable, edit, and delete schedules\n- **Schedule Recovery**: Automatically recovers and re-enables schedules after reboot\n\n## How to Use Example\n\n### Hardware Required\n\n* An ESP development board (ESP32, ESP32-S2, ESP32-S3, etc.)\n* USB cable for power supply and programming\n* WiFi network access for time synchronization and network provisioning\n\n### Supported Targets\n\nThis example requires Wi-Fi connectivity for network provisioning and time synchronization.\n\n**Supported Targets:** ESP32, ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-S2, ESP32-S3\n\n### Network Provisioning\n\nThe example uses configurable network provisioning to connect to WiFi:\n\n1. **Flash and run** the example on your ESP device\n2. **A QR code will be displayed** in the serial output with provisioning data\n3. **Use a BLE/SoftAP provisioning app** (like \"ESP SoftAP Prov\" on Android/iOS) to scan the QR code (or manually enter the QR code details)\n4. **The device will automatically** connect to WiFi and synchronize time via NTP\n5. **Schedules will then** operate with accurate real-world timing\n\n#### Configuration\n\n- `CONFIG_ESP_SCHEDULE_EXAMPLE_PROV_SCHEME` - provisioning transport type\n- `CONFIG_ESP_SCHEDULE_EXAMPLE_PROV_SECURITY_VERSION` - provisioning security version:\n   - **Version 0**: plaintext communication\n   - **Version 1**: Proof of Possession (PoP) used, \"12345678\"\n   - **Version 2**: Username: \"wifiprov\", Password: \"abcd1234\"\n\n### Project Configuration\n\nTo select the provisioning scheme:\n\n1. Run `idf.py menuconfig` (or `idf.py set-target <chip> && idf.py menuconfig`)\n2. Navigate to `Example Configuration` → `ESP Schedule Example Configuration`\n3. Select your preferred `Network Provisioning Scheme`:\n   - `BLE Provisioning` (default) - Uses Bluetooth LE\n   - `SoftAP Provisioning` - Uses WiFi Access Point\n4. Save and exit\n\n### Build and Flash\n\n1. Run `idf.py set-target <chip_name>` to set the target chip (e.g., `esp32`, `esp32s3`)\n2. Run `idf.py build` to build the project\n3. Run `idf.py -p PORT flash monitor` to build, flash and monitor the project\n\n**Note**: The example includes network provisioning (BLE or SoftAP) and SNTP time synchronization which requires network connectivity. The example will automatically provision and connect to WiFi, then synchronize time from NTP servers. Ensure your device can connect to WiFi networks for proper operation.\n\n**Security Note**: The example uses a fixed Proof of Possession (PoP) value of \"12345678\" for secure provisioning. In production applications, use a unique, randomly generated PoP for enhanced security.\n\n**QR Code Note**: For BLE provisioning, a QR code is displayed in the serial output that can be scanned with the ESP RainMaker app. If the QR code is not visible, copy the provided URL and paste it in a browser to view the QR code.\n\n### Expected Output\n\nThe example will show logs like:\n\n```text\nESP Schedule example started. Schedules will trigger based on their configurations.\nI (Current time: Fri Oct 24 14:30:00 2025\n)\nI (Days of week schedule triggered! Data: Monday/Wednesday/Friday schedule\n)\n```\n\nThe schedules will trigger at their configured times:\n- **Days of week schedule**: Every Monday, Wednesday, Friday at 14:30\n- **Date schedule**: Every 15th of the month at 09:00\n- **Relative schedule**: 60 seconds after the program starts\n- **Solar schedules**: At sunrise (exactly) and sunset (30 minutes early) for San Francisco, CA (weekdays only)\n\n## Code Structure\n\n### Main Components\n\n- **`esp_schedule_example_main.c`**: Main application file demonstrating schedule creation and usage\n- **Callback Functions**: Separate callbacks for each schedule type showing how to handle triggers\n- **Schedule Configuration**: Examples of how to configure different schedule types\n\n### Key Functions\n\n- `create_example_schedules()`: Creates the three example schedules\n- `edit_example_schedules()`: Demonstrates how to edit existing schedules\n- `days_of_week_callback()`, `date_callback()`, `relative_callback()`: Handle schedule triggers\n- `timestamp_callback()`: Handles schedule timestamp updates\n\n## Customization\n\n### Changing Schedule Times\n\nTo modify the schedule times, edit the `esp_schedule_config_t` structures in `create_example_schedules()`:\n\n```c\n// Days of week schedule - change time to 10:00 AM\n.trigger.hours = 10,\n.trigger.minutes = 0,\n\n// Date schedule - change to 20th of every month at 3:00 PM\n.trigger.date.day = 20,\n.trigger.hours = 15,\n.trigger.minutes = 0,\n\n// Relative schedule - change to 30 seconds from now\n.trigger.relative_seconds = 30,\n\n// Solar schedule - change location to New York, adjust timing, and change days\n.trigger.day.repeat_days = ESP_SCHEDULE_DAY_SATURDAY | ESP_SCHEDULE_DAY_SUNDAY,  // Weekends only\n.trigger.solar.latitude = 40.7128,    // New York latitude\n.trigger.solar.longitude = -74.0060,  // New York longitude\n.trigger.solar.offset_minutes = 15,   // 15 minutes after sunrise\n```\n\n### Adding More Schedule Types\n\nThe example demonstrates all the main schedule types including sunrise/sunset schedules. You can also use:\n\n- **Sunrise/Sunset Schedules** (already included in the example - see solar_callback):\n  ```c\n  .trigger.type = ESP_SCHEDULE_TYPE_SUNRISE,\n  .trigger.solar.latitude = 37.7749,    // San Francisco latitude\n  .trigger.solar.longitude = -122.4194, // San Francisco longitude\n  .trigger.solar.offset_minutes = 30,   // 30 minutes after sunrise\n  ```\n\n### Schedule Persistence\n\nSchedules are automatically saved to NVS (Non-Volatile Storage) and will persist across:\n- Device reboots\n- Power cycles\n- Firmware updates\n\n### Schedule Management\n\nThe example shows how to:\n- Create new schedules\n- Enable/disable schedules\n- Edit existing schedules\n- Handle schedule recovery after reboot\n\n## Troubleshooting\n\n### Schedule Not Triggering\n\n1. **Check system time**: Ensure the ESP32 system time is set correctly\n2. **Verify schedule configuration**: Double-check hours/minutes and trigger conditions\n3. **Check logs**: Look for schedule creation and trigger messages in the serial output\n4. **Solar schedules**: Ensure `CONFIG_ESP_SCHEDULE_ENABLE_DAYLIGHT=y` is enabled and location coordinates are accurate\n5. **Daylight saving time**: Solar schedules automatically adjust for DST changes\n\n### NVS Issues\n\nIf you encounter NVS-related errors:\n1. The example includes automatic NVS initialization and recovery\n2. Check if the NVS partition has enough space\n3. Consider erasing NVS if corruption occurs: `idf.py erase-flash`\n\n### Memory Issues\n\nIf you run out of memory when creating many schedules:\n1. Each schedule consumes some memory\n2. Consider the validity periods to automatically clean up old schedules\n3. Monitor heap usage with `ESP_LOGI(TAG, \"Free heap: %d\", esp_get_free_heap_size())`\n\n## Further Reading\n\n- [ESP Schedule API Reference](../../include/esp_schedule.h)\n- [ESP Schedule README](../../README.md)\n"
  },
  {
    "path": "esp_schedule/examples/get_started/main/CMakeLists.txt",
    "content": "set(supported_targets \"esp32\" \"esp32s2\" \"esp32s3\" \"esp32c2\" \"esp32c3\" \"esp32c5\" \"esp32c6\" \"esp32c61\")\n\n# Redirect to a stub if target is not supported\nif(CONFIG_IDF_TARGET IN_LIST supported_targets)\n    set(srcs \"esp_schedule_example_main.c\"\n            \"network/app_network.c\"\n        )\n    set(priv_include_dirs \"network\")\nelse()\n    message(WARNING \"Target ${CONFIG_IDF_TARGET} is not supported. Redirecting to stub example.\")\n    set(srcs \"esp_schedule_example_stub.c\")\n    set(priv_include_dirs \"\")\nendif()\n\nidf_component_register(SRCS ${srcs}\n                       INCLUDE_DIRS \".\"\n                       PRIV_INCLUDE_DIRS ${priv_include_dirs}\n                       PRIV_REQUIRES esp_schedule nvs_flash esp_netif esp_event esp_wifi)\n"
  },
  {
    "path": "esp_schedule/examples/get_started/main/Kconfig.projbuild",
    "content": "menu \"esp_schedule Example Configuration\"\n\n    choice ESP_SCHEDULE_EXAMPLE_PROV_SCHEME\n        prompt \"Network Provisioning Scheme\"\n        default ESP_SCHEDULE_EXAMPLE_PROV_SOFTAP\n        help\n            Select the network provisioning scheme for the ESP Schedule example.\n            For BLE provisioning, please enable BT_ENABLED and BT_NIMBLE_ENABLED.\n\n        config ESP_SCHEDULE_EXAMPLE_PROV_BLE\n            bool \"BLE Provisioning\"\n            depends on BT_ENABLED && BT_NIMBLE_ENABLED\n            help\n                Use Bluetooth Low Energy (BLE) for network provisioning.\n                Requires a BLE-capable device and provisioning app.\n\n        config ESP_SCHEDULE_EXAMPLE_PROV_SOFTAP\n            bool \"SoftAP Provisioning\"\n            help\n                Use WiFi Soft Access Point for network provisioning.\n                Creates a WiFi hotspot that users can connect to for provisioning.\n\n    endchoice\n\n    choice ESP_SCHEDULE_EXAMPLE_PROV_SECURITY_VERSION\n        prompt \"Provisioning security version\"\n        default ESP_SCHEDULE_EXAMPLE_PROV_SECURITY_VERSION_1 if ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1\n        default ESP_SCHEDULE_EXAMPLE_PROV_SECURITY_VERSION_2 if ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2\n        help\n            Select the network provisioning security version.\n\n        config ESP_SCHEDULE_EXAMPLE_PROV_SECURITY_VERSION_0\n            bool \"Security Version 0\"\n            depends on ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0\n            help\n                Security version 0. No authentication is needed; plaintext communication.\n\n        config ESP_SCHEDULE_EXAMPLE_PROV_SECURITY_VERSION_1\n            bool \"Security Version 1\"\n            depends on ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1\n            help\n                Security version 1. The PoP is set to '12345678'.\n                In production, please use a randomly generated PoP in a factory partition.\n\n        config ESP_SCHEDULE_EXAMPLE_PROV_SECURITY_VERSION_2\n            bool \"Security Version 2\"\n            depends on ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2\n            help\n                Security version 2. Username: 'wifiprov', Password: 'abcd1234'\n                In production, please use a randomly generated username and password in a factory partition.\n\n    endchoice\n\nendmenu"
  },
  {
    "path": "esp_schedule/examples/get_started/main/esp_schedule_example_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <time.h>\n#include \"esp_log.h\"\n#include \"esp_schedule.h\"\n#include \"nvs_flash.h\"\n#include \"esp_system.h\"\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"esp_netif.h\"\n#include \"esp_event.h\"\n#include \"esp_sntp.h\"\n#include \"lwip/ip_addr.h\"\n#include \"network_provisioning/manager.h\"\n#include \"freertos/event_groups.h\"\n#include \"app_network.h\"\n\nstatic const char *TAG = \"esp_schedule_example\";\n\n/* Event group for network provisioning synchronization */\nstatic EventGroupHandle_t s_network_event_group;\n\n// Callback functions for different schedule types\nstatic void days_of_week_callback(esp_schedule_handle_t handle, void *priv_data)\n{\n    ESP_LOGI(TAG, \"Days of week schedule triggered! Data: %s\", (char *)priv_data);\n\n    // Example: Toggle an LED, send a notification, etc.\n    // Your application logic here\n}\n\nstatic void date_callback(esp_schedule_handle_t handle, void *priv_data)\n{\n    ESP_LOGI(TAG, \"Date schedule triggered! Data: %s\", (char *)priv_data);\n\n    // Example: Birthday reminder, anniversary notification, etc.\n    // Your application logic here\n}\n\nstatic void relative_callback(esp_schedule_handle_t handle, void *priv_data)\n{\n    ESP_LOGI(TAG, \"Relative schedule triggered! Data: %s\", (char *)priv_data);\n\n    // Example: Timer expired, delayed action completed, etc.\n    // Your application logic here\n}\n\n#ifdef CONFIG_ESP_SCHEDULE_ENABLE_DAYLIGHT\nstatic void solar_callback(esp_schedule_handle_t handle, void *priv_data)\n{\n    ESP_LOGI(TAG, \"Solar schedule triggered! Data: %s\", (char *)priv_data);\n\n    // Example: Turn on lights at sunset, turn off lights at sunrise, etc.\n    // Your application logic here\n}\n#endif // CONFIG_ESP_SCHEDULE_ENABLE_DAYLIGHT\n\nstatic void timestamp_callback(esp_schedule_handle_t handle, uint32_t next_timestamp, void *priv_data)\n{\n    time_t timestamp = (time_t)next_timestamp;\n    char *time_str = ctime(&timestamp);\n    if (time_str) {\n        ESP_LOGI(TAG, \"Next schedule timestamp updated for %s: %s\", (char *)priv_data, time_str);\n    } else {\n        ESP_LOGI(TAG, \"Next schedule timestamp updated for %s: <invalid time>\", (char *)priv_data);\n    }\n}\n\n// Private data for different schedules\nstatic char *days_of_week_data = \"Monday/Wednesday/Friday schedule\";\nstatic char *date_data = \"Monthly schedule\";\nstatic char *relative_data = \"Timer schedule\";\n#ifdef CONFIG_ESP_SCHEDULE_ENABLE_DAYLIGHT\nstatic char *solar_data = \"Sunrise/Sunset schedule\";\n#endif // CONFIG_ESP_SCHEDULE_ENABLE_DAYLIGHT\n\n/**\n * @brief Create example schedules\n *\n * This function creates the example schedules using the esp_schedule_create() API.\n * @note If NVS is enabled, then the names of the schedules are used as NVS keys, so they must be shorter than the NVS key length limit of 16 characters.\n */\nstatic void create_example_schedules(void)\n{\n    ESP_LOGI(TAG, \"Creating example schedules...\");\n\n    // Example 1: Days of week schedule\n    // Triggers every Monday, Wednesday, and Friday at 14:30\n    esp_schedule_config_t days_schedule = {\n        .name = \"work_days\",\n        .trigger.type = ESP_SCHEDULE_TYPE_DAYS_OF_WEEK,\n        .trigger.hours = 14,\n        .trigger.minutes = 30,\n        .trigger.day.repeat_days = ESP_SCHEDULE_DAY_MONDAY | ESP_SCHEDULE_DAY_WEDNESDAY | ESP_SCHEDULE_DAY_FRIDAY,\n        .trigger_cb = days_of_week_callback,\n        .timestamp_cb = timestamp_callback,\n        .priv_data = days_of_week_data,\n        .validity = {\n            .start_time = 0,  // Start immediately\n            .end_time = 0     // No end time (run indefinitely)\n        }\n    };\n\n    esp_schedule_handle_t days_handle = esp_schedule_create(&days_schedule);\n    if (days_handle) {\n        ESP_LOGI(TAG, \"Created days of week schedule successfully\");\n        esp_schedule_enable(days_handle);\n    }\n\n    // Example 2: Date schedule\n    // Triggers every month on the 15th at 09:00\n    esp_schedule_config_t date_schedule = {\n        .name = \"monthly_15\",\n        .trigger.type = ESP_SCHEDULE_TYPE_DATE,\n        .trigger.hours = 9,\n        .trigger.minutes = 0,\n        .trigger.date.day = 15,\n        .trigger.date.repeat_months = ESP_SCHEDULE_MONTH_ALL,  // Every month\n        .trigger.date.repeat_every_year = true,\n        .trigger_cb = date_callback,\n        .timestamp_cb = timestamp_callback,\n        .priv_data = date_data,\n        .validity = {\n            .start_time = 0,  // Start immediately\n            .end_time = 0     // No end time\n        }\n    };\n\n    esp_schedule_handle_t date_handle = esp_schedule_create(&date_schedule);\n    if (date_handle) {\n        ESP_LOGI(TAG, \"Created date schedule successfully\");\n        esp_schedule_enable(date_handle);\n    }\n\n    // Example 3: Relative schedule\n    // Triggers after 10 seconds from creation\n    time_t current_time = time(NULL);\n    esp_schedule_config_t relative_schedule = {\n        .name = \"10_sec\",\n        .trigger.type = ESP_SCHEDULE_TYPE_RELATIVE,\n        .trigger.relative_seconds = 10,  // 10 seconds from now\n        .trigger_cb = relative_callback,\n        .timestamp_cb = timestamp_callback,\n        .priv_data = relative_data,\n        .validity = {\n            .start_time = current_time,\n            .end_time = current_time + 120  // Valid for 2 minutes\n        }\n    };\n\n    esp_schedule_handle_t relative_handle = esp_schedule_create(&relative_schedule);\n    if (relative_handle) {\n        ESP_LOGI(TAG, \"Created relative schedule successfully\");\n        esp_schedule_enable(relative_handle);\n    }\n\n    // Example 4: Solar schedule (Sunrise/Sunset) with day-of-week filtering\n    // Note: This requires CONFIG_ESP_SCHEDULE_ENABLE_DAYLIGHT to be enabled\n    // Triggers at sunrise and sunset for a specific location, but only on weekdays\n#ifdef CONFIG_ESP_SCHEDULE_ENABLE_DAYLIGHT\n    esp_schedule_config_t sunrise_schedule = {\n        .name = \"sunrise\",\n        .trigger.type = ESP_SCHEDULE_TYPE_SUNRISE,\n        .trigger.hours = 0,  // Hours/minutes are ignored for solar schedules\n        .trigger.minutes = 0,\n        .trigger.day.repeat_days = ESP_SCHEDULE_DAY_MONDAY | ESP_SCHEDULE_DAY_TUESDAY |\n        ESP_SCHEDULE_DAY_WEDNESDAY | ESP_SCHEDULE_DAY_THURSDAY | ESP_SCHEDULE_DAY_FRIDAY,\n        .trigger.solar.latitude = 37.7749,    // San Francisco latitude\n        .trigger.solar.longitude = -122.4194, // San Francisco longitude\n        .trigger.solar.offset_minutes = 0,    // Exactly at sunrise\n        .trigger_cb = solar_callback,\n        .timestamp_cb = timestamp_callback,\n        .priv_data = solar_data,\n        .validity = {\n            .start_time = 0,  // Start immediately\n            .end_time = 0     // No end time\n        }\n    };\n\n    esp_schedule_handle_t sunrise_handle = esp_schedule_create(&sunrise_schedule);\n    if (sunrise_handle) {\n        ESP_LOGI(TAG, \"Created sunrise schedule successfully\");\n        esp_schedule_enable(sunrise_handle);\n    }\n\n    esp_schedule_config_t sunset_schedule = {\n        .name = \"sunset\",\n        .trigger.type = ESP_SCHEDULE_TYPE_SUNSET,\n        .trigger.hours = 0,  // Hours/minutes are ignored for solar schedules\n        .trigger.minutes = 0,\n        .trigger.day.repeat_days = ESP_SCHEDULE_DAY_MONDAY | ESP_SCHEDULE_DAY_TUESDAY |\n        ESP_SCHEDULE_DAY_WEDNESDAY | ESP_SCHEDULE_DAY_THURSDAY | ESP_SCHEDULE_DAY_FRIDAY,\n        .trigger.solar.latitude = 37.7749,    // San Francisco latitude\n        .trigger.solar.longitude = -122.4194, // San Francisco longitude\n        .trigger.solar.offset_minutes = -30,  // 30 minutes before sunset\n        .trigger_cb = solar_callback,\n        .timestamp_cb = timestamp_callback,\n        .priv_data = solar_data,\n        .validity = {\n            .start_time = 0,  // Start immediately\n            .end_time = 0     // No end time\n        }\n    };\n\n    esp_schedule_handle_t sunset_handle = esp_schedule_create(&sunset_schedule);\n    if (sunset_handle) {\n        ESP_LOGI(TAG, \"Created sunset schedule successfully\");\n        esp_schedule_enable(sunset_handle);\n    }\n#endif // CONFIG_ESP_SCHEDULE_ENABLE_DAYLIGHT\n}\n\nvoid app_main(void)\n{\n    // Initialize NVS (Non-Volatile Storage)\n    esp_err_t ret = nvs_flash_init();\n    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {\n        ESP_ERROR_CHECK(nvs_flash_erase());\n        ret = nvs_flash_init();\n    }\n    ESP_ERROR_CHECK(ret);\n\n    // Initialize Event Loop (Network Interface is initialized in app_network)\n    ESP_ERROR_CHECK(esp_event_loop_create_default());\n\n    // Create event group for network provisioning synchronization\n    s_network_event_group = xEventGroupCreate();\n    if (s_network_event_group == NULL) {\n        ESP_LOGE(TAG, \"Failed to create event group\");\n        return;\n    }\n\n    // Initialize network provisioning (includes WiFi and network interfaces)\n    ESP_ERROR_CHECK(app_network_init(s_network_event_group));\n\n    // Start network provisioning and wait for connection\n    esp_err_t network_result = app_network_start(s_network_event_group, 300000); // 5 minutes timeout\n    if (network_result != ESP_OK) {\n        ESP_LOGE(TAG, \"Network connection failed or timed out\");\n        return;\n    }\n\n    // Start time synchronization\n    app_network_start_time_sync(s_network_event_group);\n\n    // Wait for time synchronization to complete\n    esp_err_t time_result = app_network_wait_for_time_sync(s_network_event_group, 60000); // 1 minute timeout\n    if (time_result != ESP_OK) {\n        ESP_LOGW(TAG, \"Time synchronization failed or timed out, continuing anyway\");\n    }\n\n    // Initialize ESP Schedule\n    ESP_LOGI(TAG, \"Initializing ESP Schedule...\");\n    uint8_t schedule_count;\n    esp_schedule_handle_t *schedule_list = esp_schedule_init(true, NULL, &schedule_count);\n    if (schedule_list != NULL) {\n        // If there are existing schedules in NVS, their handles will be available in this list. We don't use them in this example, so we free the array.\n        free(schedule_list);\n    }\n\n    // Make all the schedules used\n    create_example_schedules();\n\n    ESP_LOGI(TAG, \"ESP Schedule example started. Schedules will trigger based on their configurations.\");\n\n    // The schedules will now trigger automatically based on their configurations\n    // Monitor network status and handle disconnections\n    while (1) {\n        // Main application loop\n        vTaskDelay(pdMS_TO_TICKS(1000));  // Delay 1 second\n\n        // Print current time every 10 seconds for reference\n        static int counter = 0;\n        if (++counter >= 10) {\n            time_t now = time(NULL);\n            char *time_str = ctime(&now);\n            if (time_str) {\n                ESP_LOGI(TAG, \"Current time: %s\", time_str);\n            } else {\n                ESP_LOGI(TAG, \"Current time: <invalid>\");\n            }\n            counter = 0;\n        }\n\n        // Check for network disconnection and handle it\n        EventBits_t network_bits = xEventGroupGetBits(s_network_event_group);\n        if (network_bits & NETWORK_DISCONNECTED_BIT) {\n            ESP_LOGW(TAG, \"Network disconnected, attempting to reconnect...\");\n            // For now, just log the issue - in a real application you might\n            // want to restart provisioning or handle reconnection\n            vTaskDelay(pdMS_TO_TICKS(5000)); // Wait 5 seconds before checking again\n        }\n    }\n\n    // Cleanup (this won't be reached in the current infinite loop, but good practice)\n    if (s_network_event_group) {\n        vEventGroupDelete(s_network_event_group);\n    }\n}\n"
  },
  {
    "path": "esp_schedule/examples/get_started/main/esp_schedule_example_stub.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <string.h>\n\n#include \"esp_log.h\"\n\nstatic const char *supported_targets[] = {\n    \"esp32\",\n    \"esp32s2\",\n    \"esp32s3\",\n    \"esp32c2\",\n    \"esp32c3\",\n    \"esp32c5\",\n    \"esp32c6\",\n    \"esp32c61\",\n};\n\nvoid app_main(void)\n{\n    // This is compiled only if CONFIG_IDF_TARGET is not in the list of supported targets.\n    char supported_targets_str[256] = \"\";\n    for (int i = 0; i < sizeof(supported_targets) / sizeof(supported_targets[0]); i++) {\n        char target_str[32];\n        snprintf(target_str, sizeof(target_str), \"\\n\\t%s\", supported_targets[i]);\n        strcat(supported_targets_str, target_str);\n    }\n    ESP_LOGE(\"esp_schedule_example\", \"Target '%s' is not supported. Please try one of these supported targets:%s\", CONFIG_IDF_TARGET, supported_targets_str);\n    return;\n}"
  },
  {
    "path": "esp_schedule/examples/get_started/main/idf_component.yml",
    "content": "## IDF Component Manager Manifest File\ndependencies:\n  idf:\n    version: \">=5.1\"\n  espressif/esp_schedule:\n    version: \"~1.3.1\"\n    override_path: \"../../../.\"\n  espressif/network_provisioning:\n    version: \"~1.2.0\"\n  espressif/qrcode:\n    version: \"~0.1.0\"\n"
  },
  {
    "path": "esp_schedule/examples/get_started/main/network/app_network.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"app_network.h\"\n#include \"esp_log.h\"\n#include \"esp_event.h\"\n#include \"esp_sntp.h\"\n#include \"esp_netif.h\"\n#include \"esp_wifi.h\"\n#include \"esp_mac.h\"\n#include \"qrcode.h\"\n#include \"lwip/ip_addr.h\"\n#include \"network_provisioning/manager.h\"\n#if defined(CONFIG_ESP_SCHEDULE_EXAMPLE_PROV_BLE)\n#include \"network_provisioning/scheme_ble.h\"\n#elif defined(CONFIG_ESP_SCHEDULE_EXAMPLE_PROV_SOFTAP)\n#include \"network_provisioning/scheme_softap.h\"\n#endif\n#include \"esp_wifi_types.h\"\n\nstatic const char *TAG = \"app_network\";\n\n/* Static variables for event group and provisioning scheme */\nstatic EventGroupHandle_t s_event_group = NULL;\nstatic esp_netif_t *s_sta_netif = NULL;\nstatic uint8_t s_mac_addr[6];\n\n#if defined(CONFIG_ESP_SCHEDULE_EXAMPLE_PROV_SECURITY_VERSION_1)\n/* Proof of Possession for secure provisioning */\n#define ESP_SCHEDULE_EXAMPLE_PROV_SEC1_POP \"12345678\"\n#elif defined(CONFIG_ESP_SCHEDULE_EXAMPLE_PROV_SECURITY_VERSION_2)\n/* Username and password for protocomm security 2 */\n#define ESP_SCHEDULE_EXAMPLE_PROV_SEC2_USERNAME          \"wifiprov\"\n#define ESP_SCHEDULE_EXAMPLE_PROV_SEC2_PWD               \"abcd1234\"\n\n/* This salt,verifier has been generated for username = \"wifiprov\" and password = \"abcd1234\"\n * IMPORTANT NOTE: For production cases, this must be unique to every device\n * and should come from device manufacturing partition.*/\nstatic const char sec2_salt[] = {\n    0x03, 0x6e, 0xe0, 0xc7, 0xbc, 0xb9, 0xed, 0xa8, 0x4c, 0x9e, 0xac, 0x97, 0xd9, 0x3d, 0xec, 0xf4\n};\n\nstatic const char sec2_verifier[] = {\n    0x7c, 0x7c, 0x85, 0x47, 0x65, 0x08, 0x94, 0x6d, 0xd6, 0x36, 0xaf, 0x37, 0xd7, 0xe8, 0x91, 0x43,\n    0x78, 0xcf, 0xfd, 0x61, 0x6c, 0x59, 0xd2, 0xf8, 0x39, 0x08, 0x12, 0x72, 0x38, 0xde, 0x9e, 0x24,\n    0xa4, 0x70, 0x26, 0x1c, 0xdf, 0xa9, 0x03, 0xc2, 0xb2, 0x70, 0xe7, 0xb1, 0x32, 0x24, 0xda, 0x11,\n    0x1d, 0x97, 0x18, 0xdc, 0x60, 0x72, 0x08, 0xcc, 0x9a, 0xc9, 0x0c, 0x48, 0x27, 0xe2, 0xae, 0x89,\n    0xaa, 0x16, 0x25, 0xb8, 0x04, 0xd2, 0x1a, 0x9b, 0x3a, 0x8f, 0x37, 0xf6, 0xe4, 0x3a, 0x71, 0x2e,\n    0xe1, 0x27, 0x86, 0x6e, 0xad, 0xce, 0x28, 0xff, 0x54, 0x46, 0x60, 0x1f, 0xb9, 0x96, 0x87, 0xdc,\n    0x57, 0x40, 0xa7, 0xd4, 0x6c, 0xc9, 0x77, 0x54, 0xdc, 0x16, 0x82, 0xf0, 0xed, 0x35, 0x6a, 0xc4,\n    0x70, 0xad, 0x3d, 0x90, 0xb5, 0x81, 0x94, 0x70, 0xd7, 0xbc, 0x65, 0xb2, 0xd5, 0x18, 0xe0, 0x2e,\n    0xc3, 0xa5, 0xf9, 0x68, 0xdd, 0x64, 0x7b, 0xb8, 0xb7, 0x3c, 0x9c, 0xfc, 0x00, 0xd8, 0x71, 0x7e,\n    0xb7, 0x9a, 0x7c, 0xb1, 0xb7, 0xc2, 0xc3, 0x18, 0x34, 0x29, 0x32, 0x43, 0x3e, 0x00, 0x99, 0xe9,\n    0x82, 0x94, 0xe3, 0xd8, 0x2a, 0xb0, 0x96, 0x29, 0xb7, 0xdf, 0x0e, 0x5f, 0x08, 0x33, 0x40, 0x76,\n    0x52, 0x91, 0x32, 0x00, 0x9f, 0x97, 0x2c, 0x89, 0x6c, 0x39, 0x1e, 0xc8, 0x28, 0x05, 0x44, 0x17,\n    0x3f, 0x68, 0x02, 0x8a, 0x9f, 0x44, 0x61, 0xd1, 0xf5, 0xa1, 0x7e, 0x5a, 0x70, 0xd2, 0xc7, 0x23,\n    0x81, 0xcb, 0x38, 0x68, 0xe4, 0x2c, 0x20, 0xbc, 0x40, 0x57, 0x76, 0x17, 0xbd, 0x08, 0xb8, 0x96,\n    0xbc, 0x26, 0xeb, 0x32, 0x46, 0x69, 0x35, 0x05, 0x8c, 0x15, 0x70, 0xd9, 0x1b, 0xe9, 0xbe, 0xcc,\n    0xa9, 0x38, 0xa6, 0x67, 0xf0, 0xad, 0x50, 0x13, 0x19, 0x72, 0x64, 0xbf, 0x52, 0xc2, 0x34, 0xe2,\n    0x1b, 0x11, 0x79, 0x74, 0x72, 0xbd, 0x34, 0x5b, 0xb1, 0xe2, 0xfd, 0x66, 0x73, 0xfe, 0x71, 0x64,\n    0x74, 0xd0, 0x4e, 0xbc, 0x51, 0x24, 0x19, 0x40, 0x87, 0x0e, 0x92, 0x40, 0xe6, 0x21, 0xe7, 0x2d,\n    0x4e, 0x37, 0x76, 0x2f, 0x2e, 0xe2, 0x68, 0xc7, 0x89, 0xe8, 0x32, 0x13, 0x42, 0x06, 0x84, 0x84,\n    0x53, 0x4a, 0xb3, 0x0c, 0x1b, 0x4c, 0x8d, 0x1c, 0x51, 0x97, 0x19, 0xab, 0xae, 0x77, 0xff, 0xdb,\n    0xec, 0xf0, 0x10, 0x95, 0x34, 0x33, 0x6b, 0xcb, 0x3e, 0x84, 0x0f, 0xb9, 0xd8, 0x5f, 0xb8, 0xa0,\n    0xb8, 0x55, 0x53, 0x3e, 0x70, 0xf7, 0x18, 0xf5, 0xce, 0x7b, 0x4e, 0xbf, 0x27, 0xce, 0xce, 0xa8,\n    0xb3, 0xbe, 0x40, 0xc5, 0xc5, 0x32, 0x29, 0x3e, 0x71, 0x64, 0x9e, 0xde, 0x8c, 0xf6, 0x75, 0xa1,\n    0xe6, 0xf6, 0x53, 0xc8, 0x31, 0xa8, 0x78, 0xde, 0x50, 0x40, 0xf7, 0x62, 0xde, 0x36, 0xb2, 0xba\n};\n#endif\n\n/* Event handler for network provisioning events */\nstatic void network_prov_event_handler(void *ctx, esp_event_base_t event_base, int32_t event_id, void *event_data)\n{\n    if (event_base == NETWORK_PROV_EVENT) {\n        switch (event_id) {\n        case NETWORK_PROV_START:\n            ESP_LOGI(TAG, \"Network provisioning started\");\n            break;\n\n        case NETWORK_PROV_WIFI_CRED_RECV: {\n            ESP_LOGI(TAG, \"WiFi credentials received\");\n            wifi_config_t *wifi_config = (wifi_config_t *)event_data;\n            ESP_LOGI(TAG, \"SSID: %s\", wifi_config->sta.ssid);\n            break;\n        }\n\n        case NETWORK_PROV_WIFI_CRED_SUCCESS:\n            ESP_LOGI(TAG, \"Network provisioning credentials accepted\");\n            if (s_event_group) {\n                xEventGroupSetBits(s_event_group, PROVISIONING_SUCCESS_BIT);\n            }\n            break;\n\n        case NETWORK_PROV_WIFI_CRED_FAIL:\n            ESP_LOGE(TAG, \"Network provisioning credentials failed\");\n            if (s_event_group) {\n                xEventGroupSetBits(s_event_group, PROVISIONING_FAILED_BIT);\n            }\n            break;\n\n        case NETWORK_PROV_END:\n            ESP_LOGI(TAG, \"Network provisioning ended\");\n            break;\n\n        default:\n            ESP_LOGD(TAG, \"Unhandled network provisioning event: %ld\", event_id);\n            break;\n        }\n    }\n}\n\n/* Event handler for WiFi events */\nstatic void wifi_event_handler(void *ctx, esp_event_base_t event_base, int32_t event_id, void *event_data)\n{\n    if (event_base == WIFI_EVENT) {\n        switch (event_id) {\n        case WIFI_EVENT_STA_START:\n            ESP_LOGI(TAG, \"WiFi station started\");\n            esp_wifi_connect();\n            break;\n\n        case WIFI_EVENT_STA_CONNECTED:\n            ESP_LOGI(TAG, \"WiFi station connected\");\n            break;\n\n        case WIFI_EVENT_STA_DISCONNECTED: {\n            ESP_LOGW(TAG, \"WiFi station disconnected\");\n            wifi_event_sta_disconnected_t *event = (wifi_event_sta_disconnected_t *)event_data;\n            ESP_LOGW(TAG, \"Disconnect reason: %d\", event->reason);\n\n            if (s_event_group) {\n                xEventGroupSetBits(s_event_group, NETWORK_DISCONNECTED_BIT);\n            }\n            esp_wifi_connect();\n            break;\n        }\n\n        default:\n            ESP_LOGD(TAG, \"Unhandled WiFi event: %ld\", event_id);\n            break;\n        }\n    }\n}\n\n/* Event handler for IP events */\nstatic void ip_event_handler(void *ctx, esp_event_base_t event_base, int32_t event_id, void *event_data)\n{\n    if (event_base == IP_EVENT) {\n        switch (event_id) {\n        case IP_EVENT_STA_GOT_IP: {\n            ESP_LOGI(TAG, \"WiFi connected, got IP address\");\n            ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;\n            ESP_LOGI(TAG, \"IP Address: \" IPSTR, IP2STR(&event->ip_info.ip));\n\n            if (s_event_group) {\n                xEventGroupSetBits(s_event_group, NETWORK_CONNECTED_BIT);\n            }\n            break;\n        }\n\n        case IP_EVENT_STA_LOST_IP:\n            ESP_LOGW(TAG, \"WiFi disconnected, lost IP address\");\n            if (s_event_group) {\n                xEventGroupSetBits(s_event_group, NETWORK_DISCONNECTED_BIT);\n            }\n            break;\n\n        default:\n            ESP_LOGD(TAG, \"Unhandled IP event: %ld\", event_id);\n            break;\n        }\n    }\n}\n\n/* Initialize WiFi interfaces */\nstatic esp_err_t wifi_init(void)\n{\n    esp_err_t ret;\n\n    /* Get MAC address for service name generation */\n    ret = esp_read_mac(s_mac_addr, ESP_MAC_BASE);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to read MAC address: %s\", esp_err_to_name(ret));\n        return ret;\n    }\n\n    /* Initialize TCP/IP */\n    ret = esp_netif_init();\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to initialize TCP/IP: %s\", esp_err_to_name(ret));\n        return ret;\n    }\n\n    /* Create default WiFi station interface */\n    s_sta_netif = esp_netif_create_default_wifi_sta();\n    if (s_sta_netif == NULL) {\n        ESP_LOGE(TAG, \"Failed to create WiFi station interface\");\n        return ESP_FAIL;\n    }\n\n    /* Initialize WiFi with default configuration */\n    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();\n    ret = esp_wifi_init(&cfg);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to initialize WiFi: %s\", esp_err_to_name(ret));\n        return ret;\n    }\n\n    /* Set WiFi storage to RAM (credentials will be managed by provisioning) */\n    ret = esp_wifi_set_storage(WIFI_STORAGE_RAM);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to set WiFi storage: %s\", esp_err_to_name(ret));\n        return ret;\n    }\n\n    /* Register event handlers */\n    ret = esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to register WiFi event handler: %s\", esp_err_to_name(ret));\n        return ret;\n    }\n\n    ret = esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &ip_event_handler, NULL);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to register IP event handler: %s\", esp_err_to_name(ret));\n        return ret;\n    }\n\n    ESP_LOGI(TAG, \"WiFi interfaces initialized\");\n    return ESP_OK;\n}\n\n/* Start WiFi station */\nstatic esp_err_t wifi_start_sta(void)\n{\n    esp_err_t ret;\n    ret = esp_wifi_set_mode(WIFI_MODE_STA);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to set WiFi mode to STA: %s\", esp_err_to_name(ret));\n        return ret;\n    }\n    ret = esp_wifi_start();\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to start WiFi station: %s\", esp_err_to_name(ret));\n        return ret;\n    }\n    return ESP_OK;\n}\n\n/* Generate QR code for provisioning data */\nstatic void display_qr_code(const char *service_name)\n{\n    if (!service_name) {\n        ESP_LOGW(TAG, \"Cannot generate QR code payload. Data missing.\");\n        return;\n    }\n\n#if defined(CONFIG_ESP_SCHEDULE_EXAMPLE_PROV_BLE)\n    const char *transport = \"ble\";\n#elif defined(CONFIG_ESP_SCHEDULE_EXAMPLE_PROV_SOFTAP)\n    const char *transport = \"softap\";\n#else\n    ESP_LOGE(TAG, \"Unknown transport; cannot generate QR code.\");\n    return;\n#endif\n\n    static const char *version = \"v1\";\n    char payload[150];\n\n#if defined(CONFIG_ESP_SCHEDULE_EXAMPLE_PROV_SECURITY_VERSION_1)\n    snprintf(payload, sizeof(payload), \"{\\\"ver\\\":\\\"%s\\\",\\\"name\\\":\\\"%s\\\",\\\"pop\\\":\\\"%s\\\",\\\"transport\\\":\\\"%s\\\"}\",\n             version, service_name, ESP_SCHEDULE_EXAMPLE_PROV_SEC1_POP, transport);\n#elif defined(CONFIG_ESP_SCHEDULE_EXAMPLE_PROV_SECURITY_VERSION_2)\n    snprintf(payload, sizeof(payload), \"{\\\"ver\\\":\\\"%s\\\",\\\"name\\\":\\\"%s\\\",\\\"username\\\":\\\"%s\\\",\\\"pop\\\":\\\"%s\\\",\\\"transport\\\":\\\"%s\\\"}\",\n             version, service_name, ESP_SCHEDULE_EXAMPLE_PROV_SEC2_USERNAME, ESP_SCHEDULE_EXAMPLE_PROV_SEC2_PWD, transport);\n#else\n    snprintf(payload, sizeof(payload), \"{\\\"ver\\\":\\\"%s\\\",\\\"name\\\":\\\"%s\\\",\\\"transport\\\":\\\"%s\\\"}\",\n             version, service_name, transport);\n#endif\n\n    ESP_LOGI(TAG, \"Scan this QR code from the ESP RainMaker phone app for Provisioning.\");\n    esp_qrcode_config_t cfg = ESP_QRCODE_CONFIG_DEFAULT();\n    esp_qrcode_generate(&cfg, payload);\n\n    ESP_LOGI(TAG, \"If QR code is not visible, copy paste the below URL in a browser.\\nhttps://espressif.github.io/esp-jumpstart/qrcode.html?data=%s\", payload);\n}\n\n/* Initialize network provisioning with event group handling */\nesp_err_t app_network_init(EventGroupHandle_t event_group)\n{\n    esp_err_t ret;\n\n    s_event_group = event_group;\n\n    /* Initialize WiFi interfaces first */\n    ret = wifi_init();\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to initialize WiFi\");\n        return ret;\n    }\n\n    /* Initialize network provisioning manager */\n    network_prov_mgr_config_t config = {\n#if defined(CONFIG_ESP_SCHEDULE_EXAMPLE_PROV_BLE)\n        .scheme = network_prov_scheme_ble,\n        .scheme_event_handler = NETWORK_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BLE,\n#elif defined(CONFIG_ESP_SCHEDULE_EXAMPLE_PROV_SOFTAP)\n        .scheme = network_prov_scheme_softap,\n        .scheme_event_handler = NETWORK_PROV_EVENT_HANDLER_NONE,\n#endif\n    };\n\n    ret = network_prov_mgr_init(config);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to initialize network provisioning manager: %s\", esp_err_to_name(ret));\n        return ret;\n    }\n\n    /* Register event handlers */\n    ret = esp_event_handler_register(NETWORK_PROV_EVENT, ESP_EVENT_ANY_ID, &network_prov_event_handler, NULL);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to register network provisioning event handler: %s\", esp_err_to_name(ret));\n        return ret;\n    }\n\n    ret = esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &ip_event_handler, NULL);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to register IP event handler: %s\", esp_err_to_name(ret));\n        return ret;\n    }\n\n    ESP_LOGI(TAG, \"Network provisioning initialized successfully\");\n    return ESP_OK;\n}\n\n/* Start network provisioning and wait for connection */\nesp_err_t app_network_start(EventGroupHandle_t event_group, uint32_t timeout_ms)\n{\n    esp_err_t ret;\n    bool provisioned = false;\n\n    /* Check if device is already provisioned */\n    ret = network_prov_mgr_is_wifi_provisioned(&provisioned);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to check provisioning status: %s\", esp_err_to_name(ret));\n        return ret;\n    }\n\n    if (!provisioned) {\n        ESP_LOGI(TAG, \"Device not provisioned, starting provisioning...\");\n\n        /* Generate service name */\n        char service_name[32];\n        snprintf(service_name, sizeof(service_name), \"ESP-Schedule-%02x%02x%02x\",\n                 s_mac_addr[3], s_mac_addr[4], s_mac_addr[5]);\n\n        /* Display QR code for provisioning */\n        display_qr_code(service_name);\n#if defined(CONFIG_ESP_SCHEDULE_EXAMPLE_PROV_SOFTAP)\n        /* For SoftAP, create WiFi AP interface */\n        esp_netif_create_default_wifi_ap();\n#endif\n\n#if defined(CONFIG_ESP_SCHEDULE_EXAMPLE_PROV_SECURITY_VERSION_0)\n        ret = network_prov_mgr_start_provisioning(NETWORK_PROV_SECURITY_0, NULL, service_name, NULL);\n#endif\n#if defined(CONFIG_ESP_SCHEDULE_EXAMPLE_PROV_SECURITY_VERSION_1)\n        ret = network_prov_mgr_start_provisioning(NETWORK_PROV_SECURITY_1, ESP_SCHEDULE_EXAMPLE_PROV_SEC1_POP, service_name, NULL);\n#elif defined(CONFIG_ESP_SCHEDULE_EXAMPLE_PROV_SECURITY_VERSION_2)\n        const network_prov_security2_params_t sec2_params = {\n            .salt = sec2_salt,\n            .salt_len = sizeof(sec2_salt),\n            .verifier = sec2_verifier,\n            .verifier_len = sizeof(sec2_verifier),\n        };\n        ret = network_prov_mgr_start_provisioning(NETWORK_PROV_SECURITY_2, &sec2_params, service_name, NULL);\n#endif\n        if (ret != ESP_OK) {\n            ESP_LOGE(TAG, \"Failed to start network provisioning: %s\", esp_err_to_name(ret));\n            return ret;\n        }\n    } else {\n        ESP_LOGI(TAG, \"Device already provisioned, starting Wi-Fi STA\");\n\n        /* Start WiFi station directly */\n        ret = wifi_start_sta();\n        if (ret != ESP_OK) {\n            ESP_LOGE(TAG, \"Failed to start WiFi station: %s\", esp_err_to_name(ret));\n            return ret;\n        }\n\n        /* Post provisioning end event since we're already provisioned */\n        esp_event_post(NETWORK_PROV_EVENT, NETWORK_PROV_END, NULL, 0, portMAX_DELAY);\n    }\n\n    /* Wait for network connection */\n    EventBits_t bits = xEventGroupWaitBits(event_group,\n                                           NETWORK_CONNECTED_BIT,\n                                           pdTRUE,  // Clear bits on exit\n                                           pdFALSE, // Wait for connection only\n                                           pdMS_TO_TICKS(timeout_ms));\n\n    if (bits & NETWORK_CONNECTED_BIT) {\n        ESP_LOGI(TAG, \"Network connected successfully\");\n        return ESP_OK;\n    } else {\n        ESP_LOGE(TAG, \"Network connection timed out\");\n        return ESP_ERR_TIMEOUT;\n    }\n}\n\n/* Start time synchronization */\nvoid app_network_start_time_sync(EventGroupHandle_t event_group)\n{\n    ESP_LOGI(TAG, \"Starting SNTP time synchronization...\");\n\n    /* Configure SNTP */\n    esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);\n    esp_sntp_setservername(0, \"pool.ntp.org\");\n    esp_sntp_setservername(1, \"time.google.com\");\n    esp_sntp_setservername(2, \"time.cloudflare.com\");\n\n    /* Start SNTP */\n    esp_sntp_init();\n\n    /* Set a flag to indicate time sync has started */\n    if (event_group) {\n        xEventGroupSetBits(event_group, TIME_SYNC_SUCCESS_BIT);\n    }\n}\n\n/* Wait for time synchronization to complete */\nesp_err_t app_network_wait_for_time_sync(EventGroupHandle_t event_group, uint32_t timeout_ms)\n{\n    time_t now = 0;\n    int retry = 0;\n    const int retry_count = timeout_ms / 2000;  // Check every 2 seconds\n    const time_t time_threshold = 1609459200;  // January 1, 2021 - reasonable baseline\n\n    ESP_LOGI(TAG, \"Waiting for time synchronization...\");\n\n    while (retry < retry_count) {\n        time(&now);\n\n        if (now >= time_threshold && sntp_get_sync_status() != SNTP_SYNC_STATUS_RESET) {\n            ESP_LOGI(TAG, \"Time synchronized successfully! Current time: %s\", ctime(&now));\n            if (event_group) {\n                xEventGroupSetBits(event_group, TIME_SYNC_SUCCESS_BIT);\n            }\n            return ESP_OK;\n        }\n\n        ESP_LOGD(TAG, \"Time sync attempt %d/%d, time: %ld, status: %d\",\n                 retry + 1, retry_count, (long)now, sntp_get_sync_status());\n\n        vTaskDelay(2000 / portTICK_PERIOD_MS);\n        retry++;\n    }\n\n    ESP_LOGW(TAG, \"Time synchronization may have failed or time is before threshold\");\n    if (event_group) {\n        xEventGroupSetBits(event_group, TIME_SYNC_FAILED_BIT);\n    }\n    return ESP_ERR_TIMEOUT;\n}"
  },
  {
    "path": "esp_schedule/examples/get_started/main/network/app_network.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/event_groups.h\"\n#include \"network_provisioning/manager.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* Event group bits for network provisioning states */\n#define NETWORK_CONNECTED_BIT      BIT0\n#define NETWORK_DISCONNECTED_BIT   BIT1\n#define PROVISIONING_SUCCESS_BIT   BIT2\n#define PROVISIONING_FAILED_BIT    BIT3\n#define TIME_SYNC_SUCCESS_BIT      BIT4\n#define TIME_SYNC_FAILED_BIT       BIT5\n\n/**\n * @brief Initialize network provisioning with event group handling\n *\n * This function initializes the network provisioning system and sets up event handlers\n * for network provisioning and IP events. It uses either BLE or SoftAP provisioning\n * based on the Kconfig selection.\n *\n * @param event_group Pointer to the event group that will be used for synchronization\n * @return esp_err_t ESP_OK on success, or error code on failure\n */\nesp_err_t app_network_init(EventGroupHandle_t event_group);\n\n/**\n * @brief Start network provisioning and wait for connection\n *\n * This function checks if the device is already provisioned. If provisioned,\n * it starts WiFi station and waits for network connection. If not provisioned,\n * it starts the provisioning sequence and waits for network connection.\n *\n * @param event_group The event group to wait on\n * @param timeout_ms Timeout in milliseconds\n * @return esp_err_t ESP_OK if network connected, ESP_FAIL if failed or timed out\n */\nesp_err_t app_network_start(EventGroupHandle_t event_group, uint32_t timeout_ms);\n\n/**\n * @brief Start time synchronization\n *\n * This function starts SNTP time synchronization and waits for it to complete.\n *\n * @param event_group The event group to signal completion on\n */\nvoid app_network_start_time_sync(EventGroupHandle_t event_group);\n\n/**\n * @brief Wait for time synchronization to complete\n *\n * This function waits for time synchronization to complete successfully.\n *\n * @param event_group The event group to wait on\n * @param timeout_ms Timeout in milliseconds\n * @return esp_err_t ESP_OK if time sync succeeded, ESP_FAIL if failed or timed out\n */\nesp_err_t app_network_wait_for_time_sync(EventGroupHandle_t event_group, uint32_t timeout_ms);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_schedule/examples/get_started/sdkconfig.defaults",
    "content": "# Example project configuration for ESP Schedule\n\n# Enable daylight (sunrise/sunset) schedules for the example\nCONFIG_ESP_SCHEDULE_ENABLE_DAYLIGHT=y\n\n# Example can become pretty big, so enable larger partition\nCONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y\n"
  },
  {
    "path": "esp_schedule/examples/get_started/sdkconfig.defaults.esp32c2",
    "content": "# ESP32C2 specific\n\nCONFIG_IDF_TARGET=\"esp32c2\"\nCONFIG_XTAL_FREQ_26=y"
  },
  {
    "path": "esp_schedule/idf_component.yml",
    "content": "## IDF Component Manager Manifest File\nversion: \"1.3.2\"\ndescription: Task scheduling based on periodic and one-time events\nurl: https://github.com/espressif/idf-extra-components/tree/master/components/esp_schedule\nrepository: https://github.com/espressif/idf-extra-components.git\nissues: https://github.com/espressif/esp-rainmaker/issues\ndependencies:\n  idf: \">=5.1\"\n  espressif/esp_daylight:\n    version: \"~1.0.1\"\n    override_path: \"../esp_daylight\"\n"
  },
  {
    "path": "esp_schedule/include/esp_schedule.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <time.h>\n#include \"esp_err.h\"\n#include \"sdkconfig.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** Schedule Handle */\ntypedef void *esp_schedule_handle_t;\n\n/** Maximum length of the schedule name allowed. This value cannot be more than 16 as it is used for NVS key. */\n#define MAX_SCHEDULE_NAME_LEN 16\n\n/** Callback for schedule trigger\n *\n * This callback is called when the schedule is triggered.\n *\n * @param[in] handle Schedule handle.\n * @param[in] priv_data Pointer to the private data passed while creating/editing the schedule.\n */\ntypedef void (*esp_schedule_trigger_cb_t)(esp_schedule_handle_t handle, void *priv_data);\n\n/** Callback for schedule timestamp\n *\n * This callback is called when the next trigger timestamp of the schedule is changed. This might be useful to check if\n * one time schedules have already passed while the device was powered off.\n *\n * @param[in] handle Schedule handle.\n * @param[in] next_timestamp timestamp at which the schedule will trigger next.\n * @param[in] priv_data Pointer to the user data passed while creating/editing the schedule.\n */\ntypedef void (*esp_schedule_timestamp_cb_t)(esp_schedule_handle_t handle, uint32_t next_timestamp, void *priv_data);\n\n/** Schedule type */\ntypedef enum esp_schedule_type {\n    ESP_SCHEDULE_TYPE_INVALID = 0,\n    ESP_SCHEDULE_TYPE_DAYS_OF_WEEK,\n    ESP_SCHEDULE_TYPE_DATE,\n    ESP_SCHEDULE_TYPE_RELATIVE,\n#if CONFIG_ESP_SCHEDULE_ENABLE_DAYLIGHT\n    ESP_SCHEDULE_TYPE_SUNRISE,\n    ESP_SCHEDULE_TYPE_SUNSET,\n#endif\n} esp_schedule_type_t;\n\n/** Schedule days. Used for ESP_SCHEDULE_TYPE_DAYS_OF_WEEK. */\ntypedef enum esp_schedule_days {\n    ESP_SCHEDULE_DAY_ONCE      = 0,\n    ESP_SCHEDULE_DAY_EVERYDAY  = 0b1111111,\n    ESP_SCHEDULE_DAY_MONDAY    = 1 << 0,\n    ESP_SCHEDULE_DAY_TUESDAY   = 1 << 1,\n    ESP_SCHEDULE_DAY_WEDNESDAY = 1 << 2,\n    ESP_SCHEDULE_DAY_THURSDAY  = 1 << 3,\n    ESP_SCHEDULE_DAY_FRIDAY    = 1 << 4,\n    ESP_SCHEDULE_DAY_SATURDAY  = 1 << 5,\n    ESP_SCHEDULE_DAY_SUNDAY    = 1 << 6,\n} esp_schedule_days_t;\n\n/** Schedule months. Used for ESP_SCHEDULE_TYPE_DATE. */\ntypedef enum esp_schedule_months {\n    ESP_SCHEDULE_MONTH_ONCE         = 0,\n    ESP_SCHEDULE_MONTH_ALL          = 0b111111111111,\n    ESP_SCHEDULE_MONTH_JANUARY      = 1 << 0,\n    ESP_SCHEDULE_MONTH_FEBRUARY     = 1 << 1,\n    ESP_SCHEDULE_MONTH_MARCH        = 1 << 2,\n    ESP_SCHEDULE_MONTH_APRIL        = 1 << 3,\n    ESP_SCHEDULE_MONTH_MAY          = 1 << 4,\n    ESP_SCHEDULE_MONTH_JUNE         = 1 << 5,\n    ESP_SCHEDULE_MONTH_JULY         = 1 << 6,\n    ESP_SCHEDULE_MONTH_AUGUST       = 1 << 7,\n    ESP_SCHEDULE_MONTH_SEPTEMBER    = 1 << 8,\n    ESP_SCHEDULE_MONTH_OCTOBER      = 1 << 9,\n    ESP_SCHEDULE_MONTH_NOVEMBER     = 1 << 10,\n    ESP_SCHEDULE_MONTH_DECEMBER     = 1 << 11,\n} esp_schedule_months_t;\n\n/** Trigger details of the schedule */\ntypedef struct esp_schedule_trigger {\n    /** Type of schedule */\n    esp_schedule_type_t type;\n    /** Hours in 24 hour format. Accepted values: 0-23 */\n    uint8_t hours;\n    /** Minutes in the given hour. Accepted values: 0-59. */\n    uint8_t minutes;\n    /** For type ESP_SCHEDULE_TYPE_DAYS_OF_WEEK and solar schedules with day-of-week patterns */\n    struct {\n        /** 'OR' list of esp_schedule_days_t */\n        uint8_t repeat_days;\n    } day;\n    /** For type ESP_SCHEDULE_TYPE_DATE and solar schedules with specific date patterns */\n    struct {\n        /** Day of the month. Accepted values: 1-31. */\n        uint8_t day;\n        /* 'OR' list of esp_schedule_months_t */\n        uint16_t repeat_months;\n        /** Year */\n        uint16_t year;\n        /** If the schedule is to be repeated every year. */\n        bool repeat_every_year;\n    } date;\n#if CONFIG_ESP_SCHEDULE_ENABLE_DAYLIGHT\n    /** For type ESP_SCHEDULE_TYPE_SUNRISE and ESP_SCHEDULE_TYPE_SUNSET\n     * Uses day.repeat_days for day-of-week patterns (if date.day == 0)\n     * Uses date.* fields for specific date patterns (if date.day != 0)\n     * If both are 0, treated as single-time schedule */\n    struct {\n        /** Latitude in decimal degrees (-90 to +90, positive North) */\n        double latitude;\n        /** Longitude in decimal degrees (-180 to +180, positive East) */\n        double longitude;\n        /** Offset in minutes from sunrise/sunset (positive = after, negative = before) */\n        int offset_minutes;\n    } solar;\n#endif\n    /** For type ESP_SCHEDULE_TYPE_SECONDS */\n    int relative_seconds;\n    /** Used for passing the next schedule timestamp for\n     * ESP_SCHEDULE_TYPE_RELATIVE */\n    time_t next_scheduled_time_utc;\n} esp_schedule_trigger_t;\n\n/** Schedule Validity\n * Start and end time within which the schedule will be applicable.\n */\ntypedef struct esp_schedule_validity {\n    /* Start time as UTC timestamp */\n    time_t start_time;\n    /* End time as UTC timestamp */\n    time_t end_time;\n} esp_schedule_validity_t;\n\n/** Schedule config */\ntypedef struct esp_schedule_config {\n    /** Name of the schedule. This is like a primary key for the schedule. This is required. +1 for NULL termination. */\n    char name[MAX_SCHEDULE_NAME_LEN + 1];\n    /** Trigger details */\n    esp_schedule_trigger_t trigger;\n    /** Trigger callback */\n    esp_schedule_trigger_cb_t trigger_cb;\n    /** Timestamp callback */\n    esp_schedule_timestamp_cb_t timestamp_cb;\n    /** Private data associated with the schedule. This will be passed to callbacks. */\n    void *priv_data;\n    /** Validity of schedules. */\n    esp_schedule_validity_t validity;\n} esp_schedule_config_t;\n\n/** Initialize ESP Schedule\n *\n * This initializes ESP Schedule. This must be called first before calling any of the other APIs.\n * This API also gets all the schedules from NVS (if it has been enabled).\n *\n * Note: After calling this API, the pointers to the callbacks should be updated for all the schedules by calling\n * esp_schedule_get() followed by esp_schedule_edit() with the correct callbacks.\n *\n * @param[in] enable_nvs If NVS is to be enabled or not.\n * @param[in] nvs_partition (Optional) The NVS partition to be used. If NULL is passed, the default partition is used.\n * @param[out] schedule_count Number of active schedules found in NVS.\n *\n * @return Array of schedule handles if any schedules have been found.\n * @return NULL if no schedule is found in NVS (or if NVS is not enabled).\n */\nesp_schedule_handle_t *esp_schedule_init(bool enable_nvs, char *nvs_partition, uint8_t *schedule_count);\n\n/** Create Schedule\n *\n * This API can be used to create a new schedule. The schedule still needs to be enabled using\n * esp_schedule_enable().\n *\n * @param[in] schedule_config Configuration of the schedule to be created.\n *\n * @return Schedule handle if successfully created.\n * @return NULL in case of error.\n */\nesp_schedule_handle_t esp_schedule_create(esp_schedule_config_t *schedule_config);\n\n/** Remove Schedule\n *\n * This API can be used to remove an existing schedule.\n *\n * @param[in] handle Schedule handle for the schedule to be removed.\n *\n * @return ESP_OK on success.\n * @return error in case of failure.\n */\nesp_err_t esp_schedule_delete(esp_schedule_handle_t handle);\n\n/** Edit Schedule\n *\n * This API can be used to edit an existing schedule.\n * The schedule name should be same as when the schedule was created. The complete config must be provided\n * or the previously stored config might be over-written.\n *\n * Note: If a schedule is edited when it is on-going, the new changes will not be reflected.\n * You will need to disable the schedule, edit it, and then enable it again.\n *\n * @param[in] handle Schedule handle for the schedule to be edited.\n * @param[in] schedule_config Configuration of the schedule to be edited.\n *\n * @return ESP_OK on success.\n * @return error in case of failure.\n */\nesp_err_t esp_schedule_edit(esp_schedule_handle_t handle, esp_schedule_config_t *schedule_config);\n\n/** Enable Schedule\n *\n * This API can be used to enable an existing schedule.\n * It can be used to enable a schedule after it has been created using esp_schedule_create()\n * or if the schedule has been disabled using esp_schedule_disable().\n *\n * @param[in] handle Schedule handle for the schedule to be enabled.\n *\n * @return ESP_OK on success.\n * @return error in case of failure.\n */\nesp_err_t esp_schedule_enable(esp_schedule_handle_t handle);\n\n/** Disable Schedule\n *\n * This API can be used to disable an on-going schedule.\n * It does not remove the schedule, just stops it. The schedule can be enabled again using\n * esp_schedule_enable().\n *\n * @param[in] handle Schedule handle for the schedule to be disabled.\n *\n * @return ESP_OK on success.\n * @return error in case of failure.\n */\nesp_err_t esp_schedule_disable(esp_schedule_handle_t handle);\n\n/** Get Schedule\n *\n * This API can be used to get details of an existing schedule.\n * The schedule_config is populated with the schedule details.\n *\n * @param[in] handle Schedule handle.\n * @param[out] schedule_config Details of the schedule whose handle is passed.\n *\n * @return ESP_OK on success.\n * @return error in case of failure.\n */\nesp_err_t esp_schedule_get(esp_schedule_handle_t handle, esp_schedule_config_t *schedule_config);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_schedule/src/esp_schedule.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include <string.h>\n#include <inttypes.h>\n#include \"esp_log.h\"\n#include \"esp_sntp.h\"\n#include \"esp_daylight.h\"\n#include \"esp_schedule_internal.h\"\n\nstatic const char *TAG = \"esp_schedule\";\n\n#define SECONDS_TILL_2020 ((2020 - 1970) * 365 * 24 * 3600)\n#define SECONDS_IN_DAY (60 * 60 * 24)\n\nstatic bool init_done = false;\n\nstatic int esp_schedule_get_no_of_days(esp_schedule_trigger_t *trigger, struct tm *current_time, struct tm *schedule_time)\n{\n    /* for day, monday = 0, sunday = 6. */\n    int next_day = 0;\n    /* struct tm has tm_wday with sunday as 0. Whereas we have monday as 0. Converting struct tm to our format */\n    int today = ((current_time->tm_wday + 7 - 1) % 7);\n\n    esp_schedule_days_t today_bit = 1 << today;\n    uint8_t repeat_days = trigger->day.repeat_days;\n    int current_seconds = (current_time->tm_hour * 60 + current_time->tm_min) * 60 + current_time->tm_sec;\n    int schedule_seconds = (schedule_time->tm_hour * 60 + schedule_time->tm_min) * 60;\n\n    /* Handling for one time schedule */\n    if (repeat_days == ESP_SCHEDULE_DAY_ONCE) {\n        if (schedule_seconds > current_seconds) {\n            /* The schedule is today and is yet to go off */\n            return 0;\n        } else {\n            /* The schedule is tomorrow */\n            return 1;\n        }\n    }\n\n    /* Handling for repeating schedules */\n    /* Check if it is today */\n    if ((repeat_days & today_bit)) {\n        if (schedule_seconds > current_seconds) {\n            /* The schedule is today and is yet to go off. */\n            return 0;\n        }\n    }\n    /* Check if it is this week or next week */\n    if ((repeat_days & (today_bit ^ 0xFF)) > today_bit) {\n        /* Next schedule is yet to come in this week */\n        next_day = ffs(repeat_days & (0xFF << (today + 1))) - 1;\n        return (next_day - today);\n    } else {\n        /* First scheduled day of the next week */\n        next_day = ffs(repeat_days) - 1;\n        if (next_day == today) {\n            /* Same day, next week */\n            return 7;\n        }\n        return (7 - today + next_day);\n    }\n\n    ESP_LOGE(TAG, \"No of days could not be found. This should not happen.\");\n    return 0;\n}\n\nstatic uint8_t esp_schedule_get_next_month(esp_schedule_trigger_t *trigger, struct tm *current_time, struct tm *schedule_time)\n{\n    int current_seconds = (current_time->tm_hour * 60 + current_time->tm_min) * 60 + current_time->tm_sec;\n    int schedule_seconds = (schedule_time->tm_hour * 60 + schedule_time->tm_min) * 60;\n    /* +1 is because struct tm has months starting from 0, whereas we have them starting from 1 */\n    uint8_t current_month = current_time->tm_mon + 1;\n    /* -1 because month_bit starts from 0b1. So for January, it should be 1 << 0. And current_month starts from 1. */\n    uint16_t current_month_bit = 1 << (current_month - 1);\n    uint8_t next_schedule_month = 0;\n    uint16_t repeat_months = trigger->date.repeat_months;\n\n    /* Check if month is not specified */\n    if (repeat_months == ESP_SCHEDULE_MONTH_ONCE) {\n        if (trigger->date.day == current_time->tm_mday) {\n            /* The schedule day is same. Check if time has already passed */\n            if (schedule_seconds > current_seconds) {\n                /* The schedule is today and is yet to go off */\n                return current_month;\n            } else {\n                /* Today's time has passed */\n                return (current_month + 1);\n            }\n        } else if (trigger->date.day > current_time->tm_mday) {\n            /* The day is yet to come in this month */\n            return current_month;\n        } else {\n            /* The day has passed in the current month */\n            return (current_month + 1);\n        }\n    }\n\n    /* Check if schedule is not this year itself, it is in future. */\n    if (trigger->date.year > (current_time->tm_year + 1900)) {\n        /* Find first schedule month of next year */\n        next_schedule_month = ffs(repeat_months);\n        /* Year will be handled by the caller. So no need to add any additional months */\n        return next_schedule_month;\n    }\n\n    /* Check if schedule is this month and is yet to come */\n    if (current_month_bit & repeat_months) {\n        if (trigger->date.day == current_time->tm_mday) {\n            /* The schedule day is same. Check if time has already passed */\n            if (schedule_seconds > current_seconds) {\n                /* The schedule is today and is yet to go off */\n                return current_month;\n            }\n        }\n        if (trigger->date.day > current_time->tm_mday) {\n            /* The day is yet to come in this month */\n            return current_month;\n        }\n    }\n\n    /* Check if schedule is this year */\n    if ((repeat_months & (current_month_bit ^ 0xFFFF)) > current_month_bit) {\n        /* Next schedule month is yet to come in this year */\n        next_schedule_month = ffs(repeat_months & (0xFFFF << (current_month)));\n        return next_schedule_month;\n    }\n\n    /* Check if schedule is for this year and does not repeat */\n    if (!trigger->date.repeat_every_year) {\n        /* For yearly repeating schedules with year=0, treat as repeating */\n        if (trigger->date.year != 0 && trigger->date.year <= (current_time->tm_year + 1900)) {\n            ESP_LOGE(TAG, \"Schedule does not repeat next year, but get_next_month has been called.\");\n            return 0;\n        }\n    }\n\n    /* Schedule is not this year */\n    /* Find first schedule month of next year */\n    next_schedule_month = ffs(repeat_months);\n    /* +12 because the schedule is next year */\n    return (next_schedule_month + 12);\n}\n\nstatic uint16_t esp_schedule_get_next_year(esp_schedule_trigger_t *trigger, struct tm *current_time, struct tm *schedule_time)\n{\n    uint16_t current_year = current_time->tm_year + 1900;\n    uint16_t schedule_year = trigger->date.year;\n    if (schedule_year > current_year) {\n        return schedule_year;\n    }\n    /* If the schedule is set to repeat_every_year, we return the current year */\n    /* If the schedule has already passed in this year, we still return current year, as the additional months will be handled in get_next_month */\n    return current_year;\n}\n\n#if CONFIG_ESP_SCHEDULE_ENABLE_DAYLIGHT\n/* Helper function to calculate solar time for a specific date */\nstatic time_t esp_schedule_calc_solar_time_for_date(const esp_schedule_trigger_t *trigger,\n        int year, int month, int day,\n        const char *schedule_name)\n{\n    time_t sunrise_utc, sunset_utc;\n\n    bool calc_ok = esp_daylight_calc_sunrise_sunset_utc(\n                       year, month, day,\n                       trigger->solar.latitude,\n                       trigger->solar.longitude,\n                       &sunrise_utc, &sunset_utc);\n\n    if (!calc_ok) {\n        ESP_LOGW(TAG, \"Failed to calculate sunrise/sunset for date %04d-%02d-%02d for %s (likely polar night/day condition)\",\n                 year, month, day, schedule_name);\n        return 0;\n    }\n\n    time_t solar_time = (trigger->type == ESP_SCHEDULE_TYPE_SUNRISE) ? sunrise_utc : sunset_utc;\n    return esp_daylight_apply_offset(solar_time, trigger->solar.offset_minutes);\n}\n\n/* Helper function to handle logging and timer calculation for solar schedules */\nstatic int32_t esp_schedule_finalize_solar_time(time_t solar_time, time_t now,\n        const esp_schedule_trigger_t *trigger,\n        const char *schedule_name)\n{\n    char time_str[64];\n    struct tm schedule_time;\n\n    /* Convert solar time to local time for display and DST handling */\n    localtime_r(&solar_time, &schedule_time);\n\n    /* Print schedule time */\n    memset(time_str, 0, sizeof(time_str));\n    strftime(time_str, sizeof(time_str), \"%c %z[%Z]\", &schedule_time);\n    ESP_LOGI(TAG, \"Schedule %s (%s%+d min) will be active on: %s. DST: %s\",\n             schedule_name,\n             (trigger->type == ESP_SCHEDULE_TYPE_SUNRISE) ? \"sunrise\" : \"sunset\",\n             trigger->solar.offset_minutes,\n             time_str, schedule_time.tm_isdst ? \"Yes\" : \"No\");\n\n    /* Simple epoch-based timer calculation */\n    int32_t timer_seconds = (int32_t)difftime(solar_time, now);\n\n    /* With proactive logic, this should not happen, but log if it does */\n    if (timer_seconds < 0) {\n        ESP_LOGW(TAG, \"Unexpected: Solar schedule time has passed (%\" PRId32 \" seconds ago). This should have been handled proactively.\", -timer_seconds);\n        /* Return the negative value to help debug - caller will handle this as error */\n    }\n\n    return timer_seconds;\n}\n#endif /* CONFIG_ESP_SCHEDULE_ENABLE_DAYLIGHT */\n\nstatic uint32_t esp_schedule_get_next_schedule_time_diff(const char *schedule_name, esp_schedule_trigger_t *trigger)\n{\n    struct tm current_time, schedule_time;\n    time_t now;\n    char time_str[64];\n    int32_t time_diff;\n\n    /* Get current time */\n    time(&now);\n    /* Handling ESP_SCHEDULE_TYPE_RELATIVE first since it doesn't require any\n     * computation based on days, hours, minutes, etc.\n     */\n    if (trigger->type == ESP_SCHEDULE_TYPE_RELATIVE) {\n        /* If next scheduled time is already set, just compute the difference\n         * between current time and next scheduled time and return that diff.\n         */\n        time_t target;\n        if (trigger->next_scheduled_time_utc > 0) {\n            target = (time_t)trigger->next_scheduled_time_utc;\n            time_diff = difftime(target, now);\n        } else {\n            target = now + (time_t)trigger->relative_seconds;\n            time_diff = trigger->relative_seconds;\n        }\n        localtime_r(&target, &schedule_time);\n        trigger->next_scheduled_time_utc = mktime(&schedule_time);\n        /* Print schedule time */\n        memset(time_str, 0, sizeof(time_str));\n        strftime(time_str, sizeof(time_str), \"%c %z[%Z]\", &schedule_time);\n        ESP_LOGI(TAG, \"Schedule %s will be active on: %s. DST: %s\", schedule_name, time_str, schedule_time.tm_isdst ? \"Yes\" : \"No\");\n        return time_diff;\n    }\n\n    /* Handle solar-based schedules (sunrise/sunset) */\n#if CONFIG_ESP_SCHEDULE_ENABLE_DAYLIGHT\n    if (trigger->type == ESP_SCHEDULE_TYPE_SUNRISE || trigger->type == ESP_SCHEDULE_TYPE_SUNSET) {\n        time_t solar_time = 0;\n\n        /* Start with current local time for day calculations */\n        localtime_r(&now, &current_time);\n\n        /* Determine schedule pattern using unified approach */\n        if (trigger->date.day != 0) {\n            /* Date-based solar schedule - check if today's solar time + offset has passed */\n            struct tm schedule_time = current_time;\n            schedule_time.tm_mday = trigger->date.day;\n\n            /* For same day, check if solar time + offset has passed before deciding year */\n            if (trigger->date.day == current_time.tm_mday) {\n                uint8_t current_month = current_time.tm_mon + 1;\n                uint16_t repeat_months = trigger->date.repeat_months;\n                uint16_t current_month_bit = 1 << (current_month - 1);\n\n                /* Check if this month is in the repeat pattern */\n                if (current_month_bit & repeat_months) {\n                    /* Calculate today's solar time + offset */\n                    time_t today_solar = esp_schedule_calc_solar_time_for_date(trigger,\n                                         current_time.tm_year + 1900,\n                                         current_time.tm_mon + 1,\n                                         current_time.tm_mday,\n                                         schedule_name);\n\n                    /* If today's solar time + offset hasn't passed, use today */\n                    if (today_solar > 0 && today_solar > now) {\n                        schedule_time.tm_mon = current_time.tm_mon;\n                        schedule_time.tm_year = current_time.tm_year;\n                    } else {\n                        /* Solar time has passed, use next occurrence */\n                        schedule_time.tm_mon = esp_schedule_get_next_month(trigger, &current_time, &schedule_time) - 1;\n                        schedule_time.tm_year = esp_schedule_get_next_year(trigger, &current_time, &schedule_time) - 1900;\n                    }\n                } else {\n                    /* Not this month, use normal logic */\n                    schedule_time.tm_mon = esp_schedule_get_next_month(trigger, &current_time, &schedule_time) - 1;\n                    schedule_time.tm_year = esp_schedule_get_next_year(trigger, &current_time, &schedule_time) - 1900;\n                }\n            } else {\n                /* Different day, use normal logic */\n                schedule_time.tm_mon = esp_schedule_get_next_month(trigger, &current_time, &schedule_time) - 1;\n                schedule_time.tm_year = esp_schedule_get_next_year(trigger, &current_time, &schedule_time) - 1900;\n            }\n\n            if (schedule_time.tm_mon < 0) {\n                ESP_LOGE(TAG, \"Invalid month found for solar schedule: %s\", schedule_name);\n                return 0;\n            }\n            if (schedule_time.tm_mon >= 12) {\n                schedule_time.tm_year += schedule_time.tm_mon / 12;\n                schedule_time.tm_mon = schedule_time.tm_mon % 12;\n            }\n            mktime(&schedule_time);\n\n            /* Calculate solar time for the determined date */\n            solar_time = esp_schedule_calc_solar_time_for_date(trigger,\n                         schedule_time.tm_year + 1900,\n                         schedule_time.tm_mon + 1,\n                         schedule_time.tm_mday,\n                         schedule_name);\n\n        } else if (trigger->day.repeat_days != 0) {\n            /* Day-of-week solar schedule - check if today's solar time + offset has passed */\n            struct tm schedule_time = current_time;\n\n            /* Check if today is one of the scheduled days */\n            int today = current_time.tm_wday == 0 ? 7 : current_time.tm_wday; /* Convert Sunday from 0 to 7 */\n            uint8_t today_bit = 1 << (today - 1); /* Monday=bit0, Tuesday=bit1, etc. */\n\n            if (trigger->day.repeat_days & today_bit) {\n                /* Today is a scheduled day, check if solar time + offset has passed */\n                time_t today_solar = esp_schedule_calc_solar_time_for_date(trigger,\n                                     current_time.tm_year + 1900,\n                                     current_time.tm_mon + 1,\n                                     current_time.tm_mday,\n                                     schedule_name);\n\n                /* If today's solar time + offset hasn't passed, use today */\n                if (today_solar > 0 && today_solar > now) {\n                    /* Use today */\n                    solar_time = today_solar;\n                } else {\n                    /* Solar time has passed, find next scheduled day */\n                    int no_of_days = esp_schedule_get_no_of_days(trigger, &current_time, &schedule_time);\n                    schedule_time.tm_mday += no_of_days;\n                    mktime(&schedule_time);\n\n                    solar_time = esp_schedule_calc_solar_time_for_date(trigger,\n                                 schedule_time.tm_year + 1900,\n                                 schedule_time.tm_mon + 1,\n                                 schedule_time.tm_mday,\n                                 schedule_name);\n                }\n            } else {\n                /* Today is not a scheduled day, use normal logic */\n                int no_of_days = esp_schedule_get_no_of_days(trigger, &current_time, &schedule_time);\n                schedule_time.tm_mday += no_of_days;\n                mktime(&schedule_time);\n\n                solar_time = esp_schedule_calc_solar_time_for_date(trigger,\n                             schedule_time.tm_year + 1900,\n                             schedule_time.tm_mon + 1,\n                             schedule_time.tm_mday,\n                             schedule_name);\n            }\n\n        } else {\n            /* Single-time solar schedule - use logic similar to regular schedules */\n            solar_time = esp_schedule_calc_solar_time_for_date(trigger,\n                         current_time.tm_year + 1900,\n                         current_time.tm_mon + 1,\n                         current_time.tm_mday,\n                         schedule_name);\n\n            /* If time has passed today, calculate for tomorrow (like regular schedules) */\n            if (solar_time > 0 && solar_time <= now) {\n                struct tm tomorrow_time;\n                localtime_r(&now, &tomorrow_time);  // Use fresh local time\n                tomorrow_time.tm_mday += 1;\n                mktime(&tomorrow_time);\n\n                solar_time = esp_schedule_calc_solar_time_for_date(trigger,\n                             tomorrow_time.tm_year + 1900,\n                             tomorrow_time.tm_mon + 1,\n                             tomorrow_time.tm_mday,\n                             schedule_name);\n\n                /* If tomorrow's time is still in the past (due to large negative offset), try day after tomorrow */\n                if (solar_time > 0 && solar_time <= now) {\n                    tomorrow_time.tm_mday += 1;\n                    mktime(&tomorrow_time);\n\n                    solar_time = esp_schedule_calc_solar_time_for_date(trigger,\n                                 tomorrow_time.tm_year + 1900,\n                                 tomorrow_time.tm_mon + 1,\n                                 tomorrow_time.tm_mday,\n                                 schedule_name);\n                }\n            }\n        }\n\n        /* Return error if solar calculation failed */\n        if (solar_time == 0) {\n            ESP_LOGW(TAG, \"Solar schedule %s cannot be calculated (no sunrise/sunset at this location/date)\", schedule_name);\n            return 0;\n        }\n\n        /* Calculate timer - should always be positive since we proactively handle past times */\n        time_diff = esp_schedule_finalize_solar_time(solar_time, now, trigger, schedule_name);\n        if (time_diff < 0) {\n            /* This should not happen with proactive logic, but handle gracefully */\n            ESP_LOGE(TAG, \"Solar schedule time calculation error for %s (got %\" PRId32 \" seconds)\", schedule_name, time_diff);\n            return 0;\n        }\n\n        /* Store the final scheduled time - use raw UTC solar time for ts field (phone apps need UTC) */\n        trigger->next_scheduled_time_utc = solar_time;\n\n        return time_diff;\n    }\n#endif /* CONFIG_ESP_SCHEDULE_ENABLE_DAYLIGHT */\n\n    localtime_r(&now, &current_time);\n\n    /* Get schedule time */\n    localtime_r(&now, &schedule_time);\n    schedule_time.tm_sec = 0;\n    schedule_time.tm_min = trigger->minutes;\n    schedule_time.tm_hour = trigger->hours;\n    mktime(&schedule_time);\n\n    /* Adjust schedule day */\n    if (trigger->type == ESP_SCHEDULE_TYPE_DAYS_OF_WEEK) {\n        int no_of_days = 0;\n        no_of_days = esp_schedule_get_no_of_days(trigger, &current_time, &schedule_time);\n        schedule_time.tm_sec += no_of_days * SECONDS_IN_DAY;\n    }\n    if (trigger->type == ESP_SCHEDULE_TYPE_DATE) {\n        schedule_time.tm_mday = trigger->date.day;\n        schedule_time.tm_mon = esp_schedule_get_next_month(trigger, &current_time, &schedule_time) - 1;\n        schedule_time.tm_year = esp_schedule_get_next_year(trigger, &current_time, &schedule_time) - 1900;\n        if (schedule_time.tm_mon < 0) {\n            ESP_LOGE(TAG, \"Invalid month found: %d. Setting it to next month.\", schedule_time.tm_mon);\n            schedule_time.tm_mon = current_time.tm_mon + 1;\n        }\n        if (schedule_time.tm_mon >= 12) {\n            schedule_time.tm_year += schedule_time.tm_mon / 12;\n            schedule_time.tm_mon = schedule_time.tm_mon % 12;\n        }\n    }\n    mktime(&schedule_time);\n\n    /* Adjust time according to DST */\n    time_t dst_adjust = 0;\n    if (!current_time.tm_isdst && schedule_time.tm_isdst) {\n        dst_adjust = -3600;\n    } else if (current_time.tm_isdst && !schedule_time.tm_isdst) {\n        dst_adjust = 3600;\n    }\n    ESP_LOGD(TAG, \"DST adjust seconds: %lld\", (long long) dst_adjust);\n    schedule_time.tm_sec += dst_adjust;\n    mktime(&schedule_time);\n\n    /* Print schedule time */\n    memset(time_str, 0, sizeof(time_str));\n    strftime(time_str, sizeof(time_str), \"%c %z[%Z]\", &schedule_time);\n    ESP_LOGI(TAG, \"Schedule %s will be active on: %s. DST: %s\", schedule_name, time_str, schedule_time.tm_isdst ? \"Yes\" : \"No\");\n\n    /* Calculate difference */\n    time_diff = difftime((mktime(&schedule_time)), mktime(&current_time));\n\n    /* For one time schedules to check for expiry after a reboot. If NVS is enabled, this should be stored in NVS. */\n    trigger->next_scheduled_time_utc = mktime(&schedule_time);\n\n    return time_diff;\n}\n\nstatic bool esp_schedule_is_expired(esp_schedule_trigger_t *trigger)\n{\n    time_t current_timestamp = 0;\n    struct tm current_time = {0};\n    time(&current_timestamp);\n    localtime_r(&current_timestamp, &current_time);\n\n    if (trigger->type == ESP_SCHEDULE_TYPE_RELATIVE) {\n        if (trigger->next_scheduled_time_utc > 0 && trigger->next_scheduled_time_utc <= current_timestamp) {\n            /* Relative seconds based schedule has expired */\n            return true;\n        } else if (trigger->next_scheduled_time_utc == 0) {\n            /* Schedule has been disabled, so it is as good as expired. */\n            return true;\n        }\n    } else if (trigger->type == ESP_SCHEDULE_TYPE_DAYS_OF_WEEK) {\n        if (trigger->day.repeat_days == ESP_SCHEDULE_DAY_ONCE) {\n            if (trigger->next_scheduled_time_utc > 0 && trigger->next_scheduled_time_utc <= current_timestamp) {\n                /* One time schedule has expired */\n                return true;\n            } else if (trigger->next_scheduled_time_utc == 0) {\n                /* Schedule has been disabled, so it is as good as expired. */\n                return true;\n            }\n        }\n#if CONFIG_ESP_SCHEDULE_ENABLE_DAYLIGHT\n    } else if (trigger->type == ESP_SCHEDULE_TYPE_SUNRISE || trigger->type == ESP_SCHEDULE_TYPE_SUNSET) {\n        /* Check if this is a single-time solar schedule */\n        if (trigger->date.day == 0 && trigger->day.repeat_days == 0) {\n            if (trigger->next_scheduled_time_utc > 0 && trigger->next_scheduled_time_utc <= current_timestamp) {\n                /* One time solar schedule has expired */\n                return true;\n            } else if (trigger->next_scheduled_time_utc == 0) {\n                /* Schedule has been disabled, so it is as good as expired. */\n                return true;\n            }\n        }\n        /* Repeating solar schedules (day-of-week or date-based) never expire - they recalculate */\n#endif\n    } else if (trigger->type == ESP_SCHEDULE_TYPE_DATE) {\n        if (trigger->date.repeat_months == 0) {\n            if (trigger->next_scheduled_time_utc > 0 && trigger->next_scheduled_time_utc <= current_timestamp) {\n                /* One time schedule has expired */\n                return true;\n            } else {\n                return false;\n            }\n        }\n        if (trigger->date.repeat_every_year == true) {\n            return false;\n        }\n\n        struct tm schedule_time = {0};\n        localtime_r(&current_timestamp, &schedule_time);\n        schedule_time.tm_sec = 0;\n        schedule_time.tm_min = trigger->minutes;\n        schedule_time.tm_hour = trigger->hours;\n        schedule_time.tm_mday = trigger->date.day;\n        /* For expiry, just check the last month of the repeat_months. */\n        /* '-1' because struct tm has months starting from 0 and we have months starting from 1. */\n        schedule_time.tm_mon = fls(trigger->date.repeat_months) - 1;\n        /* '-1900' because struct tm has number of years after 1900 */\n        schedule_time.tm_year = trigger->date.year - 1900;\n        time_t schedule_timestamp = mktime(&schedule_time);\n\n        if (schedule_timestamp < current_timestamp) {\n            return true;\n        }\n    } else {\n        /* Invalid type. Mark as expired */\n        return true;\n    }\n    return false;\n}\n\nstatic void esp_schedule_stop_timer(esp_schedule_t *schedule)\n{\n    xTimerStop(schedule->timer, portMAX_DELAY);\n}\n\nstatic void esp_schedule_start_timer(esp_schedule_t *schedule)\n{\n    time_t current_time = 0;\n    time(&current_time);\n    if (current_time < SECONDS_TILL_2020) {\n        ESP_LOGE(TAG, \"Time is not updated\");\n        return;\n    }\n\n    schedule->next_scheduled_time_diff = esp_schedule_get_next_schedule_time_diff(schedule->name, &schedule->trigger);\n\n    /* Check if schedule calculation failed (returns 0) */\n    if (schedule->next_scheduled_time_diff == 0) {\n        ESP_LOGW(TAG, \"Schedule %s calculation failed or returned invalid time. Skipping timer creation.\", schedule->name);\n        /* Reset timestamp to indicate schedule is not active */\n        schedule->trigger.next_scheduled_time_utc = 0;\n        return;\n    }\n\n    ESP_LOGI(TAG, \"Starting a timer for %\"PRIu32\" seconds for schedule %s\", schedule->next_scheduled_time_diff, schedule->name);\n\n    if (schedule->timestamp_cb) {\n        schedule->timestamp_cb((esp_schedule_handle_t)schedule, schedule->trigger.next_scheduled_time_utc, schedule->priv_data);\n    }\n\n    xTimerStop(schedule->timer, portMAX_DELAY);\n    xTimerChangePeriod(schedule->timer, (schedule->next_scheduled_time_diff * 1000) / portTICK_PERIOD_MS, portMAX_DELAY);\n}\n\nstatic void esp_schedule_common_timer_cb(TimerHandle_t timer)\n{\n    void *priv_data = pvTimerGetTimerID(timer);\n    if (priv_data == NULL) {\n        return;\n    }\n    esp_schedule_t *schedule = (esp_schedule_t *)priv_data;\n    time_t now;\n    time(&now);\n    struct tm validity_time;\n    char time_str[64] = {0};\n    if (schedule->validity.start_time != 0) {\n        if (now < schedule->validity.start_time) {\n            memset(time_str, 0, sizeof(time_str));\n            localtime_r(&schedule->validity.start_time, &validity_time);\n            strftime(time_str, sizeof(time_str), \"%c %z[%Z]\", &validity_time);\n            ESP_LOGW(TAG, \"Schedule %s skipped. It will be active only after: %s. DST: %s.\", schedule->name, time_str, validity_time.tm_isdst ? \"Yes\" : \"No\");\n            /* TODO: Start the timer such that the next time it triggers, it will be within the valid window.\n             * Currently, it will just keep triggering and then get skipped if not in valid range.\n             */\n            goto restart_schedule;\n        }\n    }\n    if (schedule->validity.end_time != 0) {\n        if (now > schedule->validity.end_time) {\n            localtime_r(&schedule->validity.end_time, &validity_time);\n            strftime(time_str, sizeof(time_str), \"%c %z[%Z]\", &validity_time);\n            ESP_LOGW(TAG, \"Schedule %s skipped. It can't be active after: %s. DST: %s.\", schedule->name, time_str, validity_time.tm_isdst ? \"Yes\" : \"No\");\n            /* Return from here will ensure that the timer does not start again for this schedule */\n            return;\n        }\n    }\n    ESP_LOGI(TAG, \"Schedule %s triggered\", schedule->name);\n    if (schedule->trigger_cb) {\n        schedule->trigger_cb((esp_schedule_handle_t)schedule, schedule->priv_data);\n    }\n\nrestart_schedule:\n\n    if (esp_schedule_is_expired(&schedule->trigger)) {\n        /* Not deleting the schedule here. Just not starting it again. */\n        return;\n    }\n    esp_schedule_start_timer(schedule);\n}\n\nstatic void esp_schedule_delete_timer(esp_schedule_t *schedule)\n{\n    xTimerDelete(schedule->timer, portMAX_DELAY);\n}\n\nstatic void esp_schedule_create_timer(esp_schedule_t *schedule)\n{\n    if (esp_schedule_nvs_is_enabled()) {\n        /* This is just used for calculating next_scheduled_time_utc for ESP_SCHEDULE_DAY_ONCE (in case of ESP_SCHEDULE_TYPE_DAYS_OF_WEEK) or for ESP_SCHEDULE_MONTH_ONCE (in case of ESP_SCHEDULE_TYPE_DATE), and only used when NVS is enabled. And if NVS is enabled, time will already be synced and the time will be correctly calculated. */\n        schedule->next_scheduled_time_diff = esp_schedule_get_next_schedule_time_diff(schedule->name, &schedule->trigger);\n    }\n\n    /* Temporarily setting the timer for 1 (anything greater than 0) tick. This will get changed when xTimerChangePeriod() is called. */\n    schedule->timer = xTimerCreate(\"schedule\", 1, pdFALSE, (void *)schedule, esp_schedule_common_timer_cb);\n}\n\nesp_err_t esp_schedule_get(esp_schedule_handle_t handle, esp_schedule_config_t *schedule_config)\n{\n    if (schedule_config == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    if (handle == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    esp_schedule_t *schedule = (esp_schedule_t *)handle;\n\n    strlcpy(schedule_config->name, schedule->name, sizeof(schedule_config->name));\n    schedule_config->trigger.type = schedule->trigger.type;\n    schedule_config->trigger.hours = schedule->trigger.hours;\n    schedule_config->trigger.minutes = schedule->trigger.minutes;\n    if (schedule->trigger.type == ESP_SCHEDULE_TYPE_DAYS_OF_WEEK) {\n        schedule_config->trigger.day.repeat_days = schedule->trigger.day.repeat_days;\n    } else if (schedule->trigger.type == ESP_SCHEDULE_TYPE_DATE) {\n        schedule_config->trigger.date.day = schedule->trigger.date.day;\n        schedule_config->trigger.date.repeat_months = schedule->trigger.date.repeat_months;\n        schedule_config->trigger.date.year = schedule->trigger.date.year;\n        schedule_config->trigger.date.repeat_every_year = schedule->trigger.date.repeat_every_year;\n    }\n\n    schedule_config->trigger_cb = schedule->trigger_cb;\n    schedule_config->timestamp_cb = schedule->timestamp_cb;\n    schedule_config->priv_data = schedule->priv_data;\n    schedule_config->validity = schedule->validity;\n    return ESP_OK;\n}\n\nesp_err_t esp_schedule_enable(esp_schedule_handle_t handle)\n{\n    if (handle == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    esp_schedule_t *schedule = (esp_schedule_t *)handle;\n    esp_schedule_start_timer(schedule);\n    return ESP_OK;\n}\n\nesp_err_t esp_schedule_disable(esp_schedule_handle_t handle)\n{\n    if (handle == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    esp_schedule_t *schedule = (esp_schedule_t *)handle;\n    esp_schedule_stop_timer(schedule);\n    /* Disabling a schedule should also reset the next_scheduled_time.\n     * It would be re-computed after enabling.\n     */\n    schedule->trigger.next_scheduled_time_utc = 0;\n    return ESP_OK;\n}\n\nstatic esp_err_t esp_schedule_set(esp_schedule_t *schedule, esp_schedule_config_t *schedule_config)\n{\n    /* Setting everything apart from name. */\n    schedule->trigger.type = schedule_config->trigger.type;\n    if (schedule->trigger.type == ESP_SCHEDULE_TYPE_RELATIVE) {\n        schedule->trigger.relative_seconds = schedule_config->trigger.relative_seconds;\n        schedule->trigger.next_scheduled_time_utc = schedule_config->trigger.next_scheduled_time_utc;\n    } else {\n        schedule->trigger.hours = schedule_config->trigger.hours;\n        schedule->trigger.minutes = schedule_config->trigger.minutes;\n\n        if (schedule->trigger.type == ESP_SCHEDULE_TYPE_DAYS_OF_WEEK) {\n            schedule->trigger.day.repeat_days = schedule_config->trigger.day.repeat_days;\n        } else if (schedule->trigger.type == ESP_SCHEDULE_TYPE_DATE) {\n            schedule->trigger.date.day = schedule_config->trigger.date.day;\n            schedule->trigger.date.repeat_months = schedule_config->trigger.date.repeat_months;\n            schedule->trigger.date.year = schedule_config->trigger.date.year;\n            schedule->trigger.date.repeat_every_year = schedule_config->trigger.date.repeat_every_year;\n#if CONFIG_ESP_SCHEDULE_ENABLE_DAYLIGHT\n        } else if (schedule->trigger.type == ESP_SCHEDULE_TYPE_SUNRISE || schedule->trigger.type == ESP_SCHEDULE_TYPE_SUNSET) {\n            schedule->trigger.solar.latitude = schedule_config->trigger.solar.latitude;\n            schedule->trigger.solar.longitude = schedule_config->trigger.solar.longitude;\n            schedule->trigger.solar.offset_minutes = schedule_config->trigger.solar.offset_minutes;\n            /* Copy day and date fields for unified solar schedule approach */\n            schedule->trigger.day.repeat_days = schedule_config->trigger.day.repeat_days;\n            schedule->trigger.date.day = schedule_config->trigger.date.day;\n            schedule->trigger.date.repeat_months = schedule_config->trigger.date.repeat_months;\n            schedule->trigger.date.year = schedule_config->trigger.date.year;\n            schedule->trigger.date.repeat_every_year = schedule_config->trigger.date.repeat_every_year;\n#endif\n        }\n    }\n\n    schedule->trigger_cb = schedule_config->trigger_cb;\n    schedule->timestamp_cb = schedule_config->timestamp_cb;\n    schedule->priv_data = schedule_config->priv_data;\n    schedule->validity = schedule_config->validity;\n    esp_schedule_nvs_add(schedule);\n    return ESP_OK;\n}\n\nesp_err_t esp_schedule_edit(esp_schedule_handle_t handle, esp_schedule_config_t *schedule_config)\n{\n    if (handle == NULL || schedule_config == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    esp_schedule_t *schedule = (esp_schedule_t *)handle;\n    if (strncmp(schedule->name, schedule_config->name, sizeof(schedule->name)) != 0) {\n        ESP_LOGE(TAG, \"Schedule name mismatch. Expected: %s, Passed: %s\", schedule->name, schedule_config->name);\n        return ESP_FAIL;\n    }\n\n    /* Editing a schedule with relative time should also reset it. */\n    if (schedule->trigger.type == ESP_SCHEDULE_TYPE_RELATIVE) {\n        schedule->trigger.next_scheduled_time_utc = 0;\n    }\n    esp_schedule_set(schedule, schedule_config);\n    ESP_LOGD(TAG, \"Schedule %s edited\", schedule->name);\n    return ESP_OK;\n}\n\nesp_err_t esp_schedule_delete(esp_schedule_handle_t handle)\n{\n    if (handle == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    esp_schedule_t *schedule = (esp_schedule_t *)handle;\n    ESP_LOGI(TAG, \"Deleting schedule %s\", schedule->name);\n    if (schedule->timer) {\n        esp_schedule_stop_timer(schedule);\n        esp_schedule_delete_timer(schedule);\n    }\n    esp_schedule_nvs_remove(schedule);\n    free(schedule);\n    return ESP_OK;\n}\n\nesp_schedule_handle_t esp_schedule_create(esp_schedule_config_t *schedule_config)\n{\n    if (schedule_config == NULL) {\n        return NULL;\n    }\n    if (strlen(schedule_config->name) <= 0) {\n        ESP_LOGE(TAG, \"Set schedule failed. Please enter a unique valid name for the schedule.\");\n        return NULL;\n    }\n\n    if (schedule_config->trigger.type == ESP_SCHEDULE_TYPE_INVALID) {\n        ESP_LOGE(TAG, \"Schedule type is invalid.\");\n        return NULL;\n    }\n\n    esp_schedule_t *schedule = (esp_schedule_t *)MEM_CALLOC_EXTRAM(1, sizeof(esp_schedule_t));\n    if (schedule == NULL) {\n        ESP_LOGE(TAG, \"Could not allocate handle\");\n        return NULL;\n    }\n    strlcpy(schedule->name, schedule_config->name, sizeof(schedule->name));\n\n    esp_schedule_set(schedule, schedule_config);\n\n    esp_schedule_create_timer(schedule);\n    ESP_LOGD(TAG, \"Schedule %s created\", schedule->name);\n    return (esp_schedule_handle_t)schedule;\n}\n\nesp_schedule_handle_t *esp_schedule_init(bool enable_nvs, char *nvs_partition, uint8_t *schedule_count)\n{\n    if (!esp_sntp_enabled()) {\n        ESP_LOGI(TAG, \"Initializing SNTP\");\n        esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);\n        esp_sntp_setservername(0, \"pool.ntp.org\");\n        esp_sntp_init();\n    }\n\n    if (!enable_nvs) {\n        return NULL;\n    }\n\n    /* Wait for time to be updated here */\n\n    /* Below this is initialising schedules from NVS */\n    esp_schedule_nvs_init(nvs_partition);\n\n    /* Get handle list from NVS */\n    esp_schedule_handle_t *handle_list = NULL;\n    *schedule_count = 0;\n    handle_list = esp_schedule_nvs_get_all(schedule_count);\n    if (handle_list == NULL) {\n        ESP_LOGI(TAG, \"No schedules found in NVS\");\n        return NULL;\n    }\n    ESP_LOGI(TAG, \"Schedules found in NVS: %\"PRIu8, *schedule_count);\n    /* Start/Delete the schedules */\n    esp_schedule_t *schedule = NULL;\n    for (size_t handle_count = 0; handle_count < *schedule_count; handle_count++) {\n        schedule = (esp_schedule_t *)handle_list[handle_count];\n        schedule->trigger_cb = NULL;\n        schedule->timer = NULL;\n        /* Check for ONCE and expired schedules and delete them. */\n        if (esp_schedule_is_expired(&schedule->trigger)) {\n            /* This schedule has already expired. */\n            ESP_LOGI(TAG, \"Schedule %s does not repeat and has already expired. Deleting it.\", schedule->name);\n            esp_schedule_delete((esp_schedule_handle_t)schedule);\n            /* Removing the schedule from the list */\n            handle_list[handle_count] = handle_list[*schedule_count - 1];\n            (*schedule_count)--;\n            handle_count--;\n            continue;\n        }\n        esp_schedule_create_timer(schedule);\n        esp_schedule_start_timer(schedule);\n    }\n    init_done = true;\n    return handle_list;\n}\n"
  },
  {
    "path": "esp_schedule/src/esp_schedule_internal.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/timers.h\"\n#include \"esp_schedule.h\"\n#include \"esp_heap_caps.h\"\n\n/** Memory allocation macros for external RAM */\n#if ((CONFIG_SPIRAM || CONFIG_SPIRAM_SUPPORT) && \\\n        (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC))\n#define MEM_ALLOC_EXTRAM(size)         heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT | MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL)\n#define MEM_CALLOC_EXTRAM(num, size)   heap_caps_calloc_prefer(num, size, 2, MALLOC_CAP_DEFAULT | MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL)\n#define MEM_REALLOC_EXTRAM(ptr, size)  heap_caps_realloc_prefer(ptr, size, 2, MALLOC_CAP_DEFAULT | MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL)\n#else\n#define MEM_ALLOC_EXTRAM(size)         malloc(size)\n#define MEM_CALLOC_EXTRAM(num, size)   calloc(num, size)\n#define MEM_REALLOC_EXTRAM(ptr, size)  realloc(ptr, size)\n#endif\n\ntypedef struct esp_schedule {\n    char name[MAX_SCHEDULE_NAME_LEN + 1];\n    esp_schedule_trigger_t trigger;\n    uint32_t next_scheduled_time_diff;\n    TimerHandle_t timer;\n    esp_schedule_trigger_cb_t trigger_cb;\n    esp_schedule_timestamp_cb_t timestamp_cb;\n    void *priv_data;\n    esp_schedule_validity_t validity;\n} esp_schedule_t;\n\nesp_err_t esp_schedule_nvs_add(esp_schedule_t *schedule);\nesp_err_t esp_schedule_nvs_remove(esp_schedule_t *schedule);\nesp_schedule_handle_t *esp_schedule_nvs_get_all(uint8_t *schedule_count);\nbool esp_schedule_nvs_is_enabled(void);\nesp_err_t esp_schedule_nvs_init(char *nvs_partition);\n"
  },
  {
    "path": "esp_schedule/src/esp_schedule_nvs.c",
    "content": "// Copyright 2025 Espressif Systems (Shanghai) CO LTD\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <string.h>\n#include <time.h>\n#include \"esp_log.h\"\n#include \"nvs.h\"\n#include \"esp_schedule_internal.h\"\n\nstatic const char *TAG = \"esp_schedule_nvs\";\n\n#define ESP_SCHEDULE_NVS_NAMESPACE \"schd\"\n#define ESP_SCHEDULE_COUNT_KEY \"schd_count\"\n\nstatic char *esp_schedule_nvs_partition = NULL;\nstatic bool nvs_enabled = false;\n\nesp_err_t esp_schedule_nvs_add(esp_schedule_t *schedule)\n{\n    if (!nvs_enabled) {\n        ESP_LOGD(TAG, \"NVS not enabled. Not adding to NVS.\");\n        return ESP_ERR_INVALID_STATE;\n    }\n    nvs_handle_t nvs_handle;\n    esp_err_t err = nvs_open_from_partition(esp_schedule_nvs_partition, ESP_SCHEDULE_NVS_NAMESPACE, NVS_READWRITE, &nvs_handle);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"NVS open failed with error %d\", err);\n        return err;\n    }\n\n    /* Check if this is new schedule or editing an existing schedule */\n    size_t buf_size;\n    bool editing_schedule = true;\n    err = nvs_get_blob(nvs_handle, schedule->name, NULL, &buf_size);\n    if (err != ESP_OK) {\n        if (err == ESP_ERR_NVS_NOT_FOUND) {\n            editing_schedule = false;\n        } else {\n            ESP_LOGE(TAG, \"NVS get failed with error %d\", err);\n            nvs_close(nvs_handle);\n            return err;\n        }\n    } else {\n        ESP_LOGI(TAG, \"Updating the existing schedule %s\", schedule->name);\n    }\n\n    err = nvs_set_blob(nvs_handle, schedule->name, schedule, sizeof(esp_schedule_t));\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"NVS set failed with error %d\", err);\n        nvs_close(nvs_handle);\n        return err;\n    }\n    if (editing_schedule == false) {\n        uint8_t schedule_count;\n        err = nvs_get_u8(nvs_handle, ESP_SCHEDULE_COUNT_KEY, &schedule_count);\n        if (err != ESP_OK) {\n            if (err == ESP_ERR_NVS_NOT_FOUND) {\n                schedule_count = 0;\n            } else {\n                ESP_LOGE(TAG, \"NVS get failed with error %d\", err);\n                nvs_close(nvs_handle);\n                return err;\n            }\n        }\n        schedule_count++;\n        err = nvs_set_u8(nvs_handle, ESP_SCHEDULE_COUNT_KEY, schedule_count);\n        if (err != ESP_OK) {\n            ESP_LOGE(TAG, \"NVS set failed for schedule count with error %d\", err);\n            nvs_close(nvs_handle);\n            return err;\n        }\n    }\n    nvs_commit(nvs_handle);\n    nvs_close(nvs_handle);\n    ESP_LOGI(TAG, \"Schedule %s added in NVS\", schedule->name);\n    return ESP_OK;\n}\n\nesp_err_t esp_schedule_nvs_remove_all(void)\n{\n    if (!nvs_enabled) {\n        ESP_LOGD(TAG, \"NVS not enabled. Not removing from NVS.\");\n        return ESP_ERR_INVALID_STATE;\n    }\n    nvs_handle_t nvs_handle;\n    esp_err_t err = nvs_open_from_partition(esp_schedule_nvs_partition, ESP_SCHEDULE_NVS_NAMESPACE, NVS_READWRITE, &nvs_handle);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"NVS open failed with error %d\", err);\n        return err;\n    }\n    err = nvs_erase_all(nvs_handle);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"NVS erase all keys failed with error %d\", err);\n        nvs_close(nvs_handle);\n        return err;\n    }\n    nvs_commit(nvs_handle);\n    nvs_close(nvs_handle);\n    ESP_LOGI(TAG, \"All schedules removed from NVS\");\n    return ESP_OK;\n}\n\nesp_err_t esp_schedule_nvs_remove(esp_schedule_t *schedule)\n{\n    if (!nvs_enabled) {\n        ESP_LOGD(TAG, \"NVS not enabled. Not removing from NVS.\");\n        return ESP_ERR_INVALID_STATE;\n    }\n    nvs_handle_t nvs_handle;\n    esp_err_t err = nvs_open_from_partition(esp_schedule_nvs_partition, ESP_SCHEDULE_NVS_NAMESPACE, NVS_READWRITE, &nvs_handle);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"NVS open failed with error %d\", err);\n        return err;\n    }\n    err = nvs_erase_key(nvs_handle, schedule->name);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"NVS erase key failed with error %d\", err);\n        nvs_close(nvs_handle);\n        return err;\n    }\n    uint8_t schedule_count;\n    err = nvs_get_u8(nvs_handle, ESP_SCHEDULE_COUNT_KEY, &schedule_count);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"NVS get failed for schedule count with error %d\", err);\n        nvs_close(nvs_handle);\n        return err;\n    }\n    schedule_count--;\n    err = nvs_set_u8(nvs_handle, ESP_SCHEDULE_COUNT_KEY, schedule_count);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"NVS set failed for schedule count with error %d\", err);\n        nvs_close(nvs_handle);\n        return err;\n    }\n    nvs_commit(nvs_handle);\n    nvs_close(nvs_handle);\n    ESP_LOGI(TAG, \"Schedule %s removed from NVS\", schedule->name);\n    return ESP_OK;\n}\n\nstatic uint8_t esp_schedule_nvs_get_count(void)\n{\n    if (!nvs_enabled) {\n        ESP_LOGD(TAG, \"NVS not enabled. Not getting count from NVS.\");\n        return 0;\n    }\n    nvs_handle_t nvs_handle;\n    esp_err_t err = nvs_open_from_partition(esp_schedule_nvs_partition, ESP_SCHEDULE_NVS_NAMESPACE, NVS_READONLY, &nvs_handle);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"NVS open failed with error %d\", err);\n        return 0;\n    }\n    uint8_t schedule_count;\n    err = nvs_get_u8(nvs_handle, ESP_SCHEDULE_COUNT_KEY, &schedule_count);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"NVS get failed for schedule count with error %d\", err);\n        nvs_close(nvs_handle);\n        return 0;\n    }\n    nvs_close(nvs_handle);\n    ESP_LOGI(TAG, \"Schedules in NVS: %d\", schedule_count);\n    return schedule_count;\n}\n\nstatic esp_schedule_handle_t esp_schedule_nvs_get(char *nvs_key)\n{\n    if (!nvs_enabled) {\n        ESP_LOGD(TAG, \"NVS not enabled. Not getting from NVS.\");\n        return NULL;\n    }\n    size_t buf_size;\n    nvs_handle_t nvs_handle;\n    esp_err_t err = nvs_open_from_partition(esp_schedule_nvs_partition, ESP_SCHEDULE_NVS_NAMESPACE, NVS_READONLY, &nvs_handle);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"NVS open failed with error %d\", err);\n        return NULL;\n    }\n    err = nvs_get_blob(nvs_handle, nvs_key, NULL, &buf_size);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"NVS get failed with error %d\", err);\n        nvs_close(nvs_handle);\n        return NULL;\n    }\n    esp_schedule_t *schedule = (esp_schedule_t *)malloc(buf_size);\n    if (schedule == NULL) {\n        ESP_LOGE(TAG, \"Could not allocate handle\");\n        nvs_close(nvs_handle);\n        return NULL;\n    }\n    err = nvs_get_blob(nvs_handle, nvs_key, schedule, &buf_size);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"NVS get failed with error %d\", err);\n        nvs_close(nvs_handle);\n        free(schedule);\n        return NULL;\n    }\n    nvs_close(nvs_handle);\n    ESP_LOGI(TAG, \"Schedule %s found in NVS\", schedule->name);\n    return (esp_schedule_handle_t) schedule;\n}\n\nesp_schedule_handle_t *esp_schedule_nvs_get_all(uint8_t *schedule_count)\n{\n    if (!nvs_enabled) {\n        ESP_LOGD(TAG, \"NVS not enabled. Not Initialising NVS.\");\n        return NULL;\n    }\n\n    *schedule_count = esp_schedule_nvs_get_count();\n    if (*schedule_count == 0) {\n        ESP_LOGI(TAG, \"No Entries found in NVS\");\n        return NULL;\n    }\n    esp_schedule_handle_t *handle_list = (esp_schedule_handle_t *)malloc(sizeof(esp_schedule_handle_t) * (*schedule_count));\n    if (handle_list == NULL) {\n        ESP_LOGE(TAG, \"Could not allocate schedule list\");\n        *schedule_count = 0;\n        return NULL;\n    }\n    int handle_count = 0;\n\n    nvs_entry_info_t nvs_entry;\n    nvs_iterator_t nvs_iterator = NULL;\n    esp_err_t err = nvs_entry_find(esp_schedule_nvs_partition, ESP_SCHEDULE_NVS_NAMESPACE, NVS_TYPE_BLOB, &nvs_iterator);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"No entry found in NVS\");\n        free(handle_list);\n        return NULL;\n    }\n    while (err == ESP_OK) {\n        nvs_entry_info(nvs_iterator, &nvs_entry);\n        ESP_LOGI(TAG, \"Found schedule in NVS with key: %s\", nvs_entry.key);\n        handle_list[handle_count] = esp_schedule_nvs_get(nvs_entry.key);\n        if (handle_list[handle_count] != NULL) {\n            /* Increase count only if nvs_get was successful */\n            handle_count++;\n        }\n        err = nvs_entry_next(&nvs_iterator);\n    }\n    nvs_release_iterator(nvs_iterator);\n    *schedule_count = handle_count;\n    ESP_LOGI(TAG, \"Found %d schedules in NVS\", *schedule_count);\n    return handle_list;\n}\n\nbool esp_schedule_nvs_is_enabled(void)\n{\n    return nvs_enabled;\n}\n\nesp_err_t esp_schedule_nvs_init(char *nvs_partition)\n{\n    if (nvs_enabled) {\n        ESP_LOGI(TAG, \"NVS already enabled\");\n        return ESP_OK;\n    }\n    if (nvs_partition) {\n        esp_schedule_nvs_partition = strndup(nvs_partition, strlen(nvs_partition));\n    } else {\n        esp_schedule_nvs_partition = strndup(\"nvs\", strlen(\"nvs\"));\n    }\n    if (esp_schedule_nvs_partition == NULL) {\n        ESP_LOGE(TAG, \"Could not allocate nvs_partition\");\n        return ESP_ERR_NO_MEM;\n    }\n    nvs_enabled = true;\n    return ESP_OK;\n}\n"
  },
  {
    "path": "esp_serial_slave_link/.build-test-rules.yml",
    "content": ""
  },
  {
    "path": "esp_serial_slave_link/CHANGELOG.md",
    "content": "## 1.1.1\n\n- Clean up the component dependency, don't depend on the `driver` component directly\n\n## 1.1.0\n\n- Supported communicating with ESP32C6 SDIO Slave\n\n## 1.0.1\n\n- Fixed build failure issue on chip which doesn't support SDMMC host\n- Remove dependency to `soc/host_reg.h`\n\n## 1.0.0\n\n- Initial version\n"
  },
  {
    "path": "esp_serial_slave_link/CMakeLists.txt",
    "content": "set(public_requires \"sdmmc\")\n\nif(\"${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}\" VERSION_GREATER_EQUAL \"5.3\")\n    list(APPEND public_requires \"esp_driver_sdspi\" \"esp_driver_sdmmc\")\nelse()\n    list(APPEND public_requires \"driver\")\nendif()\n\nidf_component_register(SRCS \"essl.c\"\n                \"essl_sdio.c\"\n                \"essl_spi.c\"\n                \"essl_sdio_defs.c\"\n            INCLUDE_DIRS \"include\"\n            REQUIRES ${public_requires}\n            PRIV_INCLUDE_DIRS \".\"\n                \"include/esp_serial_slave_link\"\n)\n"
  },
  {
    "path": "esp_serial_slave_link/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "esp_serial_slave_link/README.md",
    "content": "# Espressif Serial Slave Link (ESSL) Library\n\n[![Component Registry](https://components.espressif.com/components/espressif/esp_serial_slave_link/badge.svg)](https://components.espressif.com/components/espressif/esp_serial_slave_link)\n\nIt's used on the HOST, to communicate with ESP chips as SLAVE via SDIO or SPI slave HD mode.\n\n## Documentation\n\nFor detailed information about the Espressif Serial Slave Link component, including API reference and user guides, please visit:\n\n-   **Programming Guide & API Reference**: [Espressif Serial Slave Link Documentation](https://espressif.github.io/idf-extra-components/latest/esp_serial_slave_link/index.html)\n"
  },
  {
    "path": "esp_serial_slave_link/docs/Doxyfile",
    "content": "# Set this to the header file you want\nINPUT = ../include/esp_serial_slave_link/\n\n# The output directory for the generated XML documentation\nOUTPUT_DIRECTORY = doxygen_output\n\n# Warning-related settings, it's recommended to keep them enabled\nWARN_IF_UNDOC_ENUM_VAL = YES\nWARN_AS_ERROR = YES\n\n# Other common settings\nFULL_PATH_NAMES = YES\nSTRIP_FROM_PATH = ../\nSTRIP_FROM_INC_PATH = ../\nENABLE_PREPROCESSING   = YES\nMACRO_EXPANSION        = YES\nOPTIMIZE_OUTPUT_FOR_C  = YES\nEXPAND_ONLY_PREDEF     = YES\nEXTRACT_ALL            = YES\nPREDEFINED             = $(ENV_DOXYGEN_DEFINES)\nHAVE_DOT = NO\nGENERATE_XML    = YES\nXML_OUTPUT      = xml\nGENERATE_HTML   = NO\nHAVE_DOT        = NO\nGENERATE_LATEX  = NO\nQUIET = YES\nMARKDOWN_SUPPORT = YES\n"
  },
  {
    "path": "esp_serial_slave_link/docs/book.toml",
    "content": "[book]\ntitle = \"ESP Serial Slave Link Documentation\"\nlanguage = \"en\"\n\n[output.html]\ndefault-theme = \"light\"\ngit-repository-url = \"https://github.com/espressif/idf-extra-components/tree/master/esp_serial_slave_link\"\nedit-url-template = \"https://github.com/espressif/idf-extra-components/edit/master/esp_serial_slave_link/docs/{path}\"\n"
  },
  {
    "path": "esp_serial_slave_link/docs/src/SUMMARY.md",
    "content": "# Summary\n\n---\n\n# Programming Guide\n\n-   [ESP Serial Slave Link](index.md)\n    -   [SDIO Slave Protocol](sdio_slave_protocol.md)\n    -   [SPI Slave HD Protocol](spi_slave_hd_protocol.md)\n\n---\n\n# API Reference\n\n-   [API Reference](api.md)\n"
  },
  {
    "path": "esp_serial_slave_link/docs/src/api.md",
    "content": "# API Reference\n\n<div class=\"warning\">\n\nThis file is automatically generated by esp-doxybook.\n\nDO NOT edit it manually.\n\n</div>\n"
  },
  {
    "path": "esp_serial_slave_link/docs/src/index.md",
    "content": "# ESP Serial Slave Link\n\n## Overview\n\nEspressif provides several chips that can work as slaves. These slave devices rely on some common buses, and have their own communication protocols over those buses. The `esp_serial_slave_link` component is designed for the **master** to communicate with ESP slave devices through those protocols over the bus drivers, although the name of the component implies it a `slave link`.\n\nAfter a slave device is initialized properly, the application can use it to communicate with the slave devices conveniently, as long as the slave complies with the protocols. The component provides a set of APIs to operate the slave device, including sending and receiving data, triggering interrupts, etc.\n\n## Terminology\n\n-   ESSL: Abbreviation for ESP Serial Slave Link, the component described by this document.\n-   Master: The device running the `esp_serial_slave_link` component.\n-   ESSL Device: A virtual device on the master associated with an ESP slave device. The device context has the knowledge of the slave protocol above the bus, relying on some bus drivers to communicate with the slave.\n-   ESSL Device Handle: a handle to ESSL device context containing the configuration, status and data required by the ESSL component. The context stores the driver configurations, communication state, data shared by master and slave, etc.\n\n    -   The context should be initialized before it is used, and get de-initialized if not used any more. The master application operates on the ESSL device through this handle.\n\n-   ESP Slave: the slave device connected to the bus, which ESSL component is designed to communicate with.\n-   Bus: The bus over which the master and the slave communicate with each other.\n-   Slave Protocol: The special communication protocol specified by Espressif HW/SW over the bus.\n-   TX Buffer Num: a counter, which is on the slave and can be read by the master, indicates the accumulated buffer numbers that the slave has loaded to the hardware to receive data from the master.\n-   RX Data Size: a counter, which is on the slave and can be read by the master, indicates the accumulated data size that the slave has loaded to the hardware to send to the master.\n\n## About the Slave Communication Protocols\n\nFor more details about the device communication protocols, please refer to the following documents:\n\n-   [SDIO Slave Protocol](sdio_slave_protocol.md)\n-   [SPI Slave Half Duplex Protocol](spi_slave_hd_protocol.md)\n\n## Services Provided by ESP Slave\n\nThere are some common services provided by the Espressif slaves:\n\n1.  Tohost Interrupts: The slave can inform the master about certain events by the interrupt line. (optional)\n2.  Frhost Interrupts: The master can inform the slave about certain events.\n3.  TX FIFO (master to slave): The slave can receive data from the master in units of receiving buffers. The slave updates the TX buffer num to inform the master how much data it can receive, and the master then read the TX buffer num, and take off the used buffer number to know how many buffers are remaining.\n4.  RX FIFO (slave to master): The slave can send data in stream to the master. The SDIO slave can also indicate it has new data to send to master by the interrupt line. The slave updates the RX data size to inform the master how much data it has prepared to send, and then the master read the data size, and take off the data length it has already received to know how many data is remaining.\n5.  Shared registers: The master can read some part of the registers on the slave, and also write these registers to let the slave read.\n\n## Initialization of ESP Serial Slave Link\n\n### ESP SDIO Slave\n\nThe ESP SDIO slave link (ESSL SDIO) devices relies on the SDMMC component. It includes the usage of communicating with ESP SDIO Slave device via the SDMMC Host or SDSPI Host feature. The ESSL device should be initialized as follows:\n\n1.  Initialize a SDMMC card (see [Document of SDMMC driver](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/storage/sdmmc.html)) structure.\n2.  Call `sdmmc_card_init` to initialize the card.\n3.  Initialize the ESSL device with `essl_sdio_config_t`. The `card` member should be the `sdmmc_card_t` got in step 2, and the `recv_buffer_size` member should be filled correctly according to pre-negotiated value.\n4.  Call [essl_init](api.md#function-essl_init) to do initialization of the SDIO part.\n5.  Call [essl_wait_for_ready](api.md#function-essl_wait_for_ready) to wait for the slave to be ready.\n\n<div class=\"warning\">\n\nIf you are communicating with the ESP SDIO Slave device through SPI interface, you should still choose this **SDIO interface**.\n\n</div>\n\n### ESP SPI Slave\n\nHas not been supported yet.\n\n## Typical Usage of ESP Serial Slave Link\n\nAfter the initialization process above is performed, you can call the APIs below to make use of the services provided by the slave:\n\n### Tohost Interrupts (Optional)\n\n1.  Call [essl_get_intr_ena](api.md#function-essl_get_intr_ena) to know which events will trigger the interrupts to the master.\n2.  Call [essl_set_intr_ena](api.md#function-essl_set_intr_ena) to set the events that should trigger interrupts to the master.\n3.  Call [essl_wait_int](api.md#function-essl_wait_int) to wait until interrupt from the slave, or timeout.\n4.  When interrupt is triggered, call [essl_get_intr](api.md#function-essl_get_intr) to know which events are active, and call [essl_clear_intr](api.md#function-essl_clear_intr) to clear them.\n\n### Frhost Interrupts\n\n1.  Call [essl_send_slave_intr](api.md#function-essl_send_slave_intr) to trigger general purpose interrupt of the slave.\n\n### TX FIFO\n\n1.  Call [essl_get_tx_buffer_num](api.md#function-essl_get_tx_buffer_num) to know how many buffers the slave has prepared to receive data from the master. This is optional. The master will poll `tx_buffer_num` when it tries to send packets to the slave, until the slave has enough buffer or timeout.\n2.  Call [essl_send_packet](api.md#function-essl_send_packet) to send data to the slave.\n\n### RX FIFO\n\n1.  Call [essl_get_rx_data_size](api.md#function-essl_get_rx_data_size) to know how many data the slave has prepared to send to the master. This is optional. When the master tries to receive data from the slave, it updates the `rx_data_size` for once, if the current `rx_data_size` is shorter than the buffer size the master prepared to receive. And it may poll the `rx_data_size` if the `rx_data_size` keeps 0, until timeout.\n2.  Call [essl_get_packet](api.md#function-essl_get_packet) to receive data from the slave.\n\n### Reset Counters (Optional)\n\nCall [essl_reset_cnt](api.md#function-essl_reset_cnt) to reset the internal counter if you find the slave has reset its counter.\n"
  },
  {
    "path": "esp_serial_slave_link/docs/src/sdio_slave_protocol.md",
    "content": "# SDIO Slave Protocol\n\nThis document describes the process of initialization of an ESP SDIO Slave device and then provides details on the ESP SDIO Slave protocol - a non-standard protocol that allows an SDIO Host to communicate with an ESP SDIO slave.\n\nThe ESP SDIO Slave protocol was created to implement the communication between SDIO host and slave, because the SDIO specification only shows how to access the custom region of a card (by sending CMD52 and CMD53 to functions 1-7) without any details regarding the underlying hardware implementation.\n\n## SDIO Slave Capabilities of Espressif Chips\n\nThe services provided by the SDIO Slave peripheral of the\n{IDF_TARGET_NAME} chip are listed in the table below:\n\n| ESP Target Chip | Tohost intr | Frhost intr | TX DMA | RX DMA | Shared registers |\n| --------------- | ----------- | ----------- | ------ | ------ | ---------------- |\n| ESP32           | 8           | 8           | Y      | Y      | 56\\*             |\n| ESP32-C5        | 8           | 8           | Y      | Y      | 56\\*             |\n| ESP32-C6        | 8           | 8           | Y      | Y      | 56\\*             |\n\n\\* Not including the interrupt registers\n\n## ESP SDIO Slave Initialization\n\nThe host should initialize the SDIO slave according to the standard SDIO initialization process (Section 3.1.2 of [SDIO Simplified Specification](https://www.sdcard.org/downloads/pls/)). In this specification as well as below, the SDIO slave is called an SDIO/IO card. Here is a brief example of an ESP SDIO Slave initialization process:\n\n1.  SDIO reset\n    > CMD52 (Write 0x6 = 0x8)\n2.  SD reset\n    > CMD0\n3.  Check whether IO card (optional)\n    > CMD8\n4.  Send SDIO op cond and wait for card ready\n    > CMD5 arg = 0x00000000\n    >\n    > CMD5 arg = 0x00ff8000 (according to the response above, poll until ready)\n    >\n    > **Example:**\n    >\n    > > Arg of R4 after first CMD5 (arg = 0x00000000) is 0xXXFFFF00.\n    > >\n    > > Keep sending CMD5 with arg = 0x00FFFF00 until the R4 shows card ready (arg bit 31 = 1).\n5.  Set address\n    > CMD3\n6.  Select card\n    > CMD7 (arg address according to CMD3 response)\n    >\n    > **Example:**\n    >\n    > > Arg of R6 after CMD3 is 0x0001xxxx.\n    > >\n    > > Arg of CMD7 should be 0x00010000.\n7.  Select 4-bit mode (optional)\n    > CMD52 (Write 0x07 = 0x02)\n8.  Enable func1\n    > CMD52 (Write 0x02 = 0x02)\n9.  Enable SDIO interrupt (required if interrupt line (DAT1) is used)\n    > CMD52 (Write 0x04 = 0x03)\n10. Set Func0 block size (optional, default value is 512 (0x200))\n    > CMD52/53 (Read 0x10 ~ 0x11)\n    >\n    > CMD52/53 (Write 0x10 = 0x00)\n    >\n    > CMD52/53 (Write 0x11 = 0x02)\n    >\n    > CMD52/53 (Read 0x10 ~ 0x11, read to check the final value)\n11. Set Func1 block size (optional, default value is 512 (0x200))\n    > CMD52/53 (Read 0x110 ~ 0x111)\n    >\n    > CMD52/53 (Write 0x110 = 0x00)\n    >\n    > CMD52/53 (Write 0x111 = 0x02)\n    >\n    > CMD52/53 (Read 0x110 ~ 0x111, read to check the final value)\n\n## ESP SDIO Slave Protocol\n\nThe ESP SDIO Slave protocol is based on the SDIO Specification's I/O Read/Write commands, i.e., CMD52 and CMD53. The protocol offers the following services:\n\n-   Sending FIFO and receiving FIFO\n-   52 8-bit R/W registers shared by host and slave. For details, see `Technical Reference Manual > SDIO Slave Controller > Register Summary > SDIO SLC Host registers`.\n-   16 general purpose interrupt sources, 8 from host to slave and 8 from slave to host.\n\nTo begin communication, the host needs to enable the I/O Function 1 in the slave and access its registers as described below.\n\nThe `esp_serial_slave_link` component implements the logic of this protocol for ESP32 SDIO Host when communicating with an ESP32 SDIO slave.\n\n### Slave Register Table\n\n#### 32-bit\n\n-   0x044 (TOKEN_RDATA): in which bit 27-16 holds the number of the receiving buffer.\n-   0x058 (INT_ST): holds the interrupt source bits from slave to host.\n-   0x060 (PKT_LEN): holds the accumulated data length (in bytes) already read by host plus the data copied to the buffer but yet to be read.\n-   0x0D4 (INT_CLR): write 1 to clear interrupt bits corresponding to INT_ST.\n-   0x0DC (INT_ENA): mask bits for interrupts from slave to host.\n\n#### 8-bit\n\nShared general purpose registers:\n\n-   0x06C-0x077: R/W registers 0-11 shared by slave and host.\n-   0x07A-0x07B: R/W registers 14-15 shared by slave and host.\n-   0x07E-0x07F: R/W registers 18-19 shared by slave and host.\n-   0x088-0x08B: R/W registers 24-27 shared by slave and host.\n-   0x09C-0x0BB: R/W registers 32-63 shared by slave and host.\n\nInterrupt Registers:\n\n-   0x08D (SLAVE_INT): bits for host to interrupt slave. auto clear.\n\n#### FIFO (Sending and Receiving)\n\n0x090 - 0x1F7FF are reserved for FIFOs.\n\nThe address of CMD53 is related to the length requested to read from or write to the slave in a single transfer, as demonstrated by the equation below:\n\n_requested length = 0x1F800 - address_\n\nThe slave responds to data that has a length equal to the length field of CMD53. In cases where the data is longer than the **requested length**, the data will be zero filled (when sending) or discarded (when receiving). This includes both the block and the byte mode of CMD53.\n\n<div class=\"warning\">\nThe function number should be set to 1, and OP Code should be set to 1 (for CMD53).\n\nIn order to achieve higher efficiency when accessing the FIFO by an arbitrary length, the block and byte modes of CMD53 can be used in combination. For example, given that the block size is set to 512 by default, you can write or get 1031 bytes of data from the FIFO by doing the following:\n\n1.  Send CMD53 in block mode, block count = 2 (1024 bytes) to address 0x1F3F9 = 0x1F800 - **1031**.\n2.  Then send CMD53 in byte mode, byte count = 8 (or 7 if your controller supports that) to address 0x1F7F9 = 0x1F800 - **7**.\n</div>\n\n### Interrupts\n\nSDIO interrupts are \"level sensitive\". For host interrupts, the slave sends an interrupt by pulling the DAT1 line down at a proper time. The host detects when the interrupt line is pulled down and reads the `INT_ST` register to determine the source of the interrupt. After that, the host can clear the interrupt bits by writing the `INT_CLR` register and process the interrupt. The host can also mask unneeded sources by clearing the bits in the `INT_ENA` register corresponding to the sources. If all the sources are cleared (or masked), the DAT1 line goes inactive.\n\nOn ESP32, the corresponding `host_int` bits are: bit 0 to bit 7.\n\nFor slave interrupts, the host sends a transfer to write the `SLAVE_INT` register. Once a bit is set to 1, the slave hardware and the driver will detect it and inform the application.\n\n### Receiving FIFO\n\nTo write to the slave's receiving FIFO, the host should complete the following steps:\n\n1.  **Read the TOKEN1 field (bits 27-16) of the register TOKEN_RDATA (0x044)**. The buffer number remaining is TOKEN1 minus the number of buffers used by host.\n2.  **Make sure the buffer number is sufficient** (_buffer_size_ x _buffer_num_ is greater than the data to write, _buffer_size_ is pre-defined between the host and the slave before the communication starts). Otherwise, keep returning to step 1 until the buffer size is sufficient.\n3.  **Write to the FIFO address with CMD53**. Note that the _requested length_ should not exceed the length calculated at step 2, and the FIFO address is related to _requested length_.\n4.  **Calculate used buffers**. Note that a partially-used buffer at the tail is counted as used.\n\n### Sending FIFO\n\nTo read the slave's sending FIFO, the host should complete the following steps:\n\n1.  **Wait for the interrupt line to become active** (optional, low by default).\n2.  **Read (poll) the interrupt bits in the INT_ST register** to monitor if new packets exist.\n3.  **If new packets are ready, read the PKT_LEN register**. Before reading the packets, determine the length of data to be read. As the host keeps the length of data already read from the slave, subtract this value from `PKT_LEN`, the result will be the maximum length of data available for reading. If no data has been added to the sending FIFO yet, wait and poll until the slave is ready and update `PKT_LEN`.\n4.  **Read from the FIFO using CMD53**. Note that the **requested length** should not be greater than calculated at Step 3, and the FIFO address is related to **requested length**.\n5.  **Update the read length**.\n"
  },
  {
    "path": "esp_serial_slave_link/docs/src/spi_slave_hd_protocol.md",
    "content": "# SPI Slave HD (Half Duplex) Protocol\n\n<div class=\"warning\">\n\nESP32 does not support this feature.\n\n</div>\n\n## SPI Slave Capabilities of Espressif Chips\n\n| ESP Target Chip | Tohost intr | Frhost intr | TX DMA | RX DMA | Shared registers |\n| --------------- | :---------: | :---------: | :----: | :----: | :--------------: |\n| ESP32-S2        |      N      |      2      |   Y    |   Y    |        72        |\n| ESP32-C3        |      N      |      2      |   Y    |   Y    |        64        |\n| ESP32-S3        |      N      |      2      |   Y    |   Y    |        64        |\n| ESP32-C2        |      N      |      2      |   Y    |   Y    |        64        |\n| ESP32-C6        |      N      |      2      |   Y    |   Y    |        64        |\n| ESP32-H2        |      N      |      2      |   Y    |   Y    |        64        |\n| ESP32-P4        |      N      |      2      |   Y    |   Y    |        64        |\n| ESP32-C5        |      N      |      2      |   Y    |   Y    |        64        |\n| ESP32-C61       |      N      |      2      |   Y    |   Y    |        64        |\n| ESP32-H21       |      N      |      2      |   Y    |   Y    |        64        |\n\n## Introduction\n\nIn the half duplex mode, the master has to use the protocol defined by the slave to communicate with the slave. Each transaction may consist of the following phases (listed by the order they should exist):\n\n-   Command: 8-bit, master to slave\n    > This phase determines the rest phases of the transactions. See [the supported commands](#supported-commands).\n-   Address: 8-bit, master to slave, optional\n    > For some commands (`WRBUF`, `RDBUF`), this phase specifies the address of the shared register to write to/read from.\n    >\n    > For other commands with this phase, they are meaningless but still have to exist in the transaction.\n-   Dummy: 8-bit floating, optional\n    > This phase is the turnaround time between the master and the slave on the bus, and also provides enough time for the slave to prepare the data to send to the master.\n-   Data: variable length, the direction is also determined by the command.\n    > This may be a data `OUT` phase, in which the direction is slave to master, or a data `IN` phase, in which the direction is master to slave.\n\nThe **direction** means which side (master or slave) controls the MOSI, MISO, WP, and HD pins.\n\n## Data IO Modes\n\nIn some IO modes, more data wires can be used to send the data. As a result, the SPI clock cycles required for the same amount of data will be less than in the 1-bit mode. For example, in QIO mode, address and data (IN and OUT) should be sent on all 4 data wires (MOSI, MISO, WP, and HD). Here are the modes supported by the ESP32-S2 SPI slave and the wire number (WN) used in corresponding modes.\n\n| Mode  | Command WN | Address WN | Dummy cycles | Data WN |\n| ----- | ---------- | ---------- | ------------ | ------- |\n| 1-bit | 1          | 1          | 1            | 1       |\n| DOUT  | 1          | 1          | 4            | 2       |\n| DIO   | 1          | 2          | 4            | 2       |\n| QOUT  | 1          | 1          | 4            | 4       |\n| QIO   | 1          | 4          | 4            | 4       |\n| QPI   | 4          | 4          | 4            | 4       |\n\nNormally, which mode is used is determined by the command sent by the master (See [the Supported Commands](#supported-commands)), except the QPI mode.\n\n### QPI Mode\n\nThe QPI mode is a special state of the SPI Slave. The master can send the `ENQPI` command to put the slave into the QPI mode state. In the QPI mode, the command is also sent in 4-bit, thus it is not compatible with the normal modes. The master should only send QPI commands when the slave is in QPI mode. To exit from the QPI mode, master can send the EXQPI command.\n\n## Supported Commands\n\n<div class=\"warning\">\nThe command name is in a master-oriented direction. For example, WRBUF means master writes the buffer of slave.\n</div>\n\n| Name     | Description         | Command | Address  | Data                                                     |\n| -------- | ------------------- | ------- | -------- | -------------------------------------------------------- |\n| WRBUF    | Write buffer        | 0x01    | Buf addr | master to slave, no longer than buffer size              |\n| RDBUF    | Read buffer         | 0x02    | Buf addr | slave to master, no longer than buffer size              |\n| WRDMA    | Write DMA           | 0x03    | 8 bits   | master to slave, no longer than length provided by slave |\n| RDDMA    | Read DMA            | 0x04    | 8 bits   | slave to master, no longer than length provided by slave |\n| SEG_DONE | Segments done       | 0x05    |          |                                                          |\n| ENQPI    | Enter QPI mode      | 0x06    |          |                                                          |\n| WR_DONE  | Write segments done | 0x07    |          |                                                          |\n| CMD8     | Interrupt           | 0x08    |          |                                                          |\n| CMD9     | Interrupt           | 0x09    |          |                                                          |\n| CMDA     | Interrupt           | 0x0A    |          |                                                          |\n| EXQPI    | Exit QPI mode       | 0xDD    |          |                                                          |\n\nMoreover, `WRBUF`, `RDBUF`, `WRDMA`, and `RDDMA` commands have their 2-bit and 4-bit version. To do transactions in 2-bit or 4-bit mode, send the original command ORed by the corresponding command mask below. For example, command 0xA1 means WRBUF in QIO mode.\n\n| Mode  | Mask |\n| ----- | ---- |\n| 1-bit | 0x00 |\n| DOUT  | 0x10 |\n| DIO   | 0x50 |\n| QOUT  | 0x20 |\n| QIO   | 0xA0 |\n| QPI   | 0xA0 |\n\n## Segment Transaction Mode\n\nSegment transaction mode is the only mode supported by the SPI Slave HD driver for now. In this mode, for a transaction the slave loads onto the DMA, the master is allowed to read or write in segments. In this way, the master does not have to prepare a large buffer as the size of data provided by the slave. After the master finishes reading/writing a buffer, it has to send the corresponding termination command to the slave as a synchronization signal. The slave driver will update new data (if exist) onto the DMA upon seeing the termination command.\n\nThe termination command is `WR_DONE` (0x07) for `WRDMA` and `CMD8` (0x08) for `RDDMA`.\n\nHere is an example for the flow the master read data from the slave DMA:\n\n1.  The slave loads 4092 bytes of data onto the RDDMA.\n2.  The master do seven `RDDMA` transactions, each of them is 512 bytes long, and reads the first 3584 bytes from the slave.\n3.  The master do the last `RDDMA` transaction of 512 bytes (equal, longer, or shorter than the total length loaded by the slave are all allowed). The first 508 bytes are valid data from the slave, while the last 4 bytes are meaningless bytes.\n4.  The master sends `CMD8` to the slave.\n5.  The slave loads another 4092 bytes of data onto the RDDMA.\n6.  The master can start new reading transactions after it sends the `CMD8`.\n"
  },
  {
    "path": "esp_serial_slave_link/essl.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"esp_log.h\"\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n\n#include \"essl.h\"\n#include \"essl_internal.h\"\n\n#define TIME_EXPIRED_SINCE_CORE(start, end, timeout, max) (bool)((end)>=(start)? \\\n         ((end)-(start)>(timeout)) :\\\n        ((max)-(timeout)>(start)-(end)))\n\n#define TIME_EXPIRED_SINCE(start, end, timeout) TIME_EXPIRED_SINCE_CORE(start, end, timeout, UINT32_MAX)\n\n#define MINUS_UNTIL_ZERO(a, b) ( ((a) > (b)) ? ((a)-(b)): 0)\n\n#define TIME_REMAIN_CORE(start, end, timeout, max) ((end)>=(start)?\\\n        MINUS_UNTIL_ZERO(timeout, (end)-(start)):\\\n        MINUS_UNTIL_ZERO((start)-(end), (max)-(timeout)))\n\n#define TIME_REMAIN(start, end, timeout)    TIME_REMAIN_CORE(start, end, timeout, UINT32_MAX)\n\n\n#define ESSL_MIN(a, b)   ((a) < (b) ? (a) : (b))\n\n__attribute__((unused)) static const char TAG[] = \"esp_serial_slave_link\";\n\n#define _CHECK_EXECUTE_CMD(DEV, CMD, STR, ...) do{ \\\n    if ((DEV) == NULL) { \\\n        return ESP_ERR_INVALID_ARG; \\\n    } \\\n    if ((DEV)->CMD) { \\\n        return (DEV)->CMD((DEV)->args,##__VA_ARGS__); \\\n    } else { \\\n        ESP_LOGE(TAG, STR); \\\n        return ESP_ERR_NOT_SUPPORTED; \\\n    } } while(0)\n\n#define CHECK_EXECUTE_CMD(DEV, CMD, ...) _CHECK_EXECUTE_CMD(DEV, CMD, #CMD\" not supported for the current device.\",##__VA_ARGS__)\n\n\nesp_err_t essl_init(essl_handle_t handle, uint32_t wait_ms)\n{\n    CHECK_EXECUTE_CMD(handle, init, wait_ms);\n}\n\nesp_err_t essl_wait_for_ready(essl_handle_t handle, uint32_t wait_ms)\n{\n    CHECK_EXECUTE_CMD(handle, wait_for_ready, wait_ms);\n}\n\nesp_err_t essl_send_packet(essl_handle_t handle, const void *start, size_t length, uint32_t wait_ms)\n{\n    if (handle == NULL || start == NULL || length == 0) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    if (handle->send_packet == NULL) {\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n    esp_err_t err;\n    const uint32_t timeout_ticks = pdMS_TO_TICKS(wait_ms);\n\n    uint32_t pre = xTaskGetTickCount();\n    uint32_t now;\n    uint32_t remain_wait_ms = 0;\n\n    do {\n        now = xTaskGetTickCount();\n        remain_wait_ms = pdTICKS_TO_MS(TIME_REMAIN(pre, now, timeout_ticks));\n        err = handle->send_packet(handle->args, start, length, remain_wait_ms);\n        if (err == ESP_OK) {\n            break;\n        } else if (err != ESP_ERR_NOT_FOUND) {\n            return err;\n        } // else ESP_ERR_NOT_FOUND\n        //the slave is not ready, retry\n    } while (remain_wait_ms > 0);\n    return err;\n}\n\nesp_err_t essl_get_packet(essl_handle_t handle, void *out_data, size_t size, size_t *out_length, uint32_t wait_ms)\n{\n    if (handle == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    if (out_data == NULL || size == 0 || out_length == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    if (handle->get_packet == NULL || handle->update_rx_data_size == NULL || handle->get_rx_data_size == NULL) {\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n    esp_err_t err;\n    const uint32_t timeout_ticks = pdMS_TO_TICKS(wait_ms);\n\n    uint32_t pre = xTaskGetTickCount();\n    uint32_t now = 3;\n    uint32_t wait_remain_ms = 0;\n    int data_available = handle->get_rx_data_size(handle->args);\n\n    // if there is already enough data to read, skip the length update.\n    if (data_available < size) {\n        //loop until timeout, or there is at least one byte\n        do {\n            now = xTaskGetTickCount();\n            wait_remain_ms = pdTICKS_TO_MS(TIME_REMAIN(pre, now, timeout_ticks));\n            err = handle->update_rx_data_size(handle->args, wait_remain_ms);\n            if (err != ESP_OK) {\n                return err;\n            }\n            data_available = handle->get_rx_data_size(handle->args);\n            if (data_available > 0) {\n                break;\n            }\n        } while (wait_remain_ms > 0);\n    }\n\n    if (data_available == 0) {\n        //the slave has no data to send\n        return ESP_ERR_NOT_FOUND;\n    }\n\n    int len = ESSL_MIN(data_available, size);\n    now = xTaskGetTickCount();\n    wait_remain_ms = pdTICKS_TO_MS(TIME_REMAIN(pre, now, timeout_ticks));\n    err = handle->get_packet(handle->args, out_data, len, wait_remain_ms);\n    if (err != ESP_OK) {\n        return err;\n    }\n\n    *out_length = len;\n    if (len < data_available) {\n        return ESP_ERR_NOT_FINISHED;\n    }\n    return ESP_OK;\n}\n\nesp_err_t essl_get_tx_buffer_num(essl_handle_t handle, uint32_t *out_tx_num, uint32_t wait_ms)\n{\n    if (handle == NULL || out_tx_num == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    if (handle->update_tx_buffer_num == NULL || handle->get_tx_buffer_num == NULL) {\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n\n    esp_err_t err = handle->update_tx_buffer_num(handle->args, wait_ms);\n    if (err != ESP_OK) {\n        return err;\n    }\n\n    *out_tx_num = handle->get_tx_buffer_num(handle->args);\n    return ESP_OK;\n}\n\nesp_err_t essl_get_rx_data_size(essl_handle_t handle, uint32_t *out_rx_size, uint32_t wait_ms)\n{\n    if (handle == NULL || out_rx_size == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    if (handle->update_rx_data_size == NULL || handle->get_rx_data_size == NULL) {\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n\n    esp_err_t err = handle->update_rx_data_size(handle->args, wait_ms);\n    if (err != ESP_OK) {\n        return err;\n    }\n\n    *out_rx_size = handle->get_rx_data_size(handle->args);\n    return ESP_OK;\n}\n\nesp_err_t essl_write_reg(essl_handle_t handle, uint8_t addr, uint8_t value, uint8_t *value_o, uint32_t wait_ms)\n{\n    CHECK_EXECUTE_CMD(handle, write_reg, addr, value, value_o, wait_ms);\n}\n\nesp_err_t essl_read_reg(essl_handle_t handle, uint8_t add, uint8_t *value_o, uint32_t wait_ms)\n{\n    CHECK_EXECUTE_CMD(handle, read_reg, add, value_o, wait_ms);\n}\n\nesp_err_t essl_wait_int(essl_handle_t handle, TickType_t wait_ms)\n{\n    CHECK_EXECUTE_CMD(handle, wait_int, wait_ms);\n}\n\nesp_err_t essl_reset_cnt(essl_handle_t handle)\n{\n    if (handle == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    if (handle->reset_cnt == NULL) {\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n    handle->reset_cnt(handle->args);\n    return ESP_OK;\n}\n\nesp_err_t essl_clear_intr(essl_handle_t handle, uint32_t intr_mask, uint32_t wait_ms)\n{\n    CHECK_EXECUTE_CMD(handle, clear_intr, intr_mask, wait_ms);\n}\n\nesp_err_t essl_get_intr(essl_handle_t handle, uint32_t *intr_raw, uint32_t *intr_st, uint32_t wait_ms)\n{\n    if (intr_raw == NULL && intr_st == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    CHECK_EXECUTE_CMD(handle, get_intr, intr_raw, intr_st, wait_ms);\n}\n\nesp_err_t essl_set_intr_ena(essl_handle_t handle, uint32_t ena_mask, uint32_t wait_ms)\n{\n    CHECK_EXECUTE_CMD(handle, set_intr_ena, ena_mask, wait_ms);\n}\n\nesp_err_t essl_get_intr_ena(essl_handle_t handle, uint32_t *ena_mask_o, uint32_t wait_ms)\n{\n    if (ena_mask_o == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    CHECK_EXECUTE_CMD(handle, get_intr_ena, ena_mask_o, wait_ms);\n}\n\nesp_err_t essl_send_slave_intr(essl_handle_t handle, uint32_t intr_mask, uint32_t wait_ms)\n{\n    CHECK_EXECUTE_CMD(handle, send_slave_intr, intr_mask, wait_ms);\n}\n"
  },
  {
    "path": "esp_serial_slave_link/essl_internal.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include <esp_types.h>\n#include <esp_err.h>\n\n/** Context used by the ``esp_serial_slave_link`` component.\n */\nstruct essl_dev_t {\n    void *args;\n\n    esp_err_t (*init)(void *ctx, uint32_t wait_ms);\n\n    esp_err_t (*wait_for_ready)(void *ctx, uint32_t wait_ms);\n    esp_err_t (*update_tx_buffer_num)(void *ctx, uint32_t wait_ms);\n    esp_err_t (*update_rx_data_size)(void *ctx, uint32_t wait_ms);\n    esp_err_t (*send_packet)(void *ctx, const void *start, size_t length, uint32_t wait_ms);\n    esp_err_t (*get_packet)(void *ctx, void *out_data, size_t size, uint32_t wait_ms);\n    esp_err_t (*write_reg)(void *ctx, uint8_t addr, uint8_t value, uint8_t *value_o, uint32_t wait_ms);\n    esp_err_t (*read_reg)(void *ctx, uint8_t add, uint8_t *value_o, uint32_t wait_ms);\n    esp_err_t (*wait_int)(void *ctx, uint32_t wait_ms);\n    esp_err_t (*clear_intr)(void *ctx, uint32_t intr_mask, uint32_t wait_ms);\n    esp_err_t (*get_intr)(void *ctx, uint32_t *intr_raw, uint32_t *intr_st, uint32_t wait_ms);\n    esp_err_t (*set_intr_ena)(void *ctx, uint32_t ena_mask, uint32_t wait_ms);\n    esp_err_t (*get_intr_ena)(void *ctx, uint32_t *ena_mask_o, uint32_t wait_ms);\n    esp_err_t (*send_slave_intr)(void *ctx, uint32_t intr_mask, uint32_t wait_ms);\n\n    uint32_t (*get_tx_buffer_num)(void *ctx);\n    uint32_t (*get_rx_data_size)(void *ctx);\n    void (*reset_cnt)(void *ctx);\n};\n\ntypedef struct essl_dev_t essl_dev_t;\n"
  },
  {
    "path": "esp_serial_slave_link/essl_sdio.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"soc/soc_caps.h\"\n#include \"esp_log.h\"\n#include \"sdmmc_cmd.h\"\n#include \"driver/sdmmc_defs.h\"\n\n#include \"essl_internal.h\"\n#include \"essl_sdio.h\"\n#include \"esp_heap_caps.h\"\n\nstatic const char TAG[] = \"essl_sdio\";\n\n#ifndef DR_REG_SLCHOST_BASE\n#define DR_REG_SLCHOST_BASE             0 //The SDIO slave only check the least significant 10 bits, this doesn't matter\n#endif\n\n//This should be consistent with the macro in soc/host_reg.h\n#define HOST_SLC0HOST_TOKEN_RDATA_REG   (DR_REG_SLCHOST_BASE + 0x44)\n#define HOST_SLC0HOST_INT_RAW_REG       (DR_REG_SLCHOST_BASE + 0x50)\n#define HOST_SLC0HOST_INT_ST_REG        (DR_REG_SLCHOST_BASE + 0x58)\n#define HOST_SLCHOST_PKT_LEN_REG        (DR_REG_SLCHOST_BASE + 0x60)\n#define HOST_SLCHOST_CONF_W0_REG        (DR_REG_SLCHOST_BASE + 0x6C)\n#define HOST_SLCHOST_CONF_W7_REG        (DR_REG_SLCHOST_BASE + 0x8C)\n#define HOST_SLC0HOST_INT_CLR_REG       (DR_REG_SLCHOST_BASE + 0xD4)\n#define HOST_SLC0HOST_FUNC1_INT_ENA_REG (DR_REG_SLCHOST_BASE + 0xDC)\n\n\n#define HOST_SLCHOST_CONF_W_REG(pos)    (HOST_SLCHOST_CONF_W0_REG+pos+(pos>23?4:0)+(pos>31?12:0))\n\n#define ESSL_CMD53_END_ADDR    0x1f800\n\n#define TX_BUFFER_MAX   0x1000\n#define TX_BUFFER_MASK  0xFFF\n#define RX_BYTE_MAX     0x100000\n#define RX_BYTE_MASK    0xFFFFF\n\n#define FUNC1_EN_MASK   (BIT(1))\n\n/**\n * Initialize ``void`` over SDIO by this macro.\n */\n#define ESSL_SDIO_DEFAULT_CONTEXT() (essl_dev_t){\\\n    .init = essl_sdio_init, \\\n    .wait_for_ready = essl_sdio_wait_for_ready, \\\n    .get_tx_buffer_num = essl_sdio_get_tx_buffer_num,\\\n    .update_tx_buffer_num = essl_sdio_update_tx_buffer_num,\\\n    .get_rx_data_size = essl_sdio_get_rx_data_size,\\\n    .update_rx_data_size = essl_sdio_update_rx_data_size,\\\n    .send_packet = essl_sdio_send_packet,\\\n    .get_packet = essl_sdio_get_packet,\\\n    .write_reg = essl_sdio_write_reg,\\\n    .read_reg = essl_sdio_read_reg,\\\n    .wait_int = essl_sdio_wait_int,\\\n    .send_slave_intr = essl_sdio_send_slave_intr, \\\n    .get_intr = essl_sdio_get_intr, \\\n    .clear_intr = essl_sdio_clear_intr, \\\n    .set_intr_ena = essl_sdio_set_intr_ena, \\\n    .reset_cnt = essl_sdio_reset_cnt, \\\n    }\n\ntypedef struct {\n    //common part\n    uint16_t        buffer_size;\n    ///< All data that do not fully fill a buffer is still counted as one buffer. E.g. 10 bytes data costs 2 buffers if the size is 8 bytes per buffer.\n    ///< Buffer size of the slave pre-defined between host and slave before communication.\n    size_t          tx_sent_buffers;    ///< Counter holding the amount of buffers already sent to ESP32 slave. Should be set to 0 when initialization.\n    size_t          tx_sent_buffers_latest;    ///< The latest reading (from the slave) of counter holding the amount of buffers loaded. Should be set to 0 when initialization.\n    size_t          rx_got_bytes;       ///< Counter holding the amount of bytes already received from ESP32 slave. Should be set to 0 when initialization.\n    size_t          rx_got_bytes_latest;       ///< The latest reading (from the slave) of counter holding the amount of bytes to send. Should be set to 0 when initialization.\n\n    sdmmc_card_t   *card;               ///< Initialized sdmmc_cmd card\n    uint16_t        block_size;\n    ///< If this is too large, it takes time to send stuff bits; while if too small, intervals between blocks cost much.\n    ///< Should be set according to length of data, and larger than ``TRANS_LEN_MAX/511``.\n    ///< Block size of the SDIO function 1. After the initialization this will hold the value the slave really do. Valid value is 1-2048.\n} essl_sdio_context_t;\n\n\nesp_err_t essl_sdio_update_tx_buffer_num(void *arg, uint32_t wait_ms);\nesp_err_t essl_sdio_update_rx_data_size(void *arg, uint32_t wait_ms);\n\nstatic inline esp_err_t essl_sdio_write_byte(sdmmc_card_t *card, uint32_t addr, uint8_t val, uint8_t *val_o)\n{\n    return sdmmc_io_write_byte(card, 1, addr & 0x3FF, val, val_o);\n}\n\nstatic inline esp_err_t essl_sdio_write_bytes(sdmmc_card_t *card, uint32_t addr, uint8_t *val, int len)\n{\n    return sdmmc_io_write_bytes(card, 1, addr & 0x3FF, val, len);\n}\n\nstatic inline esp_err_t essl_sdio_read_byte(sdmmc_card_t *card, uint32_t addr, uint8_t *val_o)\n{\n    return sdmmc_io_read_byte(card, 1, addr & 0x3FF, val_o);\n}\n\nstatic inline esp_err_t essl_sdio_read_bytes(sdmmc_card_t *card, uint32_t addr, uint8_t *val_o, int len)\n{\n    return sdmmc_io_read_bytes(card, 1, addr & 0x3FF, val_o, len);\n}\n\nesp_err_t essl_sdio_init_dev(essl_handle_t *out_handle, const essl_sdio_config_t *config)\n{\n    esp_err_t ret = ESP_OK;\n    essl_sdio_context_t *arg = NULL;\n    essl_dev_t *dev = NULL;\n    arg = (essl_sdio_context_t *)heap_caps_malloc(sizeof(essl_sdio_context_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);\n    dev = (essl_dev_t *)heap_caps_malloc(sizeof(essl_dev_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);\n\n    if (arg == NULL || dev == NULL) {\n        ret = ESP_ERR_NO_MEM;\n        goto cleanup;\n    }\n\n    *dev = ESSL_SDIO_DEFAULT_CONTEXT();\n    dev->args = arg;\n\n    *arg = (essl_sdio_context_t) {\n        .card = config->card,\n        .block_size = 0x200,\n        .buffer_size = config->recv_buffer_size,\n        .tx_sent_buffers = 0,\n        .rx_got_bytes = 0,\n    };\n\n    *out_handle = dev;\n    return ESP_OK;\n\ncleanup:\n    free(arg);\n    free(dev);\n    return ret;\n}\n\nesp_err_t essl_sdio_deinit_dev(essl_handle_t handle)\n{\n    if (handle) {\n        free (handle->args);\n    }\n    free(handle);\n    return ESP_OK;\n}\n\nesp_err_t essl_sdio_init(void *arg, uint32_t wait_ms)\n{\n    essl_sdio_context_t *ctx = arg;\n    esp_err_t err;\n    uint8_t ioe = 0;\n    sdmmc_card_t *card = ctx->card;\n\n    err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_ENABLE, &ioe);\n    if (err != ESP_OK) {\n        return err;\n    }\n    ESP_LOGD(TAG, \"IOE: 0x%02\"PRIx8, ioe);\n\n    uint8_t ior = 0;\n    err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_READY, &ior);\n    if (err != ESP_OK) {\n        return err;\n    }\n    ESP_LOGD(TAG, \"IOR: 0x%02\"PRIx8, ior);\n\n    // enable function 1\n    ioe |= FUNC1_EN_MASK;\n    err = sdmmc_io_write_byte(card, 0, SD_IO_CCCR_FN_ENABLE, ioe, &ioe);\n    if (err != ESP_OK) {\n        return err;\n    }\n    ESP_LOGD(TAG, \"IOE: 0x%02\"PRIx8, ioe);\n\n    // wait for the card to become ready\n    while ((ior & FUNC1_EN_MASK) == 0) {\n        err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_READY, &ior);\n        if (err != ESP_OK) {\n            return err;\n        }\n        ESP_LOGD(TAG, \"IOR: 0x%02\"PRIx8, ior);\n    }\n\n    // get interrupt status\n    uint8_t ie = 0;\n    err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_INT_ENABLE, &ie);\n    if (err != ESP_OK) {\n        return err;\n    }\n    ESP_LOGD(TAG, \"IE: 0x%02\"PRIx8, ie);\n\n    // enable interrupts for function 1&2 and master enable\n    ie |= BIT(0) | FUNC1_EN_MASK;\n    err = sdmmc_io_write_byte(card, 0, SD_IO_CCCR_INT_ENABLE, ie, &ie);\n    if (err != ESP_OK) {\n        return err;\n    }\n    ESP_LOGD(TAG, \"IE: 0x%02\"PRIx8, ie);\n\n    // get bus width register\n    uint8_t bus_width = 0;\n    err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_BUS_WIDTH, &bus_width);\n    if (err != ESP_OK) {\n        return err;\n    }\n    ESP_LOGD(TAG, \"BUS_WIDTH: 0x%02\"PRIx8, bus_width);\n\n    // enable continuous SPI interrupts\n    bus_width |= CCCR_BUS_WIDTH_ECSI;\n    err = sdmmc_io_write_byte(card, 0, SD_IO_CCCR_BUS_WIDTH, bus_width, &bus_width);\n    if (err != ESP_OK) {\n        return err;\n    }\n    ESP_LOGD(TAG, \"BUS_WIDTH: 0x%02\"PRIx8, bus_width);\n\n    uint16_t bs = 512;\n    const uint8_t *bs_u8 = (const uint8_t *) &bs;\n    uint16_t bs_read = 0;\n    uint8_t *bs_read_u8 = (uint8_t *) &bs_read;\n    // Set block sizes for functions 0 to 512 bytes\n    ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, SD_IO_CCCR_BLKSIZEL, &bs_read_u8[0]));\n    ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, SD_IO_CCCR_BLKSIZEH, &bs_read_u8[1]));\n    ESP_LOGD(TAG, \"Function 0 BS: %d\", (unsigned int) bs_read);\n\n    ESP_ERROR_CHECK(sdmmc_io_write_byte(card, 0, SD_IO_CCCR_BLKSIZEL, bs_u8[0], NULL));\n    ESP_ERROR_CHECK(sdmmc_io_write_byte(card, 0, SD_IO_CCCR_BLKSIZEH, bs_u8[1], NULL));\n    ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, SD_IO_CCCR_BLKSIZEL, &bs_read_u8[0]));\n    ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, SD_IO_CCCR_BLKSIZEH, &bs_read_u8[1]));\n    ESP_LOGD(TAG, \"Function 0 BS: %d\", (unsigned int) bs_read);\n\n    // Set block sizes for functions 1 to given value (default value = 512).\n    if (ctx->block_size > 0 && ctx->block_size <= 2048) {\n        bs = ctx->block_size;\n    } else {\n        bs = 512;\n    }\n    size_t offset = SD_IO_FBR_START * 1;\n    ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEL, &bs_read_u8[0]));\n    ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEH, &bs_read_u8[1]));\n    ESP_LOGD(TAG, \"Function 1 BS: %d\", (unsigned int) bs_read);\n\n    ESP_ERROR_CHECK(sdmmc_io_write_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEL, bs_u8[0], NULL));\n    ESP_ERROR_CHECK(sdmmc_io_write_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEH, bs_u8[1], NULL));\n    ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEL, &bs_read_u8[0]));\n    ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEH, &bs_read_u8[1]));\n    ESP_LOGD(TAG, \"Function 1 BS: %d\", (unsigned int) bs_read);\n\n    if (bs_read != ctx->block_size) {\n        ESP_LOGW(TAG, \"Function1 block size %d different than set value %d\", bs_read, ctx->block_size);\n        ctx->block_size = bs_read;\n    }\n    return ESP_OK;\n}\n\nesp_err_t essl_sdio_wait_for_ready(void *arg, uint32_t wait_ms)\n{\n    ESP_LOGV(TAG, \"wait_for_ioready\");\n    esp_err_t err;\n    sdmmc_card_t *card = ((essl_sdio_context_t *)arg)->card;\n    // wait for the card to become ready\n    uint8_t ior = 0;\n    while ((ior & FUNC1_EN_MASK) == 0) {\n        err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_READY, &ior);\n        if (err != ESP_OK) {\n            return err;\n        }\n        ESP_LOGD(TAG, \"IOR: 0x%02x\", ior);\n    }\n    return ESP_OK;\n}\n\nesp_err_t essl_sdio_send_packet(void *arg, const void *start, size_t length, uint32_t wait_ms)\n{\n    essl_sdio_context_t *ctx = arg;\n    uint16_t buffer_size = ctx->buffer_size;\n    int buffer_used = (length + buffer_size - 1) / buffer_size;\n    esp_err_t err;\n\n    if (essl_sdio_get_tx_buffer_num(arg) < buffer_used) {\n        //slave has no enough buffer, try update for once\n        esp_err_t err = essl_sdio_update_tx_buffer_num(arg, wait_ms);\n        if (err != ESP_OK) {\n            return err;\n        }\n        if (essl_sdio_get_tx_buffer_num(arg) < buffer_used) {\n            ESP_LOGV(TAG, \"buffer is not enough: %d, %d required.\", ctx->tx_sent_buffers_latest, ctx->tx_sent_buffers + buffer_used);\n            return ESP_ERR_NOT_FOUND;\n        }\n    }\n\n    ESP_LOGV(TAG, \"send_packet: len: %d\", length);\n\n    uint8_t *start_ptr = (uint8_t *)start;\n    uint32_t len_remain = length;\n    do {\n        const int block_size = 512;\n        /* Though the driver supports to split packet of unaligned size into\n         * length of 4x and 1~3, we still send aligned size of data to get\n         * higher efficiency. The length is determined by the SDIO address, and\n         * the remainning will be discard by the slave hardware.\n         */\n        int block_n = len_remain / block_size;\n        int len_to_send;\n        if (block_n) {\n            len_to_send = block_n * block_size;\n            err = sdmmc_io_write_blocks(ctx->card, 1, ESSL_CMD53_END_ADDR - len_remain, start_ptr, len_to_send);\n        } else {\n            len_to_send = len_remain;\n            err = sdmmc_io_write_bytes(ctx->card, 1, ESSL_CMD53_END_ADDR - len_remain, start_ptr, (len_to_send + 3) & (~3));\n        }\n        if (err != ESP_OK) {\n            return err;\n        }\n        start_ptr += len_to_send;\n        len_remain -= len_to_send;\n    } while (len_remain);\n\n    ctx->tx_sent_buffers += buffer_used;\n    return ESP_OK;\n}\n\nesp_err_t essl_sdio_get_packet(void *arg, void *out_data, size_t size, uint32_t wait_ms)\n{\n    essl_sdio_context_t *ctx = arg;\n    esp_err_t err;\n\n    ESP_LOGV(TAG, \"get_packet: read size=%d\", size);\n    if (essl_sdio_get_rx_data_size(arg) < size) {\n        err = essl_sdio_update_rx_data_size(arg, wait_ms);\n        if (err != ESP_OK) {\n            return err;\n        }\n        if (essl_sdio_get_rx_data_size(arg) < size) {\n            return ESP_ERR_NOT_FOUND;\n        }\n    }\n\n    uint8_t *start = out_data;\n    uint32_t len_remain = size;\n    do {\n        const int block_size = 512; //currently our driver don't support block size other than 512\n        int len_to_send;\n\n        int block_n = len_remain / block_size;\n        if (block_n != 0) {\n            len_to_send = block_n * block_size;\n            err = sdmmc_io_read_blocks(ctx->card, 1, ESSL_CMD53_END_ADDR - len_remain, start, len_to_send);\n        } else {\n            len_to_send = len_remain;\n            /* though the driver supports to split packet of unaligned size into length\n             * of 4x and 1~3, we still get aligned size of data to get higher\n             * efficiency. The length is determined by the SDIO address, and the\n             * remainning will be ignored by the slave hardware.\n             */\n            err = sdmmc_io_read_bytes(ctx->card, 1, ESSL_CMD53_END_ADDR - len_remain, start, (len_to_send + 3) & (~3));\n        }\n        if (err != ESP_OK) {\n            return err;\n        }\n        start += len_to_send;\n        len_remain -= len_to_send;\n        ctx->rx_got_bytes += len_to_send;\n    } while (len_remain != 0);\n\n    return err;\n}\n\nuint32_t essl_sdio_get_tx_buffer_num(void *arg)\n{\n    essl_sdio_context_t *ctx = arg;\n    ESP_LOGV(TAG, \"tx latest: %d, sent: %d\", ctx->tx_sent_buffers_latest, ctx->tx_sent_buffers);\n    return (ctx->tx_sent_buffers_latest + TX_BUFFER_MAX - ctx->tx_sent_buffers) % TX_BUFFER_MAX;\n}\n\nesp_err_t essl_sdio_update_tx_buffer_num(void *arg, uint32_t wait_ms)\n{\n    essl_sdio_context_t *ctx = arg;\n    uint32_t len;\n    esp_err_t err;\n\n    err = essl_sdio_read_bytes(ctx->card, HOST_SLC0HOST_TOKEN_RDATA_REG, (uint8_t *) &len, 4);\n    if (err != ESP_OK) {\n        return err;\n    }\n    len = (len >> 16)&TX_BUFFER_MASK;\n    ctx->tx_sent_buffers_latest = len;\n    ESP_LOGV(TAG, \"update_tx_buffer_num: %d\", (unsigned int)len);\n    return ESP_OK;\n}\n\nuint32_t essl_sdio_get_rx_data_size(void *arg)\n{\n    essl_sdio_context_t *ctx = arg;\n    ESP_LOGV(TAG, \"rx latest: %d, read: %d\", ctx->rx_got_bytes_latest, ctx->rx_got_bytes);\n    return (ctx->rx_got_bytes_latest + RX_BYTE_MAX - ctx->rx_got_bytes) % RX_BYTE_MAX;\n}\n\nesp_err_t essl_sdio_update_rx_data_size(void *arg, uint32_t wait_ms)\n{\n    essl_sdio_context_t *ctx = arg;\n    uint32_t len;\n    esp_err_t err;\n\n    ESP_LOGV(TAG, \"get_rx_data_size: got_bytes: %d\", ctx->rx_got_bytes);\n    err = essl_sdio_read_bytes(ctx->card, HOST_SLCHOST_PKT_LEN_REG, (uint8_t *) &len, 4);\n    if (err != ESP_OK) {\n        return err;\n    }\n    len &= RX_BYTE_MASK;\n    ctx->rx_got_bytes_latest = len;\n    return ESP_OK;\n}\n\n\nesp_err_t essl_sdio_write_reg(void *arg, uint8_t addr, uint8_t value, uint8_t *value_o, uint32_t wait_ms)\n{\n    ESP_LOGV(TAG, \"write_reg: 0x%02\"PRIX8, value);\n    // address over range\n    if (addr >= 60) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    //W7 is reserved for interrupts\n    if (addr >= 28) {\n        addr += 4;\n    }\n    return essl_sdio_write_byte(((essl_sdio_context_t *)arg)->card, HOST_SLCHOST_CONF_W_REG(addr), value, value_o);\n}\n\nesp_err_t essl_sdio_read_reg(void *arg, uint8_t add, uint8_t *value_o, uint32_t wait_ms)\n{\n    ESP_LOGV(TAG, \"read_reg\");\n    // address over range\n    if (add >= 60) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    //W7 is reserved for interrupts\n    if (add >= 28) {\n        add += 4;\n    }\n    esp_err_t ret = essl_sdio_read_byte(((essl_sdio_context_t *)arg)->card, HOST_SLCHOST_CONF_W_REG(add), value_o);\n    ESP_LOGV(TAG, \"reg: %02\"PRIX8, *value_o);\n    return ret;\n}\n\nesp_err_t essl_sdio_clear_intr(void *arg, uint32_t intr_mask, uint32_t wait_ms)\n{\n    ESP_LOGV(TAG, \"clear_intr: %08\"PRIX32, intr_mask);\n    return essl_sdio_write_bytes(((essl_sdio_context_t *) arg)->card, HOST_SLC0HOST_INT_CLR_REG, (uint8_t *) &intr_mask, 4);\n}\n\nesp_err_t essl_sdio_get_intr(void *arg, uint32_t *intr_raw, uint32_t *intr_st, uint32_t wait_ms)\n{\n    essl_sdio_context_t *ctx = arg;\n    esp_err_t r;\n    ESP_LOGV(TAG, \"get_intr\");\n    if (intr_raw == NULL && intr_st == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    if (intr_raw != NULL) {\n        r = essl_sdio_read_bytes(ctx->card, HOST_SLC0HOST_INT_RAW_REG, (uint8_t *) intr_raw, 4);\n        if (r != ESP_OK) {\n            return r;\n        }\n    }\n    if (intr_st != NULL) {\n        r = essl_sdio_read_bytes(ctx->card, HOST_SLC0HOST_INT_ST_REG, (uint8_t *) intr_st, 4);\n        if (r != ESP_OK) {\n            return r;\n        }\n    }\n    return ESP_OK;\n}\n\nesp_err_t essl_sdio_set_intr_ena(void *arg, uint32_t ena_mask, uint32_t wait_ms)\n{\n    ESP_LOGV(TAG, \"set_intr_ena: %08\"PRIX32, ena_mask);\n    return essl_sdio_write_bytes(((essl_sdio_context_t *)arg)->card, HOST_SLC0HOST_FUNC1_INT_ENA_REG,\n                                 (uint8_t *) &ena_mask, 4);\n}\n\nesp_err_t essl_sdio_get_intr_ena(void *arg, uint32_t *ena_mask_o, uint32_t wait_ms)\n{\n    ESP_LOGV(TAG, \"get_intr_ena\");\n    esp_err_t ret = essl_sdio_read_bytes(((essl_sdio_context_t *)arg)->card, HOST_SLC0HOST_FUNC1_INT_ENA_REG,\n                                         (uint8_t *) ena_mask_o, 4);\n    ESP_LOGV(TAG, \"ena: %08\"PRIX32, *ena_mask_o);\n    return ret;\n}\n\nesp_err_t essl_sdio_send_slave_intr(void *arg, uint32_t intr_mask, uint32_t wait_ms)\n{\n    //Only 8 bits available\n    ESP_LOGV(TAG, \"send_slave_intr: %02\"PRIx8, (uint8_t)intr_mask);\n    return essl_sdio_write_byte(((essl_sdio_context_t *)arg)->card, HOST_SLCHOST_CONF_W7_REG + 0, (uint8_t)intr_mask, NULL);\n}\n\nesp_err_t essl_sdio_wait_int(void *arg, uint32_t wait_ms)\n{\n    return sdmmc_io_wait_int(((essl_sdio_context_t *)arg)->card, wait_ms);\n}\n\nvoid essl_sdio_reset_cnt(void *arg)\n{\n    essl_sdio_context_t *ctx = arg;\n    ctx->rx_got_bytes = 0;\n    ctx->tx_sent_buffers = 0;\n}\n"
  },
  {
    "path": "esp_serial_slave_link/essl_sdio_defs.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// Definitions of Espressif SDIO Slave hardware\n\n\n#include \"essl_sdio.h\"\n\nessl_sdio_def_t ESSL_SDIO_DEF_ESP32 = {\n    .new_packet_intr_mask = BIT(23),\n};\n\nessl_sdio_def_t ESSL_SDIO_DEF_ESP32C6 = {\n    .new_packet_intr_mask = BIT(23),\n};\n"
  },
  {
    "path": "esp_serial_slave_link/essl_spi.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include <sys/param.h>\n#include \"esp_log.h\"\n#include \"esp_check.h\"\n#include \"esp_memory_utils.h\"\n#include \"esp_private/periph_ctrl.h\"\n\n#include \"driver/spi_master.h\"\n#include \"hal/spi_types.h\"\n#include \"hal/spi_ll.h\"\n\n#include \"essl_internal.h\"\n#include \"essl_spi.h\"\n\n/**\n * Initialise device function list of SPI by this macro.\n */\n#define ESSL_SPI_DEFAULT_DEV_FUNC() (essl_dev_t) {\\\n    .get_tx_buffer_num = essl_spi_get_tx_buffer_num,\\\n    .update_tx_buffer_num = essl_spi_update_tx_buffer_num,\\\n    .get_rx_data_size = essl_spi_get_rx_data_size,\\\n    .update_rx_data_size = essl_spi_update_rx_data_size,\\\n    .send_packet = essl_spi_send_packet,\\\n    .get_packet = essl_spi_get_packet,\\\n    .write_reg = essl_spi_write_reg,\\\n    .read_reg = essl_spi_read_reg,\\\n}\n\nstatic const char TAG[] = \"essl_spi\";\n\ntypedef struct {\n    spi_device_handle_t     spi;                    // Pointer to SPI device handle.\n    /* Master TX, Slave RX */\n    struct {\n        size_t                  sent_buf_num;           // Number of TX buffers that has been sent out by the master.\n        size_t                  slave_rx_buf_num;       // Number of RX buffers loaded by the slave.\n        uint16_t                tx_buffer_size;         /* Buffer size for Master TX / Slave RX direction.\n                                                         * Data with length within this size will still be regarded as one buffer.\n                                                         * E.g. 10 bytes data costs 2 buffers if the size is 8 bytes per buffer. */\n        uint8_t                 tx_sync_reg;            // The pre-negotiated register ID for Master-TX-SLAVE-RX synchronization. 1 word (4 Bytes) will be reserved for the synchronization.\n    } master_out;\n    /* Master RX, Slave TX */\n    struct {\n        size_t                  received_bytes;         // Number of the RX bytes that has been received by the Master.\n        size_t                  slave_tx_bytes;         // Number of the TX bytes that has been loaded by the Slave\n        uint8_t                 rx_sync_reg;            // The pre-negotiated register ID for Master-RX-SLAVE-TX synchronization. 1 word (4 Bytes) will be reserved for the synchronization.\n    } master_in;\n} essl_spi_context_t;\n\nstatic uint16_t get_hd_command(spi_command_t cmd_t, uint32_t flags)\n{\n    spi_line_mode_t line_mode = {\n        .cmd_lines = 1,\n    };\n\n    if (flags & SPI_TRANS_MODE_DIO) {\n        line_mode.data_lines = 2;\n        if (flags & SPI_TRANS_MODE_DIOQIO_ADDR) {\n            line_mode.addr_lines = 2;\n        } else {\n            line_mode.addr_lines = 1;\n        }\n    } else if (flags & SPI_TRANS_MODE_QIO) {\n        line_mode.data_lines = 4;\n        if (flags & SPI_TRANS_MODE_DIOQIO_ADDR) {\n            line_mode.addr_lines = 4;\n        } else {\n            line_mode.addr_lines = 1;\n        }\n    } else {\n        line_mode.data_lines = 1;\n        line_mode.addr_lines = 1;\n    }\n\n    return spi_ll_get_slave_hd_command(cmd_t, line_mode);\n}\n\nstatic int get_hd_dummy_bits(uint32_t flags)\n{\n    spi_line_mode_t line_mode = {};\n\n    if (flags & SPI_TRANS_MODE_DIO) {\n        line_mode.data_lines = 2;\n    } else if (flags & SPI_TRANS_MODE_QIO) {\n        line_mode.data_lines = 4;\n    } else {\n        line_mode.data_lines = 1;\n    }\n\n    return spi_ll_get_slave_hd_dummy_bits(line_mode);\n}\n\nesp_err_t essl_spi_rdbuf(spi_device_handle_t spi, uint8_t *out_data, int addr, int len, uint32_t flags)\n{\n    spi_transaction_ext_t t = {\n        .base = {\n            .cmd = get_hd_command(SPI_CMD_HD_RDBUF, flags),\n            .addr = addr % 72,\n            .rxlength = len * 8,\n            .rx_buffer = out_data,\n            .flags = flags | SPI_TRANS_VARIABLE_DUMMY,\n        },\n        .dummy_bits = get_hd_dummy_bits(flags),\n    };\n\n    return spi_device_transmit(spi, (spi_transaction_t *)&t);\n}\n\nesp_err_t essl_spi_rdbuf_polling(spi_device_handle_t spi, uint8_t *out_data, int addr, int len, uint32_t flags)\n{\n    spi_transaction_ext_t t = {\n        .base = {\n            .cmd = get_hd_command(SPI_CMD_HD_RDBUF, flags),\n            .addr = addr % 72,\n            .rxlength = len * 8,\n            .rx_buffer = out_data,\n            .flags = flags | SPI_TRANS_VARIABLE_DUMMY,\n        },\n        .dummy_bits = get_hd_dummy_bits(flags),\n    };\n\n    return spi_device_polling_transmit(spi, (spi_transaction_t *)&t);\n}\n\nesp_err_t essl_spi_wrbuf(spi_device_handle_t spi, const uint8_t *data, int addr, int len, uint32_t flags)\n{\n    spi_transaction_ext_t t = {\n        .base = {\n            .cmd = get_hd_command(SPI_CMD_HD_WRBUF, flags),\n            .addr = addr % 72,\n            .length = len * 8,\n            .tx_buffer = data,\n            .flags = flags | SPI_TRANS_VARIABLE_DUMMY,\n        },\n        .dummy_bits = get_hd_dummy_bits(flags),\n    };\n    return spi_device_transmit(spi, (spi_transaction_t *)&t);\n}\n\nesp_err_t essl_spi_wrbuf_polling(spi_device_handle_t spi, const uint8_t *data, int addr, int len, uint32_t flags)\n{\n    spi_transaction_ext_t t = {\n        .base = {\n            .cmd = get_hd_command(SPI_CMD_HD_WRBUF, flags),\n            .addr = addr % 72,\n            .length = len * 8,\n            .tx_buffer = data,\n            .flags = flags | SPI_TRANS_VARIABLE_DUMMY,\n        },\n        .dummy_bits = get_hd_dummy_bits(flags),\n    };\n    return spi_device_polling_transmit(spi, (spi_transaction_t *)&t);\n}\n\nesp_err_t essl_spi_rddma_seg(spi_device_handle_t spi, uint8_t *out_data, int seg_len, uint32_t flags)\n{\n    spi_transaction_ext_t t = {\n        .base = {\n            .cmd = get_hd_command(SPI_CMD_HD_RDDMA, flags),\n            .rxlength = seg_len * 8,\n            .rx_buffer = out_data,\n            .flags = flags | SPI_TRANS_VARIABLE_DUMMY,\n        },\n        .dummy_bits = get_hd_dummy_bits(flags),\n    };\n    return spi_device_transmit(spi, (spi_transaction_t *)&t);\n}\n\nesp_err_t essl_spi_rddma_done(spi_device_handle_t spi, uint32_t flags)\n{\n    spi_transaction_t end_t = {\n        .cmd = get_hd_command(SPI_CMD_HD_INT0, flags),\n        .flags = flags,\n    };\n    return spi_device_transmit(spi, &end_t);\n}\n\nesp_err_t essl_spi_rddma(spi_device_handle_t spi, uint8_t *out_data, int len, int seg_len, uint32_t flags)\n{\n    if (!esp_ptr_dma_capable(out_data) || ((intptr_t)out_data % 4) != 0) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    seg_len = (seg_len > 0) ? seg_len : len;\n\n    uint8_t *read_ptr = out_data;\n    esp_err_t ret = ESP_OK;\n    while (len > 0) {\n        int send_len = MIN(seg_len, len);\n\n        ret = essl_spi_rddma_seg(spi, read_ptr, send_len, flags);\n        if (ret != ESP_OK) {\n            return ret;\n        }\n\n        len -= send_len;\n        read_ptr += send_len;\n    }\n    return essl_spi_rddma_done(spi, flags);\n}\n\nesp_err_t essl_spi_wrdma_seg(spi_device_handle_t spi, const uint8_t *data, int seg_len, uint32_t flags)\n{\n    spi_transaction_ext_t t = {\n        .base = {\n            .cmd = get_hd_command(SPI_CMD_HD_WRDMA, flags),\n            .length = seg_len * 8,\n            .tx_buffer = data,\n            .flags = flags | SPI_TRANS_VARIABLE_DUMMY,\n        },\n        .dummy_bits = get_hd_dummy_bits(flags),\n    };\n    return spi_device_transmit(spi, (spi_transaction_t *)&t);\n}\n\nesp_err_t essl_spi_wrdma_done(spi_device_handle_t spi, uint32_t flags)\n{\n    spi_transaction_t end_t = {\n        .cmd = get_hd_command(SPI_CMD_HD_WR_END, flags),\n        .flags = flags,\n    };\n    return spi_device_transmit(spi, &end_t);\n}\n\nesp_err_t essl_spi_wrdma(spi_device_handle_t spi, const uint8_t *data, int len, int seg_len, uint32_t flags)\n{\n    if (!esp_ptr_dma_capable(data)) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    seg_len = (seg_len > 0) ? seg_len : len;\n\n    while (len > 0) {\n        int send_len = MIN(seg_len, len);\n\n        esp_err_t ret = essl_spi_wrdma_seg(spi, data, send_len, flags);\n        if (ret != ESP_OK) {\n            return ret;\n        }\n\n        len -= send_len;\n        data += send_len;\n    }\n\n    return essl_spi_wrdma_done(spi, flags);\n}\n\nesp_err_t essl_spi_int(spi_device_handle_t spi, int int_n, uint32_t flags)\n{\n    spi_transaction_t end_t = {\n        .cmd = get_hd_command(SPI_CMD_HD_INT0 + int_n, flags),\n        .flags = flags,\n    };\n    return spi_device_transmit(spi, &end_t);\n}\n\n//------------------------------------ APPEND MODE ----------------------------------//\nstatic uint32_t essl_spi_get_rx_data_size(void *arg);\nstatic esp_err_t essl_spi_update_rx_data_size(void *arg, uint32_t wait_ms);\nstatic uint32_t essl_spi_get_tx_buffer_num(void *arg);\nstatic esp_err_t essl_spi_update_tx_buffer_num(void *arg, uint32_t wait_ms);\n\nesp_err_t essl_spi_init_dev(essl_handle_t *out_handle, const essl_spi_config_t *init_config)\n{\n    ESP_RETURN_ON_FALSE(init_config->spi, ESP_ERR_INVALID_STATE, TAG, \"Check SPI initialization first\");\n    ESP_RETURN_ON_FALSE(init_config->tx_sync_reg <= (SOC_SPI_MAXIMUM_BUFFER_SIZE - 1) * 4, ESP_ERR_INVALID_ARG, TAG, \"GPSPI supports %d-byte-width internal registers\", SOC_SPI_MAXIMUM_BUFFER_SIZE);\n    ESP_RETURN_ON_FALSE(init_config->rx_sync_reg <= (SOC_SPI_MAXIMUM_BUFFER_SIZE - 1) * 4, ESP_ERR_INVALID_ARG, TAG, \"GPSPI supports %d-byte-width internal registers\", SOC_SPI_MAXIMUM_BUFFER_SIZE);\n    ESP_RETURN_ON_FALSE(init_config->tx_sync_reg != init_config->rx_sync_reg, ESP_ERR_INVALID_ARG, TAG, \"Should use different word of registers for synchronization\");\n\n    essl_spi_context_t *context = calloc(1, sizeof(essl_spi_context_t));\n    essl_dev_t *dev = calloc(1, sizeof(essl_dev_t));\n    if (!context || !dev) {\n        free(context);\n        free(dev);\n        return ESP_ERR_NO_MEM;\n    }\n\n    *context = (essl_spi_context_t) {\n        .spi = *init_config->spi,\n        .master_out.tx_buffer_size = init_config->tx_buf_size,\n        .master_out.tx_sync_reg = init_config->tx_sync_reg,\n        .master_in.rx_sync_reg = init_config->rx_sync_reg\n    };\n\n    *dev = ESSL_SPI_DEFAULT_DEV_FUNC();\n    dev->args = context;\n\n    *out_handle = dev;\n\n    return ESP_OK;\n}\n\nesp_err_t essl_spi_deinit_dev(essl_handle_t handle)\n{\n    ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_STATE, TAG, \"ESSL SPI is not in use\");\n    free(handle->args);\n    free(handle);\n    return ESP_OK;\n}\n\nvoid essl_spi_reset_cnt(void *arg)\n{\n    essl_spi_context_t *ctx = arg;\n    if (ctx) {\n        ctx->master_out.sent_buf_num = 0;\n        ctx->master_in.received_bytes = 0;\n    }\n}\n\n//------------------------------------ RX ----------------------------------//\nesp_err_t essl_spi_read_reg(void *arg, uint8_t addr, uint8_t *out_value, uint32_t wait_ms)\n{\n    essl_spi_context_t *ctx = arg;\n    ESP_RETURN_ON_FALSE(arg, ESP_ERR_INVALID_STATE, TAG, \"Check ESSL SPI initialization first\");\n    uint8_t reserved_1_head = ctx->master_out.tx_sync_reg < ctx->master_in.rx_sync_reg ? ctx->master_out.tx_sync_reg : ctx->master_in.rx_sync_reg;\n    uint8_t reserved_1_tail = reserved_1_head + 3;\n    uint8_t reserved_2_head = ctx->master_out.tx_sync_reg < ctx->master_in.rx_sync_reg ? ctx->master_in.rx_sync_reg : ctx->master_out.tx_sync_reg;\n    uint8_t reserved_2_tail = reserved_2_head + 3;\n    ESP_RETURN_ON_FALSE(addr < reserved_1_head || (addr > reserved_1_tail && addr < reserved_2_head) || addr > reserved_2_tail, ESP_ERR_INVALID_ARG, TAG, \"Invalid address\");\n\n    return essl_spi_rdbuf(ctx->spi, out_value, addr, sizeof(uint8_t), 0);\n}\n\nstatic uint32_t essl_spi_get_rx_data_size(void *arg)\n{\n    essl_spi_context_t *ctx = arg;\n    ESP_LOGV(TAG, \"slave tx buffer: %d bytes, master has read: %d bytes\", ctx->master_in.slave_tx_bytes, ctx->master_in.received_bytes);\n    return ctx->master_in.slave_tx_bytes - ctx->master_in.received_bytes;\n}\n\nstatic esp_err_t essl_spi_update_rx_data_size(void *arg, uint32_t wait_ms)\n{\n    essl_spi_context_t *ctx = arg;\n    uint32_t updated_size = 0;\n    uint32_t previous_size = 0;\n    esp_err_t ret;\n\n    ret = essl_spi_rdbuf_polling(ctx->spi, (uint8_t *)&previous_size, ctx->master_in.rx_sync_reg, sizeof(uint32_t), 0);\n    if (ret != ESP_OK) {\n        return ret;\n    }\n\n    /**\n     * Read until the last 2 reading result are same. Reason:\n     * SPI transaction is carried on per 1 Byte. So when Master is reading the shared register, if the\n     * register value is changed by Slave at this time, Master may get wrong data.\n     */\n    while (1) {\n        ret = essl_spi_rdbuf_polling(ctx->spi, (uint8_t *)&updated_size, ctx->master_in.rx_sync_reg, sizeof(uint32_t), 0);\n        if (ret != ESP_OK) {\n            return ret;\n        }\n        if (updated_size == previous_size) {\n            ctx->master_in.slave_tx_bytes = updated_size;\n            ESP_LOGV(TAG, \"updated: slave prepared tx buffer is: %d bytes\", (unsigned int)updated_size);\n            return ret;\n        }\n        previous_size = updated_size;\n    }\n}\n\nesp_err_t essl_spi_get_packet(void *arg, void *out_data, size_t size, uint32_t wait_ms)\n{\n    ESP_RETURN_ON_FALSE(arg, ESP_ERR_INVALID_STATE, TAG, \"Check ESSL SPI initialization first\");\n    if (!esp_ptr_dma_capable(out_data) || ((intptr_t)out_data % 4) != 0) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    essl_spi_context_t *ctx = arg;\n    esp_err_t ret;\n\n    if (essl_spi_get_rx_data_size(arg) < size) {\n        /**\n         * For realistic situation, usually there will be a large overhead (Slave will load large amount of data),\n         * so here we only update the Slave's TX size when the last-updated size is smaller than what Master requires.\n         */\n        ret = essl_spi_update_rx_data_size(arg, wait_ms);\n        if (ret != ESP_OK) {\n            return ret;\n        }\n\n        //Slave still did not load enough size of buffer\n        if (essl_spi_get_rx_data_size(arg) < size) {\n            ESP_LOGV(TAG, \"slave buffer: %d is not enough, %d is required\", ctx->master_in.slave_tx_bytes, ctx->master_in.received_bytes + size);\n            return ESP_ERR_NOT_FOUND;\n        }\n    }\n\n    ESP_LOGV(TAG, \"get_packet: size to read is: %d\", size);\n    ret = essl_spi_rddma_seg(ctx->spi, out_data, size, 0);\n    if (ret != ESP_OK) {\n        return ret;\n    }\n    ctx->master_in.received_bytes += size;\n\n    return ESP_OK;\n}\n\n//------------------------------------ TX ----------------------------------//\nesp_err_t essl_spi_write_reg(void *arg, uint8_t addr, uint8_t value, uint8_t *out_value, uint32_t wait_ms)\n{\n    essl_spi_context_t *ctx = arg;\n    ESP_RETURN_ON_FALSE(arg, ESP_ERR_INVALID_STATE, TAG, \"Check ESSL SPI initialization first\");\n    uint8_t reserved_1_head = ctx->master_out.tx_sync_reg < ctx->master_in.rx_sync_reg ? ctx->master_out.tx_sync_reg : ctx->master_in.rx_sync_reg;\n    uint8_t reserved_1_tail = reserved_1_head + 3;\n    uint8_t reserved_2_head = ctx->master_out.tx_sync_reg < ctx->master_in.rx_sync_reg ? ctx->master_in.rx_sync_reg : ctx->master_out.tx_sync_reg;\n    uint8_t reserved_2_tail = reserved_2_head + 3;\n    ESP_RETURN_ON_FALSE(addr < reserved_1_head || (addr > reserved_1_tail && addr < reserved_2_head) || addr > reserved_2_tail, ESP_ERR_INVALID_ARG, TAG, \"Invalid address\");\n    ESP_RETURN_ON_FALSE(out_value == NULL, ESP_ERR_NOT_SUPPORTED, TAG, \"This feature is not supported\");\n\n    return essl_spi_wrbuf(ctx->spi, &value, addr, sizeof(uint8_t), 0);\n}\n\nstatic uint32_t essl_spi_get_tx_buffer_num(void *arg)\n{\n    essl_spi_context_t *ctx = arg;\n    ESP_LOGV(TAG, \"slave rx buffer: %d, master has sent: %d\", ctx->master_out.slave_rx_buf_num, ctx->master_out.sent_buf_num);\n    return ctx->master_out.slave_rx_buf_num - ctx->master_out.sent_buf_num;\n}\n\nstatic esp_err_t essl_spi_update_tx_buffer_num(void *arg, uint32_t wait_ms)\n{\n    essl_spi_context_t *ctx = arg;\n    uint32_t updated_num = 0;\n    uint32_t previous_size = 0;\n    esp_err_t ret;\n\n    ret = essl_spi_rdbuf_polling(ctx->spi, (uint8_t *)&previous_size, ctx->master_out.tx_sync_reg, sizeof(uint32_t), 0);\n    if (ret != ESP_OK) {\n        return ret;\n    }\n\n    /**\n     * Read until the last 2 reading result are same. Reason:\n     * SPI transaction is carried on per 1 Byte. So when Master is reading the shared register, if the\n     * register value is changed by Slave at this time, Master may get wrong data.\n     */\n    while (1) {\n        ret = essl_spi_rdbuf_polling(ctx->spi, (uint8_t *)&updated_num, ctx->master_out.tx_sync_reg, sizeof(uint32_t), 0);\n        if (ret != ESP_OK) {\n            return ret;\n        }\n        if (updated_num == previous_size) {\n            ctx->master_out.slave_rx_buf_num = updated_num;\n            ESP_LOGV(TAG, \"updated: slave prepared rx buffer: %d\", (unsigned int)updated_num);\n            return ret;\n        }\n        previous_size = updated_num;\n    }\n}\n\nesp_err_t essl_spi_send_packet(void *arg, const void *data, size_t size, uint32_t wait_ms)\n{\n    ESP_RETURN_ON_FALSE(arg, ESP_ERR_INVALID_STATE, TAG, \"Check ESSL SPI initialization first\");\n    if (!esp_ptr_dma_capable(data)) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    essl_spi_context_t *ctx = arg;\n    esp_err_t ret;\n    uint32_t buf_num_to_use = (size + ctx->master_out.tx_buffer_size - 1) / ctx->master_out.tx_buffer_size;\n\n    if (essl_spi_get_tx_buffer_num(arg) < buf_num_to_use) {\n        /**\n         * For realistic situation, usually there will be a large overhead (Slave will load enough number of RX buffers),\n         * so here we only update the Slave's RX buffer number when the last-updated number is smaller than what Master requires.\n         */\n        ret = essl_spi_update_tx_buffer_num(arg, wait_ms);\n        if (ret != ESP_OK) {\n            return ret;\n        }\n        //Slave still did not load a sufficient amount of buffers\n        if (essl_spi_get_tx_buffer_num(arg) < buf_num_to_use) {\n            ESP_LOGV(TAG, \"slave buffer: %\"PRIu32\" is not enough, %\"PRIu32\" is required\", (uint32_t)ctx->master_out.slave_rx_buf_num, (uint32_t)ctx->master_out.sent_buf_num + buf_num_to_use);\n            return ESP_ERR_NOT_FOUND;\n        }\n    }\n\n    ESP_LOGV(TAG, \"send_packet: size to write is: %zu\", size);\n    ret = essl_spi_wrdma_seg(ctx->spi, data, size, 0);\n    if (ret != ESP_OK) {\n        return ret;\n    }\n    ctx->master_out.sent_buf_num += buf_num_to_use;\n\n    return essl_spi_wrdma_done(ctx->spi, 0);\n}\n"
  },
  {
    "path": "esp_serial_slave_link/idf_component.yml",
    "content": "version: \"1.1.2\"\ndescription: Espressif Serial Slave Link Library\nurl: https://github.com/espressif/idf-extra-components/tree/master/esp_serial_slave_link\nrepository: https://github.com/espressif/idf-extra-components.git\ndocumentation: https://espressif.github.io/idf-extra-components/latest/esp_serial_slave_link/index.html\nissues: https://github.com/espressif/idf-extra-components/issues\ndependencies:\n    idf: \">=5.0\"\n"
  },
  {
    "path": "esp_serial_slave_link/include/esp_serial_slave_link/essl.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n\n#include \"esp_err.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct essl_dev_t;\n/// Handle of an ESSL device\ntypedef struct essl_dev_t *essl_handle_t;\n\n/**\n * @brief Initialize the slave.\n *\n * @param handle Handle of an ESSL device.\n * @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.\n * @return\n *        - ESP_OK:                If success\n *        - ESP_ERR_NOT_SUPPORTED: Current device does not support this function.\n *        - Other value returned from lower layer `init`.\n */\nesp_err_t essl_init(essl_handle_t handle, uint32_t wait_ms);\n\n/**\n * @brief Wait for interrupt of an ESSL slave device.\n *\n * @param handle Handle of an ESSL device.\n * @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.\n *\n * @return\n *      - ESP_OK:                If success\n *      - ESP_ERR_NOT_SUPPORTED: Current device does not support this function.\n *      - One of the error codes from SDMMC host controller\n */\nesp_err_t essl_wait_for_ready(essl_handle_t handle, uint32_t wait_ms);\n\n/**\n * @brief Get buffer num for the host to send data to the slave. The buffers are size of ``buffer_size``.\n *\n * @param handle Handle of a ESSL device.\n * @param out_tx_num Output of buffer num that host can send data to ESSL slave.\n * @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.\n *\n * @return\n *      - ESP_OK:                Success\n *      - ESP_ERR_NOT_SUPPORTED: This API is not supported in this mode\n *      - One of the error codes from SDMMC/SPI host controller\n */\nesp_err_t essl_get_tx_buffer_num(essl_handle_t handle, uint32_t *out_tx_num, uint32_t wait_ms);\n\n/**\n * @brief Get the size, in bytes, of the data that the ESSL slave is ready to send\n *\n * @param handle Handle of an ESSL device.\n * @param out_rx_size Output of data size to read from slave, in bytes\n * @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.\n *\n * @return\n *      - ESP_OK:                Success\n *      - ESP_ERR_NOT_SUPPORTED: This API is not supported in this mode\n *      - One of the error codes from SDMMC/SPI host controller\n */\nesp_err_t essl_get_rx_data_size(essl_handle_t handle, uint32_t *out_rx_size, uint32_t wait_ms);\n\n\n/**\n * @brief Reset the counters of this component. Usually you don't need to do this unless you know the slave is reset.\n *\n * @param handle Handle of an ESSL device.\n *\n * @return\n *        - ESP_OK:                Success\n *        - ESP_ERR_NOT_SUPPORTED: This API is not supported in this mode\n *        - ESP_ERR_INVALID_ARG:   Invalid argument, handle is not init.\n */\nesp_err_t essl_reset_cnt(essl_handle_t handle);\n\n/**\n * @brief Send a packet to the ESSL Slave. The Slave receives the packet into buffers whose size is ``buffer_size`` (configured during initialization).\n *\n * @param handle Handle of an ESSL device.\n * @param start Start address of the packet to send\n * @param length Length of data to send, if the packet is over-size, the it will be divided into blocks and hold into different buffers automatically.\n * @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.\n *\n * @return\n *      - ESP_OK Success\n *      - ESP_ERR_INVALID_ARG:   Invalid argument, handle is not init or other argument is not valid.\n *      - ESP_ERR_TIMEOUT:       No buffer to use, or error ftrom SDMMC host controller.\n *      - ESP_ERR_NOT_FOUND:     Slave is not ready for receiving.\n *      - ESP_ERR_NOT_SUPPORTED: This API is not supported in this mode\n *      - One of the error codes from SDMMC/SPI host controller.\n */\nesp_err_t essl_send_packet(essl_handle_t handle, const void *start, size_t length, uint32_t wait_ms);\n\n/**\n * @brief Get a packet from ESSL slave.\n *\n * @param handle Handle of an ESSL device.\n * @param[out] out_data Data output address\n * @param size The size of the output buffer, if the buffer is smaller than the size of data to receive from slave, the driver returns ``ESP_ERR_NOT_FINISHED``\n * @param[out] out_length Output of length the data actually received from slave.\n * @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.\n *\n * @return\n *     - ESP_OK Success:        All the data has been read from the slave.\n *     - ESP_ERR_INVALID_ARG:   Invalid argument, The handle is not initialized or the other arguments are invalid.\n *     - ESP_ERR_NOT_FINISHED:  Read was successful, but there is still data remaining.\n *     - ESP_ERR_NOT_FOUND:     Slave is not ready to send data.\n *     - ESP_ERR_NOT_SUPPORTED: This API is not supported in this mode\n *     - One of the error codes from SDMMC/SPI host controller.\n */\nesp_err_t essl_get_packet(essl_handle_t handle, void *out_data, size_t size, size_t *out_length, uint32_t wait_ms);\n\n/**\n * @brief Write general purpose R/W registers (8-bit) of ESSL slave.\n *\n * @param handle Handle of an ESSL device.\n * @param addr Address of register to write. For SDIO, valid address: 0-59. For SPI, see ``essl_spi.h``\n * @param value Value to write to the register.\n * @param value_o Output of the returned written value.\n * @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.\n *\n * @note sdio 28-31 are reserved, the lower API helps to skip.\n *\n * @return\n *      - ESP_OK Success\n *      - One of the error codes from SDMMC/SPI host controller\n */\nesp_err_t essl_write_reg(essl_handle_t handle, uint8_t addr, uint8_t value, uint8_t *value_o, uint32_t wait_ms);\n\n/**\n * @brief Read general purpose R/W registers (8-bit) of ESSL slave.\n *\n * @param handle Handle of a ``essl`` device.\n * @param add Address of register to read. For SDIO, Valid address: 0-27, 32-63 (28-31 reserved, return interrupt bits on read). For SPI, see ``essl_spi.h``\n * @param value_o Output value read from the register.\n * @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.\n *\n * @return\n *      - ESP_OK Success\n *      - One of the error codes from SDMMC/SPI host controller\n */\nesp_err_t essl_read_reg(essl_handle_t handle, uint8_t add, uint8_t *value_o, uint32_t wait_ms);\n\n/**\n * @brief wait for an interrupt of the slave\n *\n * @param handle Handle of an ESSL device.\n * @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.\n *\n * @return\n *        - ESP_OK:                If interrupt is triggered.\n *        - ESP_ERR_NOT_SUPPORTED: Current device does not support this function.\n *        - ESP_ERR_TIMEOUT:       No interrupts before timeout.\n */\nesp_err_t essl_wait_int(essl_handle_t handle, uint32_t wait_ms);\n\n/**\n * @brief Clear interrupt bits of ESSL slave. All the bits set in the mask will be cleared, while other bits will stay the same.\n *\n * @param handle Handle of an ESSL device.\n * @param intr_mask Mask of interrupt bits to clear.\n * @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.\n *\n * @return\n *        - ESP_OK:                Success\n *        - ESP_ERR_NOT_SUPPORTED: Current device does not support this function.\n *        - One of the error codes from SDMMC host controller\n */\nesp_err_t essl_clear_intr(essl_handle_t handle, uint32_t intr_mask, uint32_t wait_ms);\n\n/**\n * @brief Get interrupt bits of ESSL slave.\n *\n * @param handle Handle of an ESSL device.\n * @param intr_raw Output of the raw interrupt bits. Set to NULL if only masked bits are read.\n * @param intr_st Output of the masked interrupt bits. set to NULL if only raw bits are read.\n * @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.\n *\n * @return\n *        - ESP_OK:                Success\n *        - ESP_INVALID_ARG:       If both ``intr_raw`` and ``intr_st`` are NULL.\n *        - ESP_ERR_NOT_SUPPORTED: Current device does not support this function.\n *        - One of the error codes from SDMMC host controller\n */\nesp_err_t essl_get_intr(essl_handle_t handle, uint32_t *intr_raw, uint32_t *intr_st, uint32_t wait_ms);\n\n/**\n * @brief Set interrupt enable bits of ESSL slave. The slave only sends interrupt on the line when there is a bit both the raw status and the enable are set.\n *\n * @param handle Handle of an ESSL device.\n * @param ena_mask Mask of the interrupt bits to enable.\n * @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.\n *\n * @return\n *        - ESP_OK:                Success\n *        - ESP_ERR_NOT_SUPPORTED: Current device does not support this function.\n *        - One of the error codes from SDMMC host controller\n */\nesp_err_t essl_set_intr_ena(essl_handle_t handle, uint32_t ena_mask, uint32_t wait_ms);\n\n/**\n * @brief Get interrupt enable bits of ESSL slave.\n *\n * @param handle Handle of an ESSL device.\n * @param ena_mask_o Output of interrupt bit enable mask.\n * @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.\n *\n * @return\n *      - ESP_OK Success\n *      - One of the error codes from SDMMC host controller\n */\nesp_err_t essl_get_intr_ena(essl_handle_t handle, uint32_t *ena_mask_o, uint32_t wait_ms);\n\n/**\n * @brief Send interrupts to slave. Each bit of the interrupt will be triggered.\n *\n * @param handle Handle of an ESSL device.\n * @param intr_mask Mask of interrupt bits to send to slave.\n * @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.\n *\n * @return\n *        - ESP_OK:                Success\n *        - ESP_ERR_NOT_SUPPORTED: Current device does not support this function.\n *        - One of the error codes from SDMMC host controller\n */\nesp_err_t essl_send_slave_intr(essl_handle_t handle, uint32_t intr_mask, uint32_t wait_ms);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_serial_slave_link/include/esp_serial_slave_link/essl_sdio.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// ESP SDIO slave link used by the ESP host to communicate with ESP SDIO slave.\n\n#pragma once\n\n#include \"esp_err.h\"\n#include \"driver/sdmmc_types.h\"\n#include \"driver/sdmmc_host.h\"\n\n#include \"esp_serial_slave_link/essl.h\"\n#include \"essl_sdio_defs.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/// Configuration for the ESSL SDIO device\ntypedef struct {\n    sdmmc_card_t *card;     ///< The initialized sdmmc card pointer of the slave.\n    int recv_buffer_size;   ///< The pre-negotiated recv buffer size used by both the host and the slave.\n} essl_sdio_config_t;\n\n\n/**\n * @brief Initialize the ESSL SDIO device and get its handle.\n *\n * @param out_handle Output of the handle.\n * @param config    Configuration for the ESSL SDIO device.\n * @return\n *  - ESP_OK: on success\n *  - ESP_ERR_NO_MEM: memory exhausted.\n */\nesp_err_t essl_sdio_init_dev(essl_handle_t *out_handle, const essl_sdio_config_t *config);\n\n/**\n * @brief Deinitialize and free the space used by the ESSL SDIO device.\n *\n * @param handle Handle of the ESSL SDIO device to deinit.\n * @return\n *  - ESP_OK: on success\n *  - ESP_ERR_INVALID_ARG: wrong handle passed\n */\nesp_err_t essl_sdio_deinit_dev(essl_handle_t handle);\n\n// Please call `essl_` functions without `sdio` instead of calling these functions directly.\n/** @cond */\n/**\n * @brief SDIO Initialize process of an ESSL SDIO slave device.\n *\n * @param arg Context of the ``essl`` component. Send to other functions later.\n * @param wait_ms Time to wait before operation is done, in ms.\n *\n * @return\n *      - ESP_OK if success\n *      - One of the error codes from SDMMC host controller\n */\nesp_err_t essl_sdio_init(void *arg, uint32_t wait_ms);\n\n/**\n * @brief Wait for interrupt of an ESSL SDIO slave device.\n *\n * @param arg Context of the ``essl`` component.\n * @param wait_ms Time to wait before operation is done, in ms.\n *\n * @return\n *      - ESP_OK if success\n *      - One of the error codes from SDMMC host controller\n */\nesp_err_t essl_sdio_wait_for_ready(void *arg, uint32_t wait_ms);\n\n/**\n * @brief Get buffer num for the host to send data to the slave. The buffers are size of ``buffer_size``.\n *\n * @param arg Context of the component.\n *\n * @return\n *      - ESP_OK Success\n *      - One of the error codes from SDMMC host controller\n */\nuint32_t essl_sdio_get_tx_buffer_num(void *arg);\n\n/**\n * @brief Get amount of data the ESSL SDIO slave preparing to send to host.\n *\n * @param arg Context of the component.\n *\n * @return\n *      - ESP_OK Success\n *      - One of the error codes from SDMMC host controller\n */\nuint32_t essl_sdio_get_rx_data_size(void *arg);\n\n/**\n * @brief Send a packet to the ESSL SDIO slave. The slave receive the packet into buffers whose size is ``buffer_size`` in the arg.\n *\n * @param arg Context of the component.\n * @param start Start address of the packet to send\n * @param length Length of data to send, if the packet is over-size, the it will be divided into blocks and hold into different buffers automatically.\n * @param wait_ms Time to wait before timeout, in ms.\n *\n * @return\n *      - ESP_OK Success\n *      - ESP_ERR_TIMEOUT No buffer to use, or error ftrom SDMMC host controller\n *      - One of the error codes from SDMMC host controller\n */\nesp_err_t essl_sdio_send_packet(void *arg, const void *start, size_t length, uint32_t wait_ms);\n\n/**\n * @brief Get a packet from an ESSL SDIO slave.\n *\n * @param arg Context of the component.\n * @param[out] out_data Data output address\n * @param size The size of the output buffer, if the buffer is smaller than the size of data to receive from slave, the driver returns ``ESP_ERR_NOT_FINISHED``\n * @param wait_ms Time to wait before timeout, in ms.\n *\n * @return\n *     - ESP_OK Success, all the data are read from the slave.\n *     - ESP_ERR_NOT_FINISHED Read success, while there're data remaining.\n *     - One of the error codes from SDMMC host controller\n */\nesp_err_t essl_sdio_get_packet(void *arg, void *out_data, size_t size, uint32_t wait_ms);\n\n/**\n * @brief Wait for the interrupt from the SDIO slave.\n *\n * @param arg Context of the component.\n * @param wait_ms Time to wait before timeout, in ms.\n * @return\n *  - ESP_ERR_NOT_SUPPORTED: if the interrupt line is not initialized properly.\n *  - ESP_OK: if interrupt happened\n *  - ESP_ERR_TIMEOUT: if timeout before interrupt happened.\n *  - or other values returned from the `io_int_wait` member of the `card->host` structure.\n */\nesp_err_t essl_sdio_wait_int(void *arg, uint32_t wait_ms);\n\n/**\n * @brief Clear interrupt bits of an ESSL SDIO slave. All the bits set in the mask will be cleared, while other bits will stay the same.\n *\n * @param arg Context of the component.\n * @param intr_mask Mask of interrupt bits to clear.\n * @param wait_ms Time to wait before timeout, in ms.\n *\n * @return\n *      - ESP_OK Success\n *      - One of the error codes from SDMMC host controller\n */\nesp_err_t essl_sdio_clear_intr(void *arg, uint32_t intr_mask, uint32_t wait_ms);\n\n/**\n * @brief Get interrupt bits of an ESSL SDIO slave.\n *\n * @param arg Context of the component.\n * @param intr_raw Output of the raw interrupt bits. Set to NULL if only masked bits are read.\n * @param intr_st Output of the masked interrupt bits. set to NULL if only raw bits are read.\n * @param wait_ms Time to wait before timeout, in ms.\n *\n * @return\n *      - ESP_OK Success\n *      - ESP_INVALID_ARG   if both ``intr_raw`` and ``intr_st`` are NULL.\n *      - One of the error codes from SDMMC host controller\n */\nesp_err_t essl_sdio_get_intr(void *arg, uint32_t *intr_raw, uint32_t *intr_st, uint32_t wait_ms);\n\n/**\n * @brief Set interrupt enable bits of an ESSL SDIO slave. The slave only sends interrupt on the line when there is a bit both the raw status and the enable are set.\n *\n * @param arg Context of the component.\n * @param ena_mask Mask of the interrupt bits to enable.\n * @param wait_ms Time to wait before timeout, in ms.\n *\n * @return\n *      - ESP_OK Success\n *      - One of the error codes from SDMMC host controller\n */\nesp_err_t essl_sdio_set_intr_ena(void *arg, uint32_t ena_mask, uint32_t wait_ms);\n\n/**\n * @brief Get interrupt enable bits of an ESSL SDIO slave.\n *\n * @param arg Context of the component.\n * @param ena_mask_o Output of interrupt bit enable mask.\n * @param wait_ms Time to wait before timeout, in ms.\n *\n * @return\n *      - ESP_OK Success\n *      - One of the error codes from SDMMC host controller\n */\nesp_err_t essl_sdio_get_intr_ena(void *arg, uint32_t *ena_mask_o, uint32_t wait_ms);\n\n/**\n * @brief Write general purpose R/W registers (8-bit) of an ESSL SDIO slave.\n *\n * @param arg Context of the component.\n * @param addr Address of register to write. Valid address: 0-27, 32-63 (28-31 reserved).\n * @param value Value to write to the register.\n * @param wait_ms Time to wait before timeout, in ms.\n *\n * @return\n *      - ESP_OK Success\n *      - ESP_ERR_INVALID_ARG Address not valid.\n *      - One of the error codes from SDMMC host controller\n */\nesp_err_t essl_sdio_write_reg(void *arg, uint8_t addr, uint8_t value, uint8_t *value_o, uint32_t wait_ms);\n\n/**\n * @brief Read general purpose R/W registers (8-bit) of an ESSL SDIO slave.\n *\n * @param arg Context of the component.\n * @param add Address of register to read. Valid address: 0-27, 32-63 (28-31 reserved, return interrupt bits on read).\n * @param value Output value read from the register.\n * @param wait_ms Time to wait before timeout, in ms.\n *\n * @return\n *      - ESP_OK Success\n *      - ESP_ERR_INVALID_ARG Address not valid.\n *      - One of the error codes from SDMMC host controller\n */\nesp_err_t essl_sdio_read_reg(void *arg, uint8_t add, uint8_t *value_o, uint32_t wait_ms);\n\n/**\n * @brief Send interrupts to slave. Each bit of the interrupt will be triggered.\n *\n * @param arg Context of the component.\n * @param intr_mask Mask of interrupt bits to send to slave.\n * @param wait_ms Time to wait before timeout, in ms.\n *\n * @return\n *      - ESP_OK Success\n *      - One of the error codes from SDMMC host controller\n */\nesp_err_t essl_sdio_send_slave_intr(void *arg, uint32_t intr_mask, uint32_t wait_ms);\n\n/**\n * @brief Reset the counter on the host side.\n *\n * @note Only call when you know the slave has reset its counter, or there will be inconsistent between the master and the slave.\n *\n * @param arg  Context of the component.\n */\nvoid essl_sdio_reset_cnt(void *arg);\n\n/** @endcond */\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_serial_slave_link/include/esp_serial_slave_link/essl_sdio_defs.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n/**\n * This file contains SDIO Slave hardware specific requirements\n */\n\n#include <stdint.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct {\n    //interrupts\n    uint32_t new_packet_intr_mask;\n} essl_sdio_def_t;\n\n/// Definitions of ESP32 SDIO Slave hardware\nextern essl_sdio_def_t ESSL_SDIO_DEF_ESP32;\n/// Definitions of ESP32C6 SDIO Slave hardware\nextern essl_sdio_def_t ESSL_SDIO_DEF_ESP32C6;\n\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_serial_slave_link/include/esp_serial_slave_link/essl_spi.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include \"esp_err.h\"\n#include \"driver/spi_master.h\"\n\n#include \"esp_serial_slave_link/essl.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/// Configuration of ESSL SPI device\ntypedef struct {\n    spi_device_handle_t *spi;           ///< Pointer to SPI device handle.\n    uint32_t            tx_buf_size;    ///< The pre-negotiated Master TX buffer size used by both the host and the slave.\n    uint8_t             tx_sync_reg;    ///< The pre-negotiated register ID for Master-TX-SLAVE-RX synchronization. 1 word (4 Bytes) will be reserved for the synchronization.\n    uint8_t             rx_sync_reg;    ///< The pre-negotiated register ID for Master-RX-Slave-TX synchronization. 1 word (4 Bytes) will be reserved for the synchronization.\n} essl_spi_config_t;\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n// APIs for DMA Append Mode\n// This mode has a better performance for continuous Half Duplex SPI transactions.\n//\n// * You can use the ``essl_spi_init_dev`` and ``essl_spi_deinit_dev`` together with APIs in ``essl.h`` to communicate\n//   with ESP SPI Slaves in Half Duplex DMA Append Mode. See example for SPI SLAVE HALFDUPLEX APPEND MODE.\n// * You can also use the following APIs to create your own logic.\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n/**\n * @brief Initialize the ESSL SPI device function list and get its handle\n *\n * @param[out] out_handle    Output of the handle\n * @param      init_config   Configuration for the ESSL SPI device\n * @return\n *        - ESP_OK:                On success\n *        - ESP_ERR_NO_MEM:        Memory exhausted\n *        - ESP_ERR_INVALID_STATE: SPI driver is not initialized\n *        - ESP_ERR_INVALID_ARG:   Wrong register ID\n */\nesp_err_t essl_spi_init_dev(essl_handle_t *out_handle, const essl_spi_config_t *init_config);\n\n/**\n * @brief Deinitialize the ESSL SPI device and free the memory used by the device\n *\n * @param handle    Handle of the ESSL SPI device\n * @return\n *        - ESP_OK:                On success\n *        - ESP_ERR_INVALID_STATE: ESSL SPI is not in use\n */\nesp_err_t essl_spi_deinit_dev(essl_handle_t handle);\n\n/**\n * @brief Read from the shared registers\n *\n * @note The registers for Master/Slave synchronization are reserved. Do not use them. (see `rx_sync_reg` in `essl_spi_config_t`)\n *\n * @param      arg        Context of the component. (Member ``arg`` from ``essl_handle_t``)\n * @param      addr       Address of the shared registers. (Valid: 0 ~ SOC_SPI_MAXIMUM_BUFFER_SIZE, registers for M/S sync are reserved, see note1).\n * @param[out] out_value  Read buffer for the shared registers.\n * @param      wait_ms    Time to wait before timeout (reserved for future use, user should set this to 0).\n * @return\n *        - ESP_OK:                success\n *        - ESP_ERR_INVALID_STATE: ESSL SPI has not been initialized.\n *        - ESP_ERR_INVALID_ARG:   The address argument is not valid. See note 1.\n *        - or other return value from :cpp:func:`spi_device_transmit`.\n */\nesp_err_t essl_spi_read_reg(void *arg, uint8_t addr, uint8_t *out_value, uint32_t wait_ms);\n\n/**\n * @brief Get a packet from Slave\n *\n * @param      arg         Context of the component. (Member ``arg`` from ``essl_handle_t``)\n * @param[out] out_data    Output data address\n * @param      size        The size of the output data.\n * @param      wait_ms     Time to wait before timeout (reserved for future use, user should set this to 0).\n * @return\n *        - ESP_OK:                On Success\n *        - ESP_ERR_INVALID_STATE: ESSL SPI has not been initialized.\n *        - ESP_ERR_INVALID_ARG:   The output data address is neither DMA capable nor 4 byte-aligned\n *        - ESP_ERR_INVALID_SIZE:  Master requires ``size`` bytes of data but Slave did not load enough bytes.\n */\nesp_err_t essl_spi_get_packet(void *arg, void *out_data, size_t size, uint32_t wait_ms);\n\n/**\n * @brief Write to the shared registers\n *\n * @note The registers for Master/Slave synchronization are reserved. Do not use them. (see `tx_sync_reg` in `essl_spi_config_t`)\n * @note Feature of checking the actual written value (``out_value``) is not supported.\n *\n * @param      arg        Context of the component. (Member ``arg`` from ``essl_handle_t``)\n * @param      addr       Address of the shared registers. (Valid: 0 ~ SOC_SPI_MAXIMUM_BUFFER_SIZE, registers for M/S sync are reserved, see note1)\n * @param      value      Buffer for data to send, should be align to 4.\n * @param[out] out_value  Not supported, should be set to NULL.\n * @param      wait_ms    Time to wait before timeout (reserved for future use, user should set this to 0).\n * @return\n *        - ESP_OK:                success\n *        - ESP_ERR_INVALID_STATE: ESSL SPI has not been initialized.\n *        - ESP_ERR_INVALID_ARG:   The address argument is not valid. See note 1.\n *        - ESP_ERR_NOT_SUPPORTED: Should set ``out_value`` to NULL. See note 2.\n *        - or other return value from :cpp:func:`spi_device_transmit`.\n *\n */\nesp_err_t essl_spi_write_reg(void *arg, uint8_t addr, uint8_t value, uint8_t *out_value, uint32_t wait_ms);\n\n/**\n * @brief Send a packet to Slave\n *\n * @param arg        Context of the component. (Member ``arg`` from ``essl_handle_t``)\n * @param data       Address of the data to send\n * @param size       Size of the data to send.\n * @param wait_ms    Time to wait before timeout (reserved for future use, user should set this to 0).\n * @return\n *        - ESP_OK:                On success\n *        - ESP_ERR_INVALID_STATE: ESSL SPI has not been initialized.\n *        - ESP_ERR_INVALID_ARG:   The data address is not DMA capable\n *        - ESP_ERR_INVALID_SIZE:  Master will send ``size`` bytes of data but Slave did not load enough RX buffer\n */\nesp_err_t essl_spi_send_packet(void *arg, const void *data, size_t size, uint32_t wait_ms);\n\n/**\n * @brief Reset the counter in Master context\n *\n * @note Shall only be called if the slave has reset its counter. Else, Slave and Master would be desynchronized\n *\n * @param arg    Context of the component. (Member ``arg`` from ``essl_handle_t``)\n */\nvoid essl_spi_reset_cnt(void *arg);\n\n////////////////////////////////////////////////////////////////////////////////\n// Basic commands to communicate with the SPI Slave HD on ESP32-S2\n////////////////////////////////////////////////////////////////////////////////\n/**\n * @brief Read the shared buffer from the slave in ISR way\n *\n * @note The slave's HW doesn't guarantee the data in one SPI transaction is consistent. It sends data in unit of byte.\n * In other words, if the slave SW attempts to update the shared register when a rdbuf SPI transaction is in-flight,\n * the data got by the master will be the combination of bytes of different writes of slave SW.\n *\n * @note ``out_data`` should be prepared in words and in the DRAM. The buffer may be written in words\n *       by the DMA. When a byte is written, the remaining bytes in the same word will also be\n *       overwritten, even the ``len`` is shorter than a word.\n *\n * @param      spi       SPI device handle representing the slave\n * @param[out] out_data  Buffer for read data, strongly suggested to be in the DRAM and aligned to 4\n * @param      addr      Address of the slave shared buffer\n * @param      len       Length to read\n * @param      flags     `SPI_TRANS_*` flags to control the transaction mode of the transaction to send.\n * @return\n *      - ESP_OK: on success\n *      - or other return value from :cpp:func:`spi_device_transmit`.\n */\nesp_err_t essl_spi_rdbuf(spi_device_handle_t spi, uint8_t *out_data, int addr, int len, uint32_t flags);\n\n/**\n * @brief Read the shared buffer from the slave in polling way\n *\n * @note ``out_data`` should be prepared in words and in the DRAM. The buffer may be written in words\n *       by the DMA. When a byte is written, the remaining bytes in the same word will also be\n *       overwritten, even the ``len`` is shorter than a word.\n *\n * @param      spi       SPI device handle representing the slave\n * @param[out] out_data  Buffer for read data, strongly suggested to be in the DRAM and aligned to 4\n * @param      addr      Address of the slave shared buffer\n * @param      len       Length to read\n * @param      flags     `SPI_TRANS_*` flags to control the transaction mode of the transaction to send.\n * @return\n *      - ESP_OK: on success\n *      - or other return value from :cpp:func:`spi_device_transmit`.\n */\nesp_err_t essl_spi_rdbuf_polling(spi_device_handle_t spi, uint8_t *out_data, int addr, int len, uint32_t flags);\n\n/**\n * @brief Write the shared buffer of the slave in ISR way\n *\n * @note ``out_data`` should be prepared in words and in the DRAM. The buffer may be written in words\n *       by the DMA. When a byte is written, the remaining bytes in the same word will also be\n *       overwritten, even the ``len`` is shorter than a word.\n *\n * @param spi       SPI device handle representing the slave\n * @param data      Buffer for data to send, strongly suggested to be in the DRAM\n * @param addr      Address of the slave shared buffer,\n * @param len       Length to write\n * @param flags     `SPI_TRANS_*` flags to control the transaction mode of the transaction to send.\n * @return\n *      - ESP_OK: success\n *      - or other return value from :cpp:func:`spi_device_transmit`.\n */\nesp_err_t essl_spi_wrbuf(spi_device_handle_t spi, const uint8_t *data, int addr, int len, uint32_t flags);\n\n/**\n * @brief Write the shared buffer of the slave in polling way\n *\n * @note ``out_data`` should be prepared in words and in the DRAM. The buffer may be written in words\n *       by the DMA. When a byte is written, the remaining bytes in the same word will also be\n *       overwritten, even the ``len`` is shorter than a word.\n *\n * @param spi       SPI device handle representing the slave\n * @param data      Buffer for data to send, strongly suggested to be in the DRAM\n * @param addr      Address of the slave shared buffer,\n * @param len       Length to write\n * @param flags     `SPI_TRANS_*` flags to control the transaction mode of the transaction to send.\n * @return\n *      - ESP_OK: success\n *      - or other return value from :cpp:func:`spi_device_polling_transmit`.\n */\nesp_err_t essl_spi_wrbuf_polling(spi_device_handle_t spi, const uint8_t *data, int addr, int len, uint32_t flags);\n\n/**\n * @brief Receive long buffer in segments from the slave through its DMA.\n *\n * @note This function combines several :cpp:func:`essl_spi_rddma_seg` and one\n *       :cpp:func:`essl_spi_rddma_done` at the end. Used when the slave is working in segment mode.\n *\n * @param      spi       SPI device handle representing the slave\n * @param[out] out_data  Buffer to hold the received data, strongly suggested to be in the DRAM and aligned to 4\n * @param      len       Total length of data to receive.\n * @param      seg_len Length of each segment, which is not larger than the maximum transaction length\n *                allowed for the spi device. Suggested to be multiples of 4. When set < 0, means send\n *                all data in one segment (the ``rddma_done`` will still be sent.)\n * @param flags     `SPI_TRANS_*` flags to control the transaction mode of the transaction to send.\n * @return\n *      - ESP_OK: success\n *      - or other return value from :cpp:func:`spi_device_transmit`.\n */\nesp_err_t essl_spi_rddma(spi_device_handle_t spi, uint8_t *out_data, int len, int seg_len, uint32_t flags);\n\n/**\n * @brief Read one data segment from the slave through its DMA.\n *\n * @note To read long buffer, call :cpp:func:`essl_spi_rddma` instead.\n *\n * @param      spi       SPI device handle representing the slave\n * @param[out] out_data  Buffer to hold the received data. strongly suggested to be in the DRAM and aligned to 4\n * @param      seg_len   Length of this segment\n * @param      flags     `SPI_TRANS_*` flags to control the transaction mode of the transaction to send.\n * @return\n *      - ESP_OK: success\n *      - or other return value from :cpp:func:`spi_device_transmit`.\n */\nesp_err_t essl_spi_rddma_seg(spi_device_handle_t spi, uint8_t *out_data, int seg_len, uint32_t flags);\n\n/**\n * @brief Send the ``rddma_done`` command to the slave. Upon receiving this command, the slave will\n *        stop sending the current buffer even there are data unsent, and maybe prepare the next buffer to\n *        send.\n *\n * @note This is required only when the slave is working in segment mode.\n *\n * @param spi       SPI device handle representing the slave\n * @param flags     `SPI_TRANS_*` flags to control the transaction mode of the transaction to send.\n * @return\n *      - ESP_OK: success\n *      - or other return value from :cpp:func:`spi_device_transmit`.\n */\nesp_err_t essl_spi_rddma_done(spi_device_handle_t spi, uint32_t flags);\n\n/**\n * @brief Send long buffer in segments to the slave through its DMA.\n *\n * @note This function combines several :cpp:func:`essl_spi_wrdma_seg` and one\n *       :cpp:func:`essl_spi_wrdma_done` at the end. Used when the slave is working in segment mode.\n *\n * @param spi       SPI device handle representing the slave\n * @param data      Buffer for data to send, strongly suggested to be in the DRAM\n * @param len       Total length of data to send.\n * @param seg_len Length of each segment, which is not larger than the maximum transaction length\n *                allowed for the spi device. Suggested to be multiples of 4. When set < 0, means send\n *                all data in one segment (the ``wrdma_done`` will still be sent.)\n * @param flags     `SPI_TRANS_*` flags to control the transaction mode of the transaction to send.\n * @return\n *      - ESP_OK: success\n *      - or other return value from :cpp:func:`spi_device_transmit`.\n */\nesp_err_t essl_spi_wrdma(spi_device_handle_t spi, const uint8_t *data, int len, int seg_len, uint32_t flags);\n\n/**\n * @brief Send one data segment to the slave through its DMA.\n *\n * @note To send long buffer, call :cpp:func:`essl_spi_wrdma` instead.\n *\n * @param spi       SPI device handle representing the slave\n * @param data      Buffer for data to send, strongly suggested to be in the DRAM\n * @param seg_len   Length of this segment\n * @param flags     `SPI_TRANS_*` flags to control the transaction mode of the transaction to send.\n * @return\n *      - ESP_OK: success\n *      - or other return value from :cpp:func:`spi_device_transmit`.\n */\nesp_err_t essl_spi_wrdma_seg(spi_device_handle_t spi, const uint8_t *data, int seg_len, uint32_t flags);\n\n/**\n * @brief Send the ``wrdma_done`` command to the slave. Upon receiving this command, the slave will\n *        stop receiving, process the received data, and maybe prepare the next buffer to receive.\n *\n * @note This is required only when the slave is working in segment mode.\n *\n * @param spi       SPI device handle representing the slave\n * @param flags     `SPI_TRANS_*` flags to control the transaction mode of the transaction to send.\n * @return\n *      - ESP_OK: success\n *      - or other return value from :cpp:func:`spi_device_transmit`.\n */\nesp_err_t essl_spi_wrdma_done(spi_device_handle_t spi, uint32_t flags);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_serial_slave_link/include/essl_spi/esp32c2_defs.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n\n#pragma once\n\n// NOTE: From the view of master\n#define CMD_HD_WRBUF_REG    0x01\n#define CMD_HD_RDBUF_REG    0x02\n#define CMD_HD_WRDMA_REG    0x03\n#define CMD_HD_RDDMA_REG    0x04\n\n#define CMD_HD_ONEBIT_MODE  0x00\n#define CMD_HD_DOUT_MODE    0x10\n#define CMD_HD_QOUT_MODE    0x20\n#define CMD_HD_DIO_MODE     0x50\n#define CMD_HD_QIO_MODE     0xA0\n\n#define CMD_HD_SEG_END_REG  0x05\n#define CMD_HD_EN_QPI_REG   0x06\n#define CMD_HD_WR_END_REG   0x07\n#define CMD_HD_INT0_REG     0x08\n#define CMD_HD_INT1_REG     0x09\n#define CMD_HD_INT2_REG     0x0A\n#define CMD_HD_EX_QPI_REG   0xDD\n\n#define SPI_SLAVE_HD_BUFFER_SIZE 64\n"
  },
  {
    "path": "esp_serial_slave_link/include/essl_spi/esp32c3_defs.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n// NOTE: From the view of master\n#define CMD_HD_WRBUF_REG    0x01\n#define CMD_HD_RDBUF_REG    0x02\n#define CMD_HD_WRDMA_REG    0x03\n#define CMD_HD_RDDMA_REG    0x04\n\n#define CMD_HD_ONEBIT_MODE  0x00\n#define CMD_HD_DOUT_MODE    0x10\n#define CMD_HD_QOUT_MODE    0x20\n#define CMD_HD_DIO_MODE     0x50\n#define CMD_HD_QIO_MODE     0xA0\n\n#define CMD_HD_SEG_END_REG  0x05\n#define CMD_HD_EN_QPI_REG   0x06\n#define CMD_HD_WR_END_REG   0x07\n#define CMD_HD_INT0_REG     0x08\n#define CMD_HD_INT1_REG     0x09\n#define CMD_HD_INT2_REG     0x0A\n#define CMD_HD_EX_QPI_REG   0xDD\n\n#define SPI_SLAVE_HD_BUFFER_SIZE 64\n"
  },
  {
    "path": "esp_serial_slave_link/include/essl_spi/esp32s2_defs.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n// NOTE: From the view of master\n#define CMD_HD_WRBUF_REG    0x01\n#define CMD_HD_RDBUF_REG    0x02\n#define CMD_HD_WRDMA_REG    0x03\n#define CMD_HD_RDDMA_REG    0x04\n\n#define CMD_HD_ONEBIT_MODE  0x00\n#define CMD_HD_DOUT_MODE    0x10\n#define CMD_HD_QOUT_MODE    0x20\n#define CMD_HD_DIO_MODE     0x50\n#define CMD_HD_QIO_MODE     0xA0\n\n#define CMD_HD_SEG_END_REG  0x05\n#define CMD_HD_EN_QPI_REG   0x06\n#define CMD_HD_WR_END_REG   0x07\n#define CMD_HD_INT0_REG     0x08\n#define CMD_HD_INT1_REG     0x09\n#define CMD_HD_INT2_REG     0x0A\n#define CMD_HD_EX_QPI_REG   0xDD\n\n#define SPI_SLAVE_HD_BUFFER_SIZE 72\n"
  },
  {
    "path": "esp_serial_slave_link/include/essl_spi/esp32s3_defs.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n// NOTE: From the view of master\n#define CMD_HD_WRBUF_REG    0x01\n#define CMD_HD_RDBUF_REG    0x02\n#define CMD_HD_WRDMA_REG    0x03\n#define CMD_HD_RDDMA_REG    0x04\n\n#define CMD_HD_ONEBIT_MODE  0x00\n#define CMD_HD_DOUT_MODE    0x10\n#define CMD_HD_QOUT_MODE    0x20\n#define CMD_HD_DIO_MODE     0x50\n#define CMD_HD_QIO_MODE     0xA0\n\n#define CMD_HD_SEG_END_REG  0x05\n#define CMD_HD_EN_QPI_REG   0x06\n#define CMD_HD_WR_END_REG   0x07\n#define CMD_HD_INT0_REG     0x08\n#define CMD_HD_INT1_REG     0x09\n#define CMD_HD_INT2_REG     0x0A\n#define CMD_HD_EX_QPI_REG   0xDD\n\n#define SPI_SLAVE_HD_BUFFER_SIZE 64\n"
  },
  {
    "path": "esp_serial_slave_link/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(essl_test)\n"
  },
  {
    "path": "esp_serial_slave_link/test_apps/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"essl_test.c\"\n                    INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES unity)\n"
  },
  {
    "path": "esp_serial_slave_link/test_apps/main/essl_test.c",
    "content": "#include <stdio.h>\n\nvoid app_main(void)\n{\n\n}\n"
  },
  {
    "path": "esp_serial_slave_link/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/esp_serial_slave_link:\n    version: \"*\"\n    override_path: \"../..\"\n"
  },
  {
    "path": "esp_sysview/.build-test-rules.yml",
    "content": ""
  },
  {
    "path": "esp_sysview/CMakeLists.txt",
    "content": "if(CONFIG_ESP_TRACE_LIB_EXTERNAL)\n    set(include_dirs \"\")\n    set(srcs \"\")\n\n    list(APPEND include_dirs\n        src/Config\n        src/SEGGER\n        src/Sample/FreeRTOSV10.4\n        src/include)\n\n    list(APPEND srcs\n        src/SEGGER/SEGGER_SYSVIEW.c\n        src/Sample/FreeRTOSV10.4/Config/esp/SEGGER_SYSVIEW_Config_FreeRTOS.c\n        src/Sample/FreeRTOSV10.4/SEGGER_SYSVIEW_FreeRTOS.c\n        src/esp/SEGGER_RTT_esp.c\n        src/esp/SEGGER_SYSVIEW_esp.c\n        src/esp/adapter_encoder_sysview.c\n        src/ext/logging.c)\n\n    if(CONFIG_HEAP_TRACING_TOHOST)\n        list(APPEND srcs\n            src/ext/heap_trace_module.c\n            src/ext/heap_trace_tohost.c)\n        if(CONFIG_IDF_TARGET_ARCH_XTENSA)\n            set_source_files_properties(src/ext/heap_trace_tohost.c PROPERTIES COMPILE_FLAGS -Wno-frame-address)\n        endif()\n    endif()\n\n    configure_file(linker.lf.in ${CMAKE_CURRENT_BINARY_DIR}/linker.lf)\n\n    idf_component_register(SRCS \"${srcs}\"\n                        INCLUDE_DIRS \"${include_dirs}\"\n                        REQUIRES     esp_trace\n                        LDFRAGMENTS ${CMAKE_CURRENT_BINARY_DIR}/linker.lf\n                        WHOLE_ARCHIVE TRUE # Link all symbols so self-registering adapters (ESP_TRACE_REGISTER_*) are not discarded\n                        )\n\n    # Trick to include the SEGGER header into freertos component\n    # This allows freertos component to find esp_trace_freertos_impl.h\n    idf_component_get_property(freertos_lib freertos COMPONENT_LIB)\n    target_include_directories(${freertos_lib} INTERFACE ${include_dirs})\nelse()\n    idf_component_register(REQUIRES \"esp_trace\")\nendif()\n"
  },
  {
    "path": "esp_sysview/Kconfig",
    "content": "menu \"SEGGER SystemView Configuration\"\n    depends on ESP_TRACE_LIB_EXTERNAL\n    choice SEGGER_SYSVIEW_DEST_CPU\n        prompt \"CPU to trace\"\n        depends on ESP_TRACE_TRANSPORT_APPTRACE && APPTRACE_DEST_UART && !ESP_SYSTEM_SINGLE_CORE_MODE\n        default SEGGER_SYSVIEW_DEST_CPU_0\n        help\n            Define the CPU to trace.\n\n        config SEGGER_SYSVIEW_DEST_CPU_0\n            bool \"CPU0\"\n            help\n                Send tracing data for Pro CPU.\n\n        config SEGGER_SYSVIEW_DEST_CPU_1\n            bool \"CPU1\"\n            help\n                Send tracing data for App CPU.\n\n    endchoice\n\n    config SEGGER_SYSVIEW_MAX_TASKS\n        int \"Maximum supported tasks\"\n        range 1 64\n        default 16\n        help\n            Configures maximum supported tasks in sysview debug\n\n    config SEGGER_SYSVIEW_BUF_WAIT_TMO\n        int \"Trace buffer wait timeout\"\n        default 500\n        help\n            Configures timeout (in us) to wait for free space in trace buffer.\n            Set to -1 to wait forever and avoid lost events.\n\n    config SEGGER_SYSVIEW_EVT_OVERFLOW_ENABLE\n        bool \"Trace Buffer Overflow Event\"\n        default y\n        help\n            Enables \"Trace Buffer Overflow\" event.\n\n    config SEGGER_SYSVIEW_EVT_ISR_ENTER_ENABLE\n        bool \"ISR Enter Event\"\n        default y\n        help\n            Enables \"ISR Enter\" event.\n\n    config SEGGER_SYSVIEW_EVT_ISR_EXIT_ENABLE\n        bool \"ISR Exit Event\"\n        default y\n        help\n            Enables \"ISR Exit\" event.\n\n    config SEGGER_SYSVIEW_EVT_ISR_TO_SCHED_ENABLE\n        bool \"ISR Exit to Scheduler Event\"\n        default y\n        help\n            Enables \"ISR to Scheduler\" event.\n\n    config SEGGER_SYSVIEW_EVT_TASK_START_EXEC_ENABLE\n        bool \"Task Start Execution Event\"\n        default y\n        help\n            Enables \"Task Start Execution\" event.\n\n    config SEGGER_SYSVIEW_EVT_TASK_STOP_EXEC_ENABLE\n        bool \"Task Stop Execution Event\"\n        default y\n        help\n            Enables \"Task Stop Execution\" event.\n\n    config SEGGER_SYSVIEW_EVT_TASK_START_READY_ENABLE\n        bool \"Task Start Ready State Event\"\n        default y\n        help\n            Enables \"Task Start Ready State\" event.\n\n    config SEGGER_SYSVIEW_EVT_TASK_STOP_READY_ENABLE\n        bool \"Task Stop Ready State Event\"\n        default y\n        help\n            Enables \"Task Stop Ready State\" event.\n\n    config SEGGER_SYSVIEW_EVT_TASK_CREATE_ENABLE\n        bool \"Task Create Event\"\n        default y\n        help\n            Enables \"Task Create\" event.\n\n    config SEGGER_SYSVIEW_EVT_TASK_TERMINATE_ENABLE\n        bool \"Task Terminate Event\"\n        default y\n        help\n            Enables \"Task Terminate\" event.\n\n    config SEGGER_SYSVIEW_EVT_IDLE_ENABLE\n        bool \"System Idle Event\"\n        default y\n        help\n            Enables \"System Idle\" event.\n\n    config SEGGER_SYSVIEW_EVT_TIMER_ENTER_ENABLE\n        bool \"Timer Enter Event\"\n        default y\n        help\n            Enables \"Timer Enter\" event.\n\n    config SEGGER_SYSVIEW_EVT_TIMER_EXIT_ENABLE\n        bool \"Timer Exit Event\"\n        default y\n        help\n            Enables \"Timer Exit\" event.\nendmenu\n"
  },
  {
    "path": "esp_sysview/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "esp_sysview/README.md",
    "content": "# SEGGER SystemView for ESP-IDF\n\n[![Component Registry](https://components.espressif.com/components/espressif/esp_sysview/badge.svg)](https://components.espressif.com/components/espressif/esp_sysview)\n\nThis component integrates SEGGER SystemView with ESP-IDF and is distributed as a managed component.\n\n## Install (managed component)\n\nAdd a dependency in your project's `idf_component.yml`:\n\n```yaml\ndependencies:\n  espressif/esp_sysview: ^1\n```\n\nConfigure SystemView tracing in `idf.py menuconfig`:\n- Enable tracing: `CONFIG_ESP_TRACING_ENABLE`\n- Select trace library: Component config > ESP Trace Configuration > Trace library > External library from component registry `CONFIG_ESP_TRACE_LIB_EXTERNAL`\n- Select timestamp source: Component config > ESP Trace Configuration > Trace timestamp source\n- Configure event filters: Component config > SEGGER SystemView Configuration\n\n## Documentation and examples\n\n- ESP-IDF examples:\n  - `examples/system/sysview_tracing/` (basic SystemView tracing)\n  - `examples/system/sysview_tracing_heap_log/README.md` (heap tracing)\n- SEGGER SystemView documentation for host-side tooling.\n\n## License\n\nApache 2.0. See `LICENSE` file.\n"
  },
  {
    "path": "esp_sysview/idf_component.yml",
    "content": "version: 1.0.2\ndescription: SEGGER SystemView component for ESP-IDF\nurl: https://github.com/espressif/idf-extra-components/tree/master/esp_sysview\nissues: https://github.com/espressif/idf-extra-components/issues\nrepository: https://github.com/espressif/idf-extra-components.git\ndependencies:\n  idf: \">=6.0\"\nsbom:\n  manifests:\n    - path: sbom_segger.yml\n      dest: src/SEGGER\n"
  },
  {
    "path": "esp_sysview/linker.lf.in",
    "content": "[mapping:esp_sysview]\narchive: lib${COMPONENT_NAME}.a\nentries:\n    # Place all the symbols in the IRAM to allow tracing when flash cache is disabled\n    SEGGER_SYSVIEW (noflash)\n    SEGGER_RTT_esp (noflash)\n    SEGGER_SYSVIEW_esp (noflash)\n    SEGGER_SYSVIEW_Config_FreeRTOS (noflash)\n    SEGGER_SYSVIEW_FreeRTOS (noflash)\n    adapter_encoder_sysview (noflash)\n    if HEAP_TRACING_TOHOST = y:\n        heap_trace_module (noflash)\n"
  },
  {
    "path": "esp_sysview/sbom_segger.yml",
    "content": "name: 'SystemView'\nversion: '3.56'\ncpe: cpe:2.3:a:segger:systemview:{}:*:*:*:*:*:*:*\nsupplier: 'Organization: Espressif Systems (Shanghai) CO LTD'\noriginator: 'Organization: SEGGER Microcontroller GmbH'\ndescription: Real-time recording and visualization tool for embedded systems.\n"
  },
  {
    "path": "esp_sysview/sdkconfig.rename",
    "content": "# sdkconfig replacement configurations for deprecated options formatted as\n# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION\n\nCONFIG_SYSVIEW_MAX_TASKS\t\t\t\t\t\t\t    CONFIG_SEGGER_SYSVIEW_MAX_TASKS\nCONFIG_SYSVIEW_BUF_WAIT_TMO\t\t\t\t\t\t\t    CONFIG_SEGGER_SYSVIEW_BUF_WAIT_TMO\nCONFIG_SYSVIEW_EVT_OVERFLOW_ENABLE\t\t\t\t\t\tCONFIG_SEGGER_SYSVIEW_EVT_OVERFLOW_ENABLE\nCONFIG_SYSVIEW_EVT_ISR_ENTER_ENABLE\t\t\t\t\t\tCONFIG_SEGGER_SYSVIEW_EVT_ISR_ENTER_ENABLE\nCONFIG_SYSVIEW_EVT_ISR_EXIT_ENABLE\t\t\t\t\t\tCONFIG_SEGGER_SYSVIEW_EVT_ISR_EXIT_ENABLE\nCONFIG_SYSVIEW_EVT_ISR_TO_SCHEDULER_ENABLE\t\t\t\tCONFIG_SEGGER_SYSVIEW_EVT_ISR_TO_SCHED_ENABLE\nCONFIG_SYSVIEW_EVT_TASK_START_EXEC_ENABLE\t\t\t\tCONFIG_SEGGER_SYSVIEW_EVT_TASK_START_EXEC_ENABLE\nCONFIG_SYSVIEW_EVT_TASK_STOP_EXEC_ENABLE\t\t\t\tCONFIG_SEGGER_SYSVIEW_EVT_TASK_STOP_EXEC_ENABLE\nCONFIG_SYSVIEW_EVT_TASK_START_READY_ENABLE\t\t\t\tCONFIG_SEGGER_SYSVIEW_EVT_TASK_START_READY_ENABLE\nCONFIG_SYSVIEW_EVT_TASK_STOP_READY_ENABLE\t\t\t\tCONFIG_SEGGER_SYSVIEW_EVT_TASK_STOP_READY_ENABLE\nCONFIG_SYSVIEW_EVT_TASK_CREATE_ENABLE\t\t\t\t\tCONFIG_SEGGER_SYSVIEW_EVT_TASK_CREATE_ENABLE\nCONFIG_SYSVIEW_EVT_TASK_TERMINATE_ENABLE\t\t\t\tCONFIG_SEGGER_SYSVIEW_EVT_TASK_TERMINATE_ENABLE\nCONFIG_SYSVIEW_EVT_IDLE_ENABLE\t\t\t\t\t\t\tCONFIG_SEGGER_SYSVIEW_EVT_IDLE_ENABLE\nCONFIG_SYSVIEW_EVT_TIMER_ENTER_ENABLE\t\t\t\t\tCONFIG_SEGGER_SYSVIEW_EVT_TIMER_ENTER_ENABLE\nCONFIG_SYSVIEW_EVT_TIMER_EXIT_ENABLE\t\t\t\t\tCONFIG_SEGGER_SYSVIEW_EVT_TIMER_EXIT_ENABLE\n"
  },
  {
    "path": "esp_sysview/src/Config/Global.h",
    "content": "/*\n * SPDX-FileCopyrightText: 1995-2021 SEGGER Microcontroller GmbH\n *\n * SPDX-License-Identifier: BSD-1-Clause\n */\n/*********************************************************************\n*                    SEGGER Microcontroller GmbH                     *\n*                        The Embedded Experts                        *\n**********************************************************************\n*                                                                    *\n*            (c) 1995 - 2021 SEGGER Microcontroller GmbH             *\n*                                                                    *\n*       www.segger.com     Support: support@segger.com               *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SEGGER SystemView * Real-time application analysis           *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n* All rights reserved.                                               *\n*                                                                    *\n* SEGGER strongly recommends to not make any changes                 *\n* to or modify the source code of this software in order to stay     *\n* compatible with the SystemView and RTT protocol, and J-Link.       *\n*                                                                    *\n* Redistribution and use in source and binary forms, with or         *\n* without modification, are permitted provided that the following    *\n* condition is met:                                                  *\n*                                                                    *\n* o Redistributions of source code must retain the above copyright   *\n*   notice, this condition and the following disclaimer.             *\n*                                                                    *\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             *\n* CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,        *\n* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           *\n* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           *\n* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *\n* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR           *\n* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  *\n* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;    *\n* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF      *\n* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT          *\n* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE  *\n* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *\n* DAMAGE.                                                            *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SystemView version: 3.42                                    *\n*                                                                    *\n**********************************************************************\n----------------------------------------------------------------------\nFile    : Global.h\nPurpose : Global types\n          In case your application already has a Global.h, you should\n          merge the files. In order to use Segger code, the types\n          U8, U16, U32, I8, I16, I32 need to be defined in Global.h;\n          additional definitions do not hurt.\nRevision: $Rev: 12501 $\n---------------------------END-OF-HEADER------------------------------\n*/\n\n#ifndef GLOBAL_H            // Guard against multiple inclusion\n#define GLOBAL_H\n\n#define U8    unsigned char\n#define I8    signed char\n#define U16   unsigned short\n#define I16   signed short\n#ifdef __x86_64__\n#define U32   unsigned\n#define I32   int\n#else\n#define U32   unsigned long\n#define I32   signed long\n#endif\n\n//\n// CC_NO_LONG_SUPPORT can be defined to compile test\n// without long support for compilers that do not\n// support C99 and its long type.\n//\n#ifdef CC_NO_LONG_SUPPORT\n#define PTR_ADDR  U32\n#else  // Supports long type.\n#if defined(_WIN32) && !defined(__clang__) && !defined(__MINGW32__)\n//\n// Microsoft VC6 compiler related\n//\n#define U64   unsigned __int64\n#define U128  unsigned __int128\n#define I64   __int64\n#define I128  __int128\n#if _MSC_VER <= 1200\n#define U64_C(x) x##UI64\n#else\n#define U64_C(x) x##ULL\n#endif\n#else\n//\n// C99 compliant compiler\n//\n#define U64   unsigned long long\n#define I64   signed long long\n#define U64_C(x) x##ULL\n#endif\n\n#if (defined(_WIN64) || defined(__LP64__))  // 64-bit symbols used by Visual Studio and GCC, maybe others as well.\n#define PTR_ADDR  U64\n#else\n#define PTR_ADDR  U32\n#endif\n#endif  // Supports long type.\n\n#endif                      // Avoid multiple inclusion\n\n/*************************** End of file ****************************/\n"
  },
  {
    "path": "esp_sysview/src/Config/SEGGER_RTT_Conf.h",
    "content": "/*\n * SPDX-FileCopyrightText: 1995-2021 SEGGER Microcontroller GmbH\n *\n * SPDX-License-Identifier: BSD-1-Clause\n */\n/*********************************************************************\n*                    SEGGER Microcontroller GmbH                     *\n*                        The Embedded Experts                        *\n**********************************************************************\n*                                                                    *\n*            (c) 1995 - 2021 SEGGER Microcontroller GmbH             *\n*                                                                    *\n*       www.segger.com     Support: support@segger.com               *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SEGGER SystemView * Real-time application analysis           *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n* All rights reserved.                                               *\n*                                                                    *\n* SEGGER strongly recommends to not make any changes                 *\n* to or modify the source code of this software in order to stay     *\n* compatible with the SystemView and RTT protocol, and J-Link.       *\n*                                                                    *\n* Redistribution and use in source and binary forms, with or         *\n* without modification, are permitted provided that the following    *\n* condition is met:                                                  *\n*                                                                    *\n* o Redistributions of source code must retain the above copyright   *\n*   notice, this condition and the following disclaimer.             *\n*                                                                    *\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             *\n* CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,        *\n* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           *\n* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           *\n* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *\n* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR           *\n* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  *\n* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;    *\n* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF      *\n* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT          *\n* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE  *\n* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *\n* DAMAGE.                                                            *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SystemView version: 3.42                                    *\n*                                                                    *\n**********************************************************************\n---------------------------END-OF-HEADER------------------------------\nFile    : SEGGER_RTT_Conf.h\nPurpose : Implementation of SEGGER real-time transfer (RTT) which\n          allows real-time communication on targets which support\n          debugger memory accesses while the CPU is running.\nRevision: $Rev: 24316 $\n\n*/\n\n#ifndef SEGGER_RTT_CONF_H\n#define SEGGER_RTT_CONF_H\n\n#ifdef __IAR_SYSTEMS_ICC__\n#include <intrinsics.h>\n#endif\n\n/*********************************************************************\n*\n*       Defines, configurable\n*\n**********************************************************************\n*/\n\n//\n// Take in and set to correct values for Cortex-A systems with CPU cache\n//\n//#define SEGGER_RTT_CPU_CACHE_LINE_SIZE            (32)          // Largest cache line size (in bytes) in the current system\n//#define SEGGER_RTT_UNCACHED_OFF                   (0xFB000000)  // Address alias where RTT CB and buffers can be accessed uncached\n//\n// Most common case:\n// Up-channel 0: RTT\n// Up-channel 1: SystemView\n//\n#ifndef   SEGGER_RTT_MAX_NUM_UP_BUFFERS\n#define SEGGER_RTT_MAX_NUM_UP_BUFFERS             (3)     // Max. number of up-buffers (T->H) available on this target    (Default: 3)\n#endif\n//\n// Most common case:\n// Down-channel 0: RTT\n// Down-channel 1: SystemView\n//\n#ifndef   SEGGER_RTT_MAX_NUM_DOWN_BUFFERS\n#define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS           (3)     // Max. number of down-buffers (H->T) available on this target  (Default: 3)\n#endif\n\n#ifndef   BUFFER_SIZE_UP\n#define BUFFER_SIZE_UP                            (1024)  // Size of the buffer for terminal output of target, up to host (Default: 1k)\n#endif\n\n#ifndef   BUFFER_SIZE_DOWN\n#define BUFFER_SIZE_DOWN                          (16)    // Size of the buffer for terminal input to target from host (Usually keyboard input) (Default: 16)\n#endif\n\n#ifndef   SEGGER_RTT_PRINTF_BUFFER_SIZE\n#define SEGGER_RTT_PRINTF_BUFFER_SIZE             (64u)    // Size of buffer for RTT printf to bulk-send chars via RTT     (Default: 64)\n#endif\n\n#ifndef   SEGGER_RTT_MODE_DEFAULT\n#define SEGGER_RTT_MODE_DEFAULT                   SEGGER_RTT_MODE_NO_BLOCK_SKIP // Mode for pre-initialized terminal channel (buffer 0)\n#endif\n\n/*********************************************************************\n*\n*       RTT memcpy configuration\n*\n*       memcpy() is good for large amounts of data,\n*       but the overhead is big for small amounts, which are usually stored via RTT.\n*       With SEGGER_RTT_MEMCPY_USE_BYTELOOP a simple byte loop can be used instead.\n*\n*       SEGGER_RTT_MEMCPY() can be used to replace standard memcpy() in RTT functions.\n*       This is may be required with memory access restrictions,\n*       such as on Cortex-A devices with MMU.\n*/\n#ifndef   SEGGER_RTT_MEMCPY_USE_BYTELOOP\n#define SEGGER_RTT_MEMCPY_USE_BYTELOOP              0 // 0: Use memcpy/SEGGER_RTT_MEMCPY, 1: Use a simple byte-loop\n#endif\n//\n// Example definition of SEGGER_RTT_MEMCPY to external memcpy with GCC toolchains and Cortex-A targets\n//\n//#if ((defined __SES_ARM) || (defined __CROSSWORKS_ARM) || (defined __GNUC__)) && (defined (__ARM_ARCH_7A__))\n//  #define SEGGER_RTT_MEMCPY(pDest, pSrc, NumBytes)      SEGGER_memcpy((pDest), (pSrc), (NumBytes))\n//#endif\n\n//\n// Target is not allowed to perform other RTT operations while string still has not been stored completely.\n// Otherwise we would probably end up with a mixed string in the buffer.\n// If using  RTT from within interrupts, multiple tasks or multi processors, define the SEGGER_RTT_LOCK() and SEGGER_RTT_UNLOCK() function here.\n//\n// SEGGER_RTT_MAX_INTERRUPT_PRIORITY can be used in the sample lock routines on Cortex-M3/4.\n// Make sure to mask all interrupts which can send RTT data, i.e. generate SystemView events, or cause task switches.\n// When high-priority interrupts must not be masked while sending RTT data, SEGGER_RTT_MAX_INTERRUPT_PRIORITY needs to be adjusted accordingly.\n// (Higher priority = lower priority number)\n// Default value for embOS: 128u\n// Default configuration in FreeRTOS: configMAX_SYSCALL_INTERRUPT_PRIORITY: ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )\n// In case of doubt mask all interrupts: 1 << (8 - BASEPRI_PRIO_BITS) i.e. 1 << 5 when 3 bits are implemented in NVIC\n// or define SEGGER_RTT_LOCK() to completely disable interrupts.\n//\n#ifndef   SEGGER_RTT_MAX_INTERRUPT_PRIORITY\n#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY         (0x20)   // Interrupt priority to lock on SEGGER_RTT_LOCK on Cortex-M3/4 (Default: 0x20)\n#endif\n\n/*********************************************************************\n*\n*       RTT lock configuration for SEGGER Embedded Studio,\n*       Rowley CrossStudio and GCC\n*/\n#if ((defined(__SES_ARM) || defined(__SES_RISCV) || defined(__CROSSWORKS_ARM) || defined(__GNUC__) || defined(__clang__)) && !defined (__CC_ARM) && !defined(WIN32))\n#if (defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_8M_BASE__))\n#define SEGGER_RTT_LOCK()   {                                                                   \\\n                                    unsigned int _SEGGER_RTT__LockState;                                         \\\n                                  __asm volatile (\"mrs   %0, primask  \\n\\t\"                         \\\n                                                  \"movs  r1, #1       \\n\\t\"                         \\\n                                                  \"msr   primask, r1  \\n\\t\"                         \\\n                                                  : \"=r\" (_SEGGER_RTT__LockState)                                \\\n                                                  :                                                 \\\n                                                  : \"r1\", \"cc\"                                      \\\n                                                  );\n\n#define SEGGER_RTT_UNLOCK()   __asm volatile (\"msr   primask, %0  \\n\\t\"                         \\\n                                                  :                                                 \\\n                                                  : \"r\" (_SEGGER_RTT__LockState)                                 \\\n                                                  :                                                 \\\n                                                  );                                                \\\n                                }\n#elif (defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__))\n#ifndef   SEGGER_RTT_MAX_INTERRUPT_PRIORITY\n#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY   (0x20)\n#endif\n#define SEGGER_RTT_LOCK()   {                                                                   \\\n                                    unsigned int _SEGGER_RTT__LockState;                                         \\\n                                  __asm volatile (\"mrs   %0, basepri  \\n\\t\"                         \\\n                                                  \"mov   r1, %1       \\n\\t\"                         \\\n                                                  \"msr   basepri, r1  \\n\\t\"                         \\\n                                                  : \"=r\" (_SEGGER_RTT__LockState)                                \\\n                                                  : \"i\"(SEGGER_RTT_MAX_INTERRUPT_PRIORITY)          \\\n                                                  : \"r1\", \"cc\"                                      \\\n                                                  );\n\n#define SEGGER_RTT_UNLOCK()   __asm volatile (\"msr   basepri, %0  \\n\\t\"                         \\\n                                                  :                                                 \\\n                                                  : \"r\" (_SEGGER_RTT__LockState)                                 \\\n                                                  :                                                 \\\n                                                  );                                                \\\n                                }\n\n#elif (defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__))\n#define SEGGER_RTT_LOCK() {                                                \\\n                                 unsigned int _SEGGER_RTT__LockState;                       \\\n                                 __asm volatile (\"mrs r1, CPSR \\n\\t\"           \\\n                                                 \"mov %0, r1 \\n\\t\"             \\\n                                                 \"orr r1, r1, #0xC0 \\n\\t\"      \\\n                                                 \"msr CPSR_c, r1 \\n\\t\"         \\\n                                                 : \"=r\" (_SEGGER_RTT__LockState)            \\\n                                                 :                             \\\n                                                 : \"r1\", \"cc\"                  \\\n                                                 );\n\n#define SEGGER_RTT_UNLOCK() __asm volatile (\"mov r0, %0 \\n\\t\"              \\\n                                                \"mrs r1, CPSR \\n\\t\"            \\\n                                                \"bic r1, r1, #0xC0 \\n\\t\"       \\\n                                                \"and r0, r0, #0xC0 \\n\\t\"       \\\n                                                \"orr r1, r1, r0 \\n\\t\"          \\\n                                                \"msr CPSR_c, r1 \\n\\t\"          \\\n                                                :                              \\\n                                                : \"r\" (_SEGGER_RTT__LockState)              \\\n                                                : \"r0\", \"r1\", \"cc\"             \\\n                                                );                             \\\n                            }\n#elif defined(__riscv) || defined(__riscv_xlen)\n#define SEGGER_RTT_LOCK()  {                                               \\\n                                 unsigned int _SEGGER_RTT__LockState;                       \\\n                                 __asm volatile (\"csrr  %0, mstatus  \\n\\t\"     \\\n                                                 \"csrci mstatus, 8   \\n\\t\"     \\\n                                                 \"andi  %0, %0,  8   \\n\\t\"     \\\n                                                 : \"=r\" (_SEGGER_RTT__LockState)            \\\n                                                 :                             \\\n                                                 :                             \\\n                                                );\n\n#define SEGGER_RTT_UNLOCK()    __asm volatile (\"csrr  a1, mstatus  \\n\\t\"     \\\n                                                 \"or    %0, %0, a1   \\n\\t\"     \\\n                                                 \"csrs  mstatus, %0  \\n\\t\"     \\\n                                                 :                             \\\n                                                 : \"r\"  (_SEGGER_RTT__LockState)            \\\n                                                 : \"a1\"                        \\\n                                                );                             \\\n                               }\n#else\n#define SEGGER_RTT_LOCK()\n#define SEGGER_RTT_UNLOCK()\n#endif\n#endif\n\n/*********************************************************************\n*\n*       RTT lock configuration for IAR EWARM\n*/\n#ifdef __ICCARM__\n#if (defined (__ARM6M__)          && (__CORE__ == __ARM6M__))             ||                      \\\n      (defined (__ARM8M_BASELINE__) && (__CORE__ == __ARM8M_BASELINE__))\n#define SEGGER_RTT_LOCK()   {                                                                   \\\n                                  unsigned int _SEGGER_RTT__LockState;                                           \\\n                                  _SEGGER_RTT__LockState = __get_PRIMASK();                                      \\\n                                  __set_PRIMASK(1);\n\n#define SEGGER_RTT_UNLOCK()   __set_PRIMASK(_SEGGER_RTT__LockState);                                         \\\n                                }\n#elif (defined (__ARM7EM__)         && (__CORE__ == __ARM7EM__))          ||                      \\\n        (defined (__ARM7M__)          && (__CORE__ == __ARM7M__))           ||                      \\\n        (defined (__ARM8M_MAINLINE__) && (__CORE__ == __ARM8M_MAINLINE__))  ||                      \\\n        (defined (__ARM8M_MAINLINE__) && (__CORE__ == __ARM8M_MAINLINE__))\n#ifndef   SEGGER_RTT_MAX_INTERRUPT_PRIORITY\n#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY   (0x20)\n#endif\n#define SEGGER_RTT_LOCK()   {                                                                   \\\n                                  unsigned int _SEGGER_RTT__LockState;                                           \\\n                                  _SEGGER_RTT__LockState = __get_BASEPRI();                                      \\\n                                  __set_BASEPRI(SEGGER_RTT_MAX_INTERRUPT_PRIORITY);\n\n#define SEGGER_RTT_UNLOCK()   __set_BASEPRI(_SEGGER_RTT__LockState);                                         \\\n                                }\n#elif (defined (__ARM7A__) && (__CORE__ == __ARM7A__))                    ||                      \\\n        (defined (__ARM7R__) && (__CORE__ == __ARM7R__))\n#define SEGGER_RTT_LOCK() {                                                                     \\\n                                 unsigned int _SEGGER_RTT__LockState;                                            \\\n                                 __asm volatile (\"mrs r1, CPSR \\n\\t\"                                \\\n                                                 \"mov %0, r1 \\n\\t\"                                  \\\n                                                 \"orr r1, r1, #0xC0 \\n\\t\"                           \\\n                                                 \"msr CPSR_c, r1 \\n\\t\"                              \\\n                                                 : \"=r\" (_SEGGER_RTT__LockState)                                 \\\n                                                 :                                                  \\\n                                                 : \"r1\", \"cc\"                                       \\\n                                                 );\n\n#define SEGGER_RTT_UNLOCK() __asm volatile (\"mov r0, %0 \\n\\t\"                                   \\\n                                                \"mrs r1, CPSR \\n\\t\"                                 \\\n                                                \"bic r1, r1, #0xC0 \\n\\t\"                            \\\n                                                \"and r0, r0, #0xC0 \\n\\t\"                            \\\n                                                \"orr r1, r1, r0 \\n\\t\"                               \\\n                                                \"msr CPSR_c, r1 \\n\\t\"                               \\\n                                                :                                                   \\\n                                                : \"r\" (_SEGGER_RTT__LockState)                                   \\\n                                                : \"r0\", \"r1\", \"cc\"                                  \\\n                                                );                                                  \\\n                            }\n#endif\n#endif\n\n/*********************************************************************\n*\n*       RTT lock configuration for IAR RX\n*/\n#ifdef __ICCRX__\n#define SEGGER_RTT_LOCK()   {                                                                     \\\n                                unsigned long _SEGGER_RTT__LockState;                                            \\\n                                _SEGGER_RTT__LockState = __get_interrupt_state();                                \\\n                                __disable_interrupt();\n\n#define SEGGER_RTT_UNLOCK()   __set_interrupt_state(_SEGGER_RTT__LockState);                                   \\\n                              }\n#endif\n\n/*********************************************************************\n*\n*       RTT lock configuration for IAR RL78\n*/\n#ifdef __ICCRL78__\n#define SEGGER_RTT_LOCK()   {                                                                     \\\n                                __istate_t _SEGGER_RTT__LockState;                                               \\\n                                _SEGGER_RTT__LockState = __get_interrupt_state();                                \\\n                                __disable_interrupt();\n\n#define SEGGER_RTT_UNLOCK()   __set_interrupt_state(_SEGGER_RTT__LockState);                                   \\\n                              }\n#endif\n\n/*********************************************************************\n*\n*       RTT lock configuration for KEIL ARM\n*/\n#ifdef __CC_ARM\n#if (defined __TARGET_ARCH_6S_M)\n#define SEGGER_RTT_LOCK()   {                                                                   \\\n                                  unsigned int _SEGGER_RTT__LockState;                                           \\\n                                  register unsigned char _SEGGER_RTT__PRIMASK __asm( \"primask\");                 \\\n                                  _SEGGER_RTT__LockState = _SEGGER_RTT__PRIMASK;                                              \\\n                                  _SEGGER_RTT__PRIMASK = 1u;                                                     \\\n                                  __schedule_barrier();\n\n#define SEGGER_RTT_UNLOCK()   _SEGGER_RTT__PRIMASK = _SEGGER_RTT__LockState;                                              \\\n                                  __schedule_barrier();                                             \\\n                                }\n#elif (defined(__TARGET_ARCH_7_M) || defined(__TARGET_ARCH_7E_M))\n#ifndef   SEGGER_RTT_MAX_INTERRUPT_PRIORITY\n#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY   (0x20)\n#endif\n#define SEGGER_RTT_LOCK()   {                                                                   \\\n                                  unsigned int _SEGGER_RTT__LockState;                                           \\\n                                  register unsigned char BASEPRI __asm( \"basepri\");                 \\\n                                  _SEGGER_RTT__LockState = BASEPRI;                                              \\\n                                  BASEPRI = SEGGER_RTT_MAX_INTERRUPT_PRIORITY;                      \\\n                                  __schedule_barrier();\n\n#define SEGGER_RTT_UNLOCK()   BASEPRI = _SEGGER_RTT__LockState;                                              \\\n                                  __schedule_barrier();                                             \\\n                                }\n#endif\n#endif\n\n/*********************************************************************\n*\n*       RTT lock configuration for TI ARM\n*/\n#ifdef __TI_ARM__\n#if defined (__TI_ARM_V6M0__)\n#define SEGGER_RTT_LOCK()   {                                                                   \\\n                                  unsigned int _SEGGER_RTT__LockState;                                           \\\n                                  _SEGGER_RTT__LockState = __get_PRIMASK();                                      \\\n                                  __set_PRIMASK(1);\n\n#define SEGGER_RTT_UNLOCK()   __set_PRIMASK(_SEGGER_RTT__LockState);                                         \\\n                                }\n#elif (defined (__TI_ARM_V7M3__) || defined (__TI_ARM_V7M4__))\n#ifndef   SEGGER_RTT_MAX_INTERRUPT_PRIORITY\n#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY   (0x20)\n#endif\n#define SEGGER_RTT_LOCK()   {                                                                   \\\n                                  unsigned int _SEGGER_RTT__LockState;                                           \\\n                                  _SEGGER_RTT__LockState = _set_interrupt_priority(SEGGER_RTT_MAX_INTERRUPT_PRIORITY);\n\n#define SEGGER_RTT_UNLOCK()   _set_interrupt_priority(_SEGGER_RTT__LockState);                               \\\n                                }\n#endif\n#endif\n\n/*********************************************************************\n*\n*       RTT lock configuration for CCRX\n*/\n#ifdef __RX\n#include <machine.h>\n#define SEGGER_RTT_LOCK()   {                                                                     \\\n                                unsigned long _SEGGER_RTT__LockState;                                            \\\n                                _SEGGER_RTT__LockState = get_psw() & 0x010000;                                   \\\n                                clrpsw_i();\n\n#define SEGGER_RTT_UNLOCK()   set_psw(get_psw() | _SEGGER_RTT__LockState);                                     \\\n                              }\n#endif\n\n/*********************************************************************\n*\n*       RTT lock configuration for embOS Simulation on Windows\n*       (Can also be used for generic RTT locking with embOS)\n*/\n#if defined(WIN32) || defined(SEGGER_RTT_LOCK_EMBOS)\n\nvoid OS_SIM_EnterCriticalSection(void);\nvoid OS_SIM_LeaveCriticalSection(void);\n\n#define SEGGER_RTT_LOCK()       {                                                                   \\\n                                  OS_SIM_EnterCriticalSection();\n\n#define SEGGER_RTT_UNLOCK()       OS_SIM_LeaveCriticalSection();                                    \\\n                                }\n#endif\n\n/*********************************************************************\n*\n*       RTT lock configuration fallback\n*/\n#ifndef   SEGGER_RTT_LOCK\n#define SEGGER_RTT_LOCK()                // Lock RTT (nestable)   (i.e. disable interrupts)\n#endif\n\n#ifndef   SEGGER_RTT_UNLOCK\n#define SEGGER_RTT_UNLOCK()              // Unlock RTT (nestable) (i.e. enable previous interrupt lock state)\n#endif\n\n#endif\n/*************************** End of file ****************************/\n"
  },
  {
    "path": "esp_sysview/src/Config/SEGGER_SYSVIEW_Conf.h",
    "content": "/*\n * SPDX-FileCopyrightText: 1995-2021 SEGGER Microcontroller GmbH\n *\n * SPDX-License-Identifier: BSD-1-Clause\n */\n/*********************************************************************\n*                    SEGGER Microcontroller GmbH                     *\n*                        The Embedded Experts                        *\n**********************************************************************\n*                                                                    *\n*            (c) 1995 - 2021 SEGGER Microcontroller GmbH             *\n*                                                                    *\n*       www.segger.com     Support: support@segger.com               *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SEGGER SystemView * Real-time application analysis           *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n* All rights reserved.                                               *\n*                                                                    *\n* SEGGER strongly recommends to not make any changes                 *\n* to or modify the source code of this software in order to stay     *\n* compatible with the SystemView and RTT protocol, and J-Link.       *\n*                                                                    *\n* Redistribution and use in source and binary forms, with or         *\n* without modification, are permitted provided that the following    *\n* condition is met:                                                  *\n*                                                                    *\n* o Redistributions of source code must retain the above copyright   *\n*   notice, this condition and the following disclaimer.             *\n*                                                                    *\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             *\n* CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,        *\n* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           *\n* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           *\n* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *\n* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR           *\n* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  *\n* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;    *\n* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF      *\n* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT          *\n* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE  *\n* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *\n* DAMAGE.                                                            *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SystemView version: 3.42                                    *\n*                                                                    *\n**********************************************************************\n-------------------------- END-OF-HEADER -----------------------------\n\nFile    : SEGGER_SYSVIEW_Conf.h\nPurpose : SEGGER SystemView configuration file.\n          Set defines which deviate from the defaults (see SEGGER_SYSVIEW_ConfDefaults.h) here.\nRevision: $Rev: 21292 $\n\nAdditional information:\n  Required defines which must be set are:\n    SEGGER_SYSVIEW_GET_TIMESTAMP\n    SEGGER_SYSVIEW_GET_INTERRUPT_ID\n  For known compilers and cores, these might be set to good defaults\n  in SEGGER_SYSVIEW_ConfDefaults.h.\n\n  SystemView needs a (nestable) locking mechanism.\n  If not defined, the RTT locking mechanism is used,\n  which then needs to be properly configured.\n*/\n\n#ifndef SEGGER_SYSVIEW_CONF_H\n#define SEGGER_SYSVIEW_CONF_H\n\n/*********************************************************************\n*\n*       Defines, configurable\n*\n**********************************************************************\n*/\n\n/*********************************************************************\n* TODO: Add your defines here.                                       *\n**********************************************************************\n*/\n\n\n#endif  // SEGGER_SYSVIEW_CONF_H\n\n/*************************** End of file ****************************/\n"
  },
  {
    "path": "esp_sysview/src/SEGGER/SEGGER.h",
    "content": "/*\n * SPDX-FileCopyrightText: 1995-2021 SEGGER Microcontroller GmbH\n *\n * SPDX-License-Identifier: BSD-1-Clause\n *\n * SPDX-FileContributor: 2023 Espressif Systems (Shanghai) CO LTD\n */\n/*********************************************************************\n*                    SEGGER Microcontroller GmbH                     *\n*                        The Embedded Experts                        *\n**********************************************************************\n*                                                                    *\n*            (c) 1995 - 2024 SEGGER Microcontroller GmbH             *\n*                                                                    *\n*       www.segger.com     Support: support@segger.com               *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SEGGER SystemView * Real-time application analysis           *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n* All rights reserved.                                               *\n*                                                                    *\n* SEGGER strongly recommends to not make any changes                 *\n* to or modify the source code of this software in order to stay     *\n* compatible with the SystemView and RTT protocol, and J-Link.       *\n*                                                                    *\n* Redistribution and use in source and binary forms, with or         *\n* without modification, are permitted provided that the following    *\n* condition is met:                                                  *\n*                                                                    *\n* o Redistributions of source code must retain the above copyright   *\n*   notice, this condition and the following disclaimer.             *\n*                                                                    *\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             *\n* CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,        *\n* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           *\n* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           *\n* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *\n* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR           *\n* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  *\n* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;    *\n* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF      *\n* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT          *\n* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE  *\n* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *\n* DAMAGE.                                                            *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SystemView version: 3.56                                    *\n*                                                                    *\n**********************************************************************\n----------------------------------------------------------------------\nFile    : SEGGER.h\nPurpose : Global types etc & general purpose utility functions\nRevision: $Rev: 18102 $\n---------------------------END-OF-HEADER------------------------------\n*/\n\n#ifndef SEGGER_H            // Guard against multiple inclusion\n#define SEGGER_H\n\n#include <stdarg.h>         // For va_list.\n#include \"Global.h\"         // Type definitions: U8, U16, U32, I8, I16, I32\n\n#if defined(__cplusplus)\nextern \"C\" {     /* Make sure we have C-declarations in C++ programs */\n#endif\n\n/*********************************************************************\n*\n*       Keywords/specifiers\n*\n**********************************************************************\n*/\n\n#ifndef INLINE\n#if (defined(__ICCARM__) || defined(__RX) || defined(__ICCRX__))\n//\n// Other known compilers.\n//\n#define INLINE  inline\n#else\n#if (defined(_WIN32) && !defined(__clang__))\n//\n// Microsoft VC6 and newer.\n// Force inlining without cost checking.\n//\n#define INLINE  __forceinline\n#elif defined(__GNUC__) || defined(__clang__)\n//\n// Force inlining with GCC + clang\n//\n#define INLINE inline __attribute__((always_inline))\n#elif (defined(__CC_ARM))\n//\n// Force inlining with ARMCC (Keil)\n//\n#define INLINE  __inline\n#else\n//\n// Unknown compilers.\n//\n#define INLINE\n#endif\n#endif\n#endif\n\n/*********************************************************************\n*\n*       Function-like macros\n*\n**********************************************************************\n*/\n\n#define SEGGER_COUNTOF(a)          (sizeof((a))/sizeof((a)[0]))\n#define SEGGER_MIN(a,b)            (((a) < (b)) ? (a) : (b))\n#define SEGGER_MAX(a,b)            (((a) > (b)) ? (a) : (b))\n\n#ifndef   SEGGER_USE_PARA                   // Some compiler complain about unused parameters.\n#define SEGGER_USE_PARA(Para) (void)Para  // This works for most compilers.\n#endif\n\n#define SEGGER_ADDR2PTR(Type, Addr)  (/*lint -e(923) -e(9078)*/((Type*)((PTR_ADDR)(Addr))))    // Allow cast from address to pointer.\n#define SEGGER_PTR2ADDR(p)           (/*lint -e(923) -e(9078)*/((PTR_ADDR)(p)))                // Allow cast from pointer to address.\n#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).\n#define SEGGER_PTR_DISTANCE(p0, p1)  (SEGGER_PTR2ADDR(p0) - SEGGER_PTR2ADDR(p1))\n\n/*********************************************************************\n*\n*       Defines\n*\n**********************************************************************\n*/\n\n#define SEGGER_PRINTF_FLAG_ADJLEFT    (1 << 0)\n#define SEGGER_PRINTF_FLAG_SIGNFORCE  (1 << 1)\n#define SEGGER_PRINTF_FLAG_SIGNSPACE  (1 << 2)\n#define SEGGER_PRINTF_FLAG_PRECEED    (1 << 3)\n#define SEGGER_PRINTF_FLAG_ZEROPAD    (1 << 4)\n#define SEGGER_PRINTF_FLAG_NEGATIVE   (1 << 5)\n\n/*********************************************************************\n*\n*       Types\n*\n**********************************************************************\n*/\n\ntypedef struct {\n    char *pBuffer;\n    int   BufferSize;\n    int   Cnt;\n} SEGGER_BUFFER_DESC;\n\ntypedef struct {\n    unsigned int CacheLineSize;                             // 0: No Cache. Most Systems such as ARM9 use a 32 bytes cache line size.\n    void (*pfDMB)       (void);                             // Optional DMB function for Data Memory Barrier to make sure all memory operations are completed.\n    void (*pfClean)     (void *p, unsigned long NumBytes);  // Optional clean function for cached memory.\n    void (*pfInvalidate)(void *p, unsigned long NumBytes);  // Optional invalidate function for cached memory.\n} SEGGER_CACHE_CONFIG;\n\ntypedef struct SEGGER_SNPRINTF_CONTEXT_struct SEGGER_SNPRINTF_CONTEXT;\n\nstruct SEGGER_SNPRINTF_CONTEXT_struct {\n    void               *pContext;                       // Application specific context.\n    SEGGER_BUFFER_DESC *pBufferDesc;                    // Buffer descriptor to use for output.\n    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.\n};\n\ntypedef struct {\n    void (*pfStoreChar)       (SEGGER_BUFFER_DESC *pBufferDesc, SEGGER_SNPRINTF_CONTEXT *pContext, char c);\n    int  (*pfPrintUnsigned)   (SEGGER_BUFFER_DESC *pBufferDesc, SEGGER_SNPRINTF_CONTEXT *pContext, U32 v, unsigned Base, char Flags, int Width, int Precision);\n    int  (*pfPrintInt)        (SEGGER_BUFFER_DESC *pBufferDesc, SEGGER_SNPRINTF_CONTEXT *pContext, I32 v, unsigned Base, char Flags, int Width, int Precision);\n} SEGGER_PRINTF_API;\n\ntypedef 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);\n\ntypedef struct SEGGER_PRINTF_FORMATTER {\n    struct SEGGER_PRINTF_FORMATTER *pNext;              // Pointer to next formatter.\n    SEGGER_pFormatter               pfFormatter;        // Formatter function.\n    char                            Specifier;          // Format specifier.\n} SEGGER_PRINTF_FORMATTER;\n\ntypedef struct {\n    U32 (*pfGetHPTimestamp)(void);          // Mandatory, pfGetHPTimestamp\n    int (*pfGetUID)        (U8 abUID[16]);  // Optional,  pfGetUID\n} SEGGER_BSP_API;\n\n/*********************************************************************\n*\n*       Utility functions\n*\n**********************************************************************\n*/\n\n//\n// Memory operations.\n//\nvoid SEGGER_ARM_memcpy(void *pDest, const void *pSrc, int NumBytes);\nvoid SEGGER_memcpy    (void *pDest, const void *pSrc, unsigned NumBytes);\nvoid SEGGER_memxor    (void *pDest, const void *pSrc, unsigned NumBytes);\n\n//\n// String functions.\n//\nint      SEGGER_atoi       (const char *s);\nint      SEGGER_isalnum    (int c);\nint      SEGGER_isalpha    (int c);\nunsigned SEGGER_strlen     (const char *s);\nint      SEGGER_tolower    (int c);\nint      SEGGER_strcasecmp (const char *sText1, const char *sText2);\nint      SEGGER_strncasecmp(const char *sText1, const char *sText2, unsigned Count);\n\n//\n// Buffer/printf related.\n//\nvoid SEGGER_StoreChar    (SEGGER_BUFFER_DESC *pBufferDesc, char c);\nvoid SEGGER_PrintUnsigned(SEGGER_BUFFER_DESC *pBufferDesc, U32 v, unsigned Base, int Precision);\nvoid SEGGER_PrintInt     (SEGGER_BUFFER_DESC *pBufferDesc, I32 v, unsigned Base, int Precision);\nint  SEGGER_snprintf     (char *pBuffer, int BufferSize, const char *sFormat, ...);\nint  SEGGER_vsnprintf    (char *pBuffer, int BufferSize, const char *sFormat, va_list ParamList);\nint  SEGGER_vsnprintfEx  (SEGGER_SNPRINTF_CONTEXT *pContext, const char *sFormat, va_list ParamList);\n\nint  SEGGER_PRINTF_AddFormatter       (SEGGER_PRINTF_FORMATTER *pFormatter, SEGGER_pFormatter pfFormatter, char c);\nvoid SEGGER_PRINTF_AddDoubleFormatter (void);\nvoid SEGGER_PRINTF_AddIPFormatter     (void);\nvoid SEGGER_PRINTF_AddBLUEFormatter   (void);\nvoid SEGGER_PRINTF_AddCONNECTFormatter(void);\nvoid SEGGER_PRINTF_AddSSLFormatter    (void);\nvoid SEGGER_PRINTF_AddSSHFormatter    (void);\nvoid SEGGER_PRINTF_AddHTMLFormatter   (void);\n\n//\n// BSP abstraction API.\n//\nint  SEGGER_BSP_GetUID  (U8 abUID[16]);\nint  SEGGER_BSP_GetUID32(U32 *pUID);\nvoid SEGGER_BSP_SetAPI  (const SEGGER_BSP_API *pAPI);\nvoid SEGGER_BSP_SeedUID (void);\n\n//\n// Other API.\n//\nvoid SEGGER_VERSION_GetString(char acText[8], unsigned Version);\n\n#if defined(__cplusplus)\n}                /* Make sure we have C-declarations in C++ programs */\n#endif\n\n#endif                      // Avoid multiple inclusion\n\n/*************************** End of file ****************************/\n"
  },
  {
    "path": "esp_sysview/src/SEGGER/SEGGER_RTT.h",
    "content": "/*\n * SPDX-FileCopyrightText: 1995-2021 SEGGER Microcontroller GmbH\n *\n * SPDX-License-Identifier: BSD-1-Clause\n */\n/*********************************************************************\n*                    SEGGER Microcontroller GmbH                     *\n*                        The Embedded Experts                        *\n**********************************************************************\n*                                                                    *\n*            (c) 1995 - 2024 SEGGER Microcontroller GmbH             *\n*                                                                    *\n*       www.segger.com     Support: support@segger.com               *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SEGGER SystemView * Real-time application analysis           *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n* All rights reserved.                                               *\n*                                                                    *\n* SEGGER strongly recommends to not make any changes                 *\n* to or modify the source code of this software in order to stay     *\n* compatible with the SystemView and RTT protocol, and J-Link.       *\n*                                                                    *\n* Redistribution and use in source and binary forms, with or         *\n* without modification, are permitted provided that the following    *\n* condition is met:                                                  *\n*                                                                    *\n* o Redistributions of source code must retain the above copyright   *\n*   notice, this condition and the following disclaimer.             *\n*                                                                    *\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             *\n* CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,        *\n* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           *\n* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           *\n* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *\n* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR           *\n* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  *\n* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;    *\n* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF      *\n* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT          *\n* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE  *\n* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *\n* DAMAGE.                                                            *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SystemView version: 3.56                                    *\n*                                                                    *\n**********************************************************************\n---------------------------END-OF-HEADER------------------------------\nFile    : SEGGER_RTT.h\nPurpose : Implementation of SEGGER real-time transfer which allows\n          real-time communication on targets which support debugger\n          memory accesses while the CPU is running.\nRevision: $Rev: 25842 $\n----------------------------------------------------------------------\n*/\n\n#ifndef SEGGER_RTT_H\n#define SEGGER_RTT_H\n\n#include \"../Config/SEGGER_RTT_Conf.h\"\n\n/*********************************************************************\n*\n*       Defines, defaults\n*\n**********************************************************************\n*/\n\n#ifndef RTT_USE_ASM\n//\n// Some cores support out-of-order memory accesses (reordering of memory accesses in the core)\n// For such cores, we need to define a memory barrier to guarantee the order of certain accesses to the RTT ring buffers.\n// Needed for:\n//   Cortex-M7 (ARMv7-M)\n//   Cortex-M23 (ARM-v8M)\n//   Cortex-M33 (ARM-v8M)\n//   Cortex-A/R (ARM-v7A/R)\n//\n// We do not explicitly check for \"Embedded Studio\" as the compiler in use determines what we support.\n// You can use an external toolchain like IAR inside ES. So there is no point in checking for \"Embedded Studio\"\n//\n#if (defined __CROSSWORKS_ARM)                  // Rowley Crossworks\n#define _CC_HAS_RTT_ASM_SUPPORT 1\n#if (defined __ARM_ARCH_7M__)                 // Cortex-M3\n#define _CORE_HAS_RTT_ASM_SUPPORT 1\n#elif (defined __ARM_ARCH_7EM__)              // Cortex-M4/M7\n#define _CORE_HAS_RTT_ASM_SUPPORT 1\n#define _CORE_NEEDS_DMB           1\n#define RTT__DMB() __asm volatile (\"dmb\\n\" : : :);\n#elif (defined __ARM_ARCH_8M_BASE__)          // Cortex-M23\n#define _CORE_HAS_RTT_ASM_SUPPORT 0\n#define _CORE_NEEDS_DMB           1\n#define RTT__DMB() __asm volatile (\"dmb\\n\" : : :);\n#elif (defined __ARM_ARCH_8M_MAIN__)          // Cortex-M33\n#define _CORE_HAS_RTT_ASM_SUPPORT 1\n#define _CORE_NEEDS_DMB           1\n#define RTT__DMB() __asm volatile (\"dmb\\n\" : : :);\n#elif (defined(__ARM_ARCH_8_1M_MAIN__))       // Cortex-M85\n#define _CORE_HAS_RTT_ASM_SUPPORT 1\n#define _CORE_NEEDS_DMB           1\n#define RTT__DMB() __asm volatile (\"dmb\\n\" : : :);\n#else\n#define _CORE_HAS_RTT_ASM_SUPPORT 0\n#endif\n#elif (defined __ARMCC_VERSION)\n//\n// ARM compiler\n// ARM compiler V6.0 and later is clang based.\n// Our ASM part is compatible to clang.\n//\n#if (__ARMCC_VERSION >= 6000000)\n#define _CC_HAS_RTT_ASM_SUPPORT 1\n#else\n#define _CC_HAS_RTT_ASM_SUPPORT 0\n#endif\n#if (defined __ARM_ARCH_6M__)                 // Cortex-M0 / M1\n#define _CORE_HAS_RTT_ASM_SUPPORT 0         // No ASM support for this architecture\n#elif (defined __ARM_ARCH_7M__)               // Cortex-M3\n#define _CORE_HAS_RTT_ASM_SUPPORT 1\n#elif (defined __ARM_ARCH_7EM__)              // Cortex-M4/M7\n#define _CORE_HAS_RTT_ASM_SUPPORT 1\n#define _CORE_NEEDS_DMB           1\n#define RTT__DMB() __asm volatile (\"dmb\\n\" : : :);\n#elif (defined __ARM_ARCH_8M_BASE__)          // Cortex-M23\n#define _CORE_HAS_RTT_ASM_SUPPORT 0\n#define _CORE_NEEDS_DMB           1\n#define RTT__DMB() __asm volatile (\"dmb\\n\" : : :);\n#elif (defined __ARM_ARCH_8M_MAIN__)          // Cortex-M33\n#define _CORE_HAS_RTT_ASM_SUPPORT 1\n#define _CORE_NEEDS_DMB           1\n#define RTT__DMB() __asm volatile (\"dmb\\n\" : : :);\n#elif (defined __ARM_ARCH_8_1M_MAIN__)        // Cortex-M85\n#define _CORE_HAS_RTT_ASM_SUPPORT 1\n#define _CORE_NEEDS_DMB           1\n#define RTT__DMB() __asm volatile (\"dmb\\n\" : : :);\n#elif ((defined __ARM_ARCH_7A__) || (defined __ARM_ARCH_7R__))  // Cortex-A/R 32-bit ARMv7-A/R\n#define _CORE_NEEDS_DMB           1\n#define RTT__DMB() __asm volatile (\"dmb\\n\" : : :);\n#else\n#define _CORE_HAS_RTT_ASM_SUPPORT 0\n#endif\n#elif ((defined __GNUC__) || (defined __clang__))\n//\n// GCC / Clang\n//\n#define _CC_HAS_RTT_ASM_SUPPORT 1\n// ARM 7/9: __ARM_ARCH_5__ / __ARM_ARCH_5E__ / __ARM_ARCH_5T__ / __ARM_ARCH_5T__ / __ARM_ARCH_5TE__\n#if (defined __ARM_ARCH_7M__)                 // Cortex-M3\n#define _CORE_HAS_RTT_ASM_SUPPORT 1\n#elif (defined __ARM_ARCH_7EM__)              // Cortex-M4/M7\n#define _CORE_HAS_RTT_ASM_SUPPORT 1\n#define _CORE_NEEDS_DMB           1         // Only Cortex-M7 needs a DMB but we cannot distinguish M4 and M7 here...\n#define RTT__DMB() __asm volatile (\"dmb\\n\" : : :);\n#elif (defined __ARM_ARCH_8M_BASE__)          // Cortex-M23\n#define _CORE_HAS_RTT_ASM_SUPPORT 0\n#define _CORE_NEEDS_DMB           1\n#define RTT__DMB() __asm volatile (\"dmb\\n\" : : :);\n#elif (defined __ARM_ARCH_8M_MAIN__)          // Cortex-M33\n#define _CORE_HAS_RTT_ASM_SUPPORT 1\n#define _CORE_NEEDS_DMB           1\n#define RTT__DMB() __asm volatile (\"dmb\\n\" : : :);\n#elif (defined __ARM_ARCH_8_1M_MAIN__)        // Cortex-M85\n#define _CORE_HAS_RTT_ASM_SUPPORT 1\n#define _CORE_NEEDS_DMB           1\n#define RTT__DMB() __asm volatile (\"dmb\\n\" : : :);\n#elif ((defined __ARM_ARCH_7A__) || (defined __ARM_ARCH_7R__))  // Cortex-A/R 32-bit ARMv7-A/R\n#define _CORE_NEEDS_DMB           1\n#define RTT__DMB() __asm volatile (\"dmb\\n\" : : :);\n#else\n#define _CORE_HAS_RTT_ASM_SUPPORT 0\n#endif\n#elif ((defined __IASMARM__) || (defined __ICCARM__))\n//\n// IAR assembler/compiler\n//\n#define _CC_HAS_RTT_ASM_SUPPORT 1\n#if (__VER__ < 6300000)\n#define VOLATILE\n#else\n#define VOLATILE volatile\n#endif\n#if (defined __ARM7M__)                            // Needed for old versions that do not know the define yet\n#if (__CORE__ == __ARM7M__)                      // Cortex-M3\n#define _CORE_HAS_RTT_ASM_SUPPORT 1\n#endif\n#endif\n#if (defined __ARM7EM__)\n#if (__CORE__ == __ARM7EM__)                     // Cortex-M4/M7\n#define _CORE_HAS_RTT_ASM_SUPPORT 1\n#define _CORE_NEEDS_DMB 1\n#define RTT__DMB() asm VOLATILE (\"DMB\");\n#endif\n#endif\n#if (defined __ARM8M_BASELINE__)\n#if (__CORE__ == __ARM8M_BASELINE__)             // Cortex-M23\n#define _CORE_HAS_RTT_ASM_SUPPORT 0\n#define _CORE_NEEDS_DMB 1\n#define RTT__DMB() asm VOLATILE (\"DMB\");\n#endif\n#endif\n#if (defined __ARM8M_MAINLINE__)\n#if (__CORE__ == __ARM8M_MAINLINE__)             // Cortex-M33\n#define _CORE_HAS_RTT_ASM_SUPPORT 1\n#define _CORE_NEEDS_DMB 1\n#define RTT__DMB() asm VOLATILE (\"DMB\");\n#endif\n#endif\n#if (defined __ARM8EM_MAINLINE__)\n#if (__CORE__ == __ARM8EM_MAINLINE__)            // Cortex-???\n#define _CORE_HAS_RTT_ASM_SUPPORT 1\n#define _CORE_NEEDS_DMB 1\n#define RTT__DMB() asm VOLATILE (\"DMB\");\n#endif\n#endif\n#if (defined __ARM7A__)\n#if (__CORE__ == __ARM7A__)                      // Cortex-A 32-bit ARMv7-A\n#define _CORE_NEEDS_DMB 1\n#define RTT__DMB() asm VOLATILE (\"DMB\");\n#endif\n#endif\n#if (defined __ARM7R__)\n#if (__CORE__ == __ARM7R__)                      // Cortex-R 32-bit ARMv7-R\n#define _CORE_NEEDS_DMB 1\n#define RTT__DMB() asm VOLATILE (\"DMB\");\n#endif\n#endif\n// TBD: __ARM8A__ => Cortex-A 64-bit ARMv8-A\n// TBD: __ARM8R__ => Cortex-R 64-bit ARMv8-R\n#else\n//\n// Other compilers\n//\n#define _CC_HAS_RTT_ASM_SUPPORT   0\n#define _CORE_HAS_RTT_ASM_SUPPORT 0\n#endif\n//\n// If IDE and core support the ASM version, enable ASM version by default\n//\n#ifndef _CORE_HAS_RTT_ASM_SUPPORT\n#define _CORE_HAS_RTT_ASM_SUPPORT 0              // Default for unknown cores\n#endif\n#if (_CC_HAS_RTT_ASM_SUPPORT && _CORE_HAS_RTT_ASM_SUPPORT)\n#define RTT_USE_ASM                           (1)\n#else\n#define RTT_USE_ASM                           (0)\n#endif\n#endif\n\n#ifndef _CORE_NEEDS_DMB\n#define _CORE_NEEDS_DMB 0\n#endif\n\n#ifndef RTT__DMB\n#if _CORE_NEEDS_DMB\n#error \"Don't know how to place inline assembly for DMB\"\n#else\n#define RTT__DMB()\n#endif\n#endif\n\n#ifndef SEGGER_RTT_CPU_CACHE_LINE_SIZE\n#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\n#endif\n\n#ifndef SEGGER_RTT_UNCACHED_OFF\n#if SEGGER_RTT_CPU_CACHE_LINE_SIZE\n#error \"SEGGER_RTT_UNCACHED_OFF must be defined when setting SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0\"\n#else\n#define SEGGER_RTT_UNCACHED_OFF (0)\n#endif\n#endif\n#if RTT_USE_ASM\n#if SEGGER_RTT_CPU_CACHE_LINE_SIZE\n#error \"RTT_USE_ASM is not available if SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0\"\n#endif\n#endif\n\n#ifndef SEGGER_RTT_ASM  // defined when SEGGER_RTT.h is included from assembly file\n#include <stdlib.h>\n#include <stdarg.h>\n#include <stdint.h>\n\n/*********************************************************************\n*\n*       Defines, fixed\n*\n**********************************************************************\n*/\n\n//\n// Determine how much we must pad the control block to make it a multiple of a cache line in size\n// Assuming: U8 = 1B\n//           U16 = 2B\n//           U32 = 4B\n//           U8/U16/U32* = 4B\n//\n#if SEGGER_RTT_CPU_CACHE_LINE_SIZE    // Avoid division by zero in case we do not have any cache\n#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)\n#else\n#define SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(NumBytes) (NumBytes)\n#endif\n#define SEGGER_RTT__CB_SIZE                              (16 + 4 + 4 + (SEGGER_RTT_MAX_NUM_UP_BUFFERS * 24) + (SEGGER_RTT_MAX_NUM_DOWN_BUFFERS * 24))\n#define SEGGER_RTT__CB_PADDING                           (SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(SEGGER_RTT__CB_SIZE) - SEGGER_RTT__CB_SIZE)\n\n/*********************************************************************\n*\n*       Types\n*\n**********************************************************************\n*/\n\n//\n// Description for a circular buffer (also called \"ring buffer\")\n// which is used as up-buffer (T->H)\n//\ntypedef struct {\n    const     char    *sName;         // Optional name. Standard names so far are: \"Terminal\", \"SysView\", \"J-Scope_t4i4\"\n    char    *pBuffer;       // Pointer to start of buffer\n    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.\n    unsigned WrOff;         // Position of next item to be written by either target.\n    volatile  unsigned RdOff;         // Position of next item to be read by host. Must be volatile since it may be modified by host.\n    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.\n} SEGGER_RTT_BUFFER_UP;\n\n//\n// Description for a circular buffer (also called \"ring buffer\")\n// which is used as down-buffer (H->T)\n//\ntypedef struct {\n    const     char    *sName;         // Optional name. Standard names so far are: \"Terminal\", \"SysView\", \"J-Scope_t4i4\"\n    char    *pBuffer;       // Pointer to start of buffer\n    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.\n    volatile  unsigned WrOff;         // Position of next item to be written by host. Must be volatile since it may be modified by host.\n    unsigned RdOff;         // Position of next item to be read by target (down-buffer).\n    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.\n} SEGGER_RTT_BUFFER_DOWN;\n\n//\n// RTT control block which describes the number of buffers available\n// as well as the configuration for each buffer\n//\n//\ntypedef struct {\n    char                    acID[16];                                 // Initialized to \"SEGGER RTT\"\n    int                     MaxNumUpBuffers;                          // Initialized to SEGGER_RTT_MAX_NUM_UP_BUFFERS (type. 2)\n    int                     MaxNumDownBuffers;                        // Initialized to SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (type. 2)\n    SEGGER_RTT_BUFFER_UP    aUp[SEGGER_RTT_MAX_NUM_UP_BUFFERS];       // Up buffers, transferring information up from target via debug probe to host\n    SEGGER_RTT_BUFFER_DOWN  aDown[SEGGER_RTT_MAX_NUM_DOWN_BUFFERS];   // Down buffers, transferring information down from host via debug probe to target\n#if SEGGER_RTT__CB_PADDING\n    unsigned char           aDummy[SEGGER_RTT__CB_PADDING];\n#endif\n} SEGGER_RTT_CB;\n\n/*********************************************************************\n*\n*       Global data\n*\n**********************************************************************\n*/\nextern SEGGER_RTT_CB _SEGGER_RTT;\n\n/*********************************************************************\n*\n*       RTT API functions\n*\n**********************************************************************\n*/\n#ifdef __cplusplus\nextern \"C\" {\n#endif\nint          SEGGER_RTT_AllocDownBuffer         (const char *sName, void *pBuffer, unsigned BufferSize, unsigned Flags);\nint          SEGGER_RTT_AllocUpBuffer           (const char *sName, void *pBuffer, unsigned BufferSize, unsigned Flags);\nint          SEGGER_RTT_ConfigUpBuffer          (unsigned BufferIndex, const char *sName, void *pBuffer, unsigned BufferSize, unsigned Flags);\nint          SEGGER_RTT_ConfigDownBuffer        (unsigned BufferIndex, const char *sName, void *pBuffer, unsigned BufferSize, unsigned Flags);\nint          SEGGER_RTT_GetKey                  (void);\nunsigned     SEGGER_RTT_HasData                 (unsigned BufferIndex);\nint          SEGGER_RTT_HasKey                  (void);\nunsigned     SEGGER_RTT_HasDataUp               (unsigned BufferIndex);\nvoid         SEGGER_RTT_Init                    (void);\nunsigned     SEGGER_RTT_Read                    (unsigned BufferIndex,       void *pBuffer, unsigned BufferSize);\nunsigned     SEGGER_RTT_ReadNoLock              (unsigned BufferIndex,       void *pData,   unsigned BufferSize);\nint          SEGGER_RTT_SetNameDownBuffer       (unsigned BufferIndex, const char *sName);\nint          SEGGER_RTT_SetNameUpBuffer         (unsigned BufferIndex, const char *sName);\nint          SEGGER_RTT_SetFlagsDownBuffer      (unsigned BufferIndex, unsigned Flags);\nint          SEGGER_RTT_SetFlagsUpBuffer        (unsigned BufferIndex, unsigned Flags);\nint          SEGGER_RTT_WaitKey                 (void);\nunsigned     SEGGER_RTT_Write                   (unsigned BufferIndex, const void *pBuffer, unsigned NumBytes);\nunsigned     SEGGER_RTT_WriteNoLock             (unsigned BufferIndex, const void *pBuffer, unsigned NumBytes);\nunsigned     SEGGER_RTT_WriteSkipNoLock         (unsigned BufferIndex, const void *pBuffer, unsigned NumBytes);\nunsigned     SEGGER_RTT_ASM_WriteSkipNoLock     (unsigned BufferIndex, const void *pBuffer, unsigned NumBytes);\nunsigned     SEGGER_RTT_WriteString             (unsigned BufferIndex, const char *s);\nvoid         SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void *pBuffer, unsigned NumBytes);\nunsigned     SEGGER_RTT_PutChar                 (unsigned BufferIndex, char c);\nunsigned     SEGGER_RTT_PutCharSkip             (unsigned BufferIndex, char c);\nunsigned     SEGGER_RTT_PutCharSkipNoLock       (unsigned BufferIndex, char c);\nunsigned     SEGGER_RTT_GetAvailWriteSpace      (unsigned BufferIndex);\nunsigned     SEGGER_RTT_GetBytesInBuffer        (unsigned BufferIndex);\n\n// Espressif specific functions\nvoid         SEGGER_RTT_ESP_FlushNoLock         (void);\nvoid         SEGGER_RTT_ESP_Flush               (void);\n\n//\n// Function macro for performance optimization\n//\n// @AGv: This macro is used inside SEGGER SystemView code.\n// For ESP32 we use our own implementation of RTT, so this macro should not check SEGGER's RTT buffer state.\n#define      SEGGER_RTT_HASDATA(n)       (1)\n\n#if RTT_USE_ASM\n#define SEGGER_RTT_WriteSkipNoLock  SEGGER_RTT_ASM_WriteSkipNoLock\n#endif\n\n/*********************************************************************\n*\n*       RTT transfer functions to send RTT data via other channels.\n*\n**********************************************************************\n*/\nunsigned     SEGGER_RTT_ReadUpBuffer            (unsigned BufferIndex, void *pBuffer, unsigned BufferSize);\nunsigned     SEGGER_RTT_ReadUpBufferNoLock      (unsigned BufferIndex, void *pData, unsigned BufferSize);\nunsigned     SEGGER_RTT_WriteDownBuffer         (unsigned BufferIndex, const void *pBuffer, unsigned NumBytes);\nunsigned     SEGGER_RTT_WriteDownBufferNoLock   (unsigned BufferIndex, const void *pBuffer, unsigned NumBytes);\n\n#define      SEGGER_RTT_HASDATA_UP(n)    (((SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[n] + SEGGER_RTT_UNCACHED_OFF))->WrOff - ((SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_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\n\n/*********************************************************************\n*\n*       RTT \"Terminal\" API functions\n*\n**********************************************************************\n*/\nint     SEGGER_RTT_SetTerminal        (unsigned char TerminalId);\nint     SEGGER_RTT_TerminalOut        (unsigned char TerminalId, const char *s);\n\n/*********************************************************************\n*\n*       RTT printf functions (require SEGGER_RTT_printf.c)\n*\n**********************************************************************\n*/\nint SEGGER_RTT_printf(unsigned BufferIndex, const char *sFormat, ...);\nint SEGGER_RTT_vprintf(unsigned BufferIndex, const char *sFormat, va_list *pParamList);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif // ifndef(SEGGER_RTT_ASM)\n\n/*********************************************************************\n*\n*       Defines\n*\n**********************************************************************\n*/\n\n//\n// Operating modes. Define behavior if buffer is full (not enough space for entire message)\n//\n#define SEGGER_RTT_MODE_NO_BLOCK_SKIP         (0)     // Skip. Do not block, output nothing. (Default)\n#define SEGGER_RTT_MODE_NO_BLOCK_TRIM         (1)     // Trim: Do not block, output as much as fits.\n#define SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL    (2)     // Block: Wait until there is space in the buffer.\n#define SEGGER_RTT_MODE_MASK                  (3)\n\n//\n// Control sequences, based on ANSI.\n// Can be used to control color, and clear the screen\n//\n#define RTT_CTRL_RESET                \"\\x1B[0m\"         // Reset to default colors\n#define RTT_CTRL_CLEAR                \"\\x1B[2J\"         // Clear screen, reposition cursor to top left\n\n#define RTT_CTRL_TEXT_BLACK           \"\\x1B[2;30m\"\n#define RTT_CTRL_TEXT_RED             \"\\x1B[2;31m\"\n#define RTT_CTRL_TEXT_GREEN           \"\\x1B[2;32m\"\n#define RTT_CTRL_TEXT_YELLOW          \"\\x1B[2;33m\"\n#define RTT_CTRL_TEXT_BLUE            \"\\x1B[2;34m\"\n#define RTT_CTRL_TEXT_MAGENTA         \"\\x1B[2;35m\"\n#define RTT_CTRL_TEXT_CYAN            \"\\x1B[2;36m\"\n#define RTT_CTRL_TEXT_WHITE           \"\\x1B[2;37m\"\n\n#define RTT_CTRL_TEXT_BRIGHT_BLACK    \"\\x1B[1;30m\"\n#define RTT_CTRL_TEXT_BRIGHT_RED      \"\\x1B[1;31m\"\n#define RTT_CTRL_TEXT_BRIGHT_GREEN    \"\\x1B[1;32m\"\n#define RTT_CTRL_TEXT_BRIGHT_YELLOW   \"\\x1B[1;33m\"\n#define RTT_CTRL_TEXT_BRIGHT_BLUE     \"\\x1B[1;34m\"\n#define RTT_CTRL_TEXT_BRIGHT_MAGENTA  \"\\x1B[1;35m\"\n#define RTT_CTRL_TEXT_BRIGHT_CYAN     \"\\x1B[1;36m\"\n#define RTT_CTRL_TEXT_BRIGHT_WHITE    \"\\x1B[1;37m\"\n\n#define RTT_CTRL_BG_BLACK             \"\\x1B[24;40m\"\n#define RTT_CTRL_BG_RED               \"\\x1B[24;41m\"\n#define RTT_CTRL_BG_GREEN             \"\\x1B[24;42m\"\n#define RTT_CTRL_BG_YELLOW            \"\\x1B[24;43m\"\n#define RTT_CTRL_BG_BLUE              \"\\x1B[24;44m\"\n#define RTT_CTRL_BG_MAGENTA           \"\\x1B[24;45m\"\n#define RTT_CTRL_BG_CYAN              \"\\x1B[24;46m\"\n#define RTT_CTRL_BG_WHITE             \"\\x1B[24;47m\"\n\n#define RTT_CTRL_BG_BRIGHT_BLACK      \"\\x1B[4;40m\"\n#define RTT_CTRL_BG_BRIGHT_RED        \"\\x1B[4;41m\"\n#define RTT_CTRL_BG_BRIGHT_GREEN      \"\\x1B[4;42m\"\n#define RTT_CTRL_BG_BRIGHT_YELLOW     \"\\x1B[4;43m\"\n#define RTT_CTRL_BG_BRIGHT_BLUE       \"\\x1B[4;44m\"\n#define RTT_CTRL_BG_BRIGHT_MAGENTA    \"\\x1B[4;45m\"\n#define RTT_CTRL_BG_BRIGHT_CYAN       \"\\x1B[4;46m\"\n#define RTT_CTRL_BG_BRIGHT_WHITE      \"\\x1B[4;47m\"\n\n\n#endif\n\n/*************************** End of file ****************************/\n"
  },
  {
    "path": "esp_sysview/src/SEGGER/SEGGER_SYSVIEW.c",
    "content": "/*\n * SPDX-FileCopyrightText: 1995-2021 SEGGER Microcontroller GmbH\n *\n * SPDX-License-Identifier: BSD-1-Clause\n *\n * SPDX-FileContributor: 2023-2024 Espressif Systems (Shanghai) CO LTD\n */\n/*********************************************************************\n*                    SEGGER Microcontroller GmbH                     *\n*                        The Embedded Experts                        *\n**********************************************************************\n*                                                                    *\n*            (c) 1995 - 2024 SEGGER Microcontroller GmbH             *\n*                                                                    *\n*       www.segger.com     Support: support@segger.com               *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SEGGER SystemView * Real-time application analysis           *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n* All rights reserved.                                               *\n*                                                                    *\n* SEGGER strongly recommends to not make any changes                 *\n* to or modify the source code of this software in order to stay     *\n* compatible with the SystemView and RTT protocol, and J-Link.       *\n*                                                                    *\n* Redistribution and use in source and binary forms, with or         *\n* without modification, are permitted provided that the following    *\n* condition is met:                                                  *\n*                                                                    *\n* o Redistributions of source code must retain the above copyright   *\n*   notice, this condition and the following disclaimer.             *\n*                                                                    *\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             *\n* CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,        *\n* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           *\n* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           *\n* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *\n* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR           *\n* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  *\n* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;    *\n* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF      *\n* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT          *\n* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE  *\n* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *\n* DAMAGE.                                                            *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SystemView version: 3.56                                    *\n*                                                                    *\n**********************************************************************\n-------------------------- END-OF-HEADER -----------------------------\n\nFile    : SEGGER_SYSVIEW.c\nPurpose : System visualization API implementation.\nRevision: $Rev: 29105 $\n\nAdditional information:\n  Packet format:\n    Packets with IDs 0..23 are standard packets with known structure.\n    For efficiency, they do *NOT* contain a length field.\n    <ID><Data><TimeStampDelta>\n\n    Packets with IDs 24..31 are standard packets with extendible\n    structure and contain a length field.\n    <ID><Length><Data><TimeStampDelta>\n\n    Packet ID 31 is used for SystemView extended events.\n    <ID><Length><ID_EX><Data><TimeStampDelta>\n\n    Packets with IDs >= 32 always contain a length field.\n    <ID><Length><Data><TimeStampDelta>\n\n  Packet IDs:\n       0..  31 : Standard packets, known by SystemView.\n      32..1023 : OS-definable packets, described in a SystemView description file.\n    1024..2047 : User-definable packets, described in a SystemView description file.\n    2048..32767: Undefined.\n\n  Data encoding:\n    Basic types (int, short, char, ...):\n      Basic types are encoded little endian with most-significant bit variant\n      encoding.\n      Each encoded byte contains 7 data bits [6:0] and the MSB continuation bit.\n      The continuation bit indicates whether the next byte belongs to the data\n      (bit set) or this is the last byte (bit clear).\n      The most significant bits of data are encoded first, proceeding to the\n      least significant bits in the final byte (little endian).\n\n      Example encoding:\n        Data: 0x1F4 (500)\n        Encoded: 0xF4 (First 7 data bits 74 | Continuation bit)\n                 0x03 (Second 7 data bits 03, no continuation)\n\n        Data: 0xFFFFFFFF\n        Encoded: 0xFF 0xFF 0xFF 0xFF 0x0F\n\n        Data: 0xA2 (162),   0x03 (3), 0x7000\n        Encoded: 0xA2 0x01  0x03      0x80 0xE0 0x01\n\n    Byte arrays and strings:\n      Byte arrays and strings are encoded as <NumBytes> followed by the raw data.\n      NumBytes is encoded as a basic type with a theoretical maximum of 4G.\n\n      Example encoding:\n        Data: \"Hello World\\0\" (0x48 0x65 0x6C 0x6C 0x6F 0x20 0x57 0x6F 0x72 0x6C 0x64 0x00)\n        Encoded: 0x0B 0x48 0x65 0x6C 0x6C 0x6F 0x20 0x57 0x6F 0x72 0x6C 0x64\n\n  Examples packets:\n  01 F4 03 80 80 10 // Overflow packet. Data is a single U32.\n                       This packet means: 500 packets lost, Timestamp is 0x40000\n\n  02 0F 50          // ISR(15) Enter. Timestamp 80 (0x50)\n\n  03 20             // ISR Exit. Timestamp 32 (0x20) (Shortest possible packet.)\n\n  Sample code for user defined Packets:\n    #define MY_ID   0x400                // Any value between 0x400 and 0x7FF\n    void SendMyPacket(unsigned Para0, unsigned Para1, const char* s) {\n      U8  aPacket[SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + MAX_STR_LEN + 1];\n      U8* pPayload;\n      //\n      pPayload = SEGGER_SYSVIEW_PPREPARE_PACKET(aPacket);               // Prepare the packet for SystemView\n      pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, Para0);             // Add the first parameter to the packet\n      pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, Para1);             // Add the second parameter to the packet\n      pPayload = SEGGER_SYSVIEW_EncodeString(pPayload, s, MAX_STR_LEN); // Add the string to the packet\n      //\n      SEGGER_SYSVIEW_SendPacket(&aPacket[0], pPayload, MY_ID);          // Send the packet with EventId = MY_ID\n    }\n\n    #define MY_ID_1 0x401\n    void SendOnePara(unsigned Para0) {\n      SEGGER_SYSVIEW_RecordU32(MY_ID_1, Para0);\n    }\n\n*/\n\n/*********************************************************************\n*\n*       #include section\n*\n**********************************************************************\n*/\n\n#define SEGGER_SYSVIEW_C  // For EXTERN statements in SEGGER_SYSVIEW.h\n\n#include <string.h>\n#include <stdlib.h>\n#include <stdarg.h>\n#include <assert.h>\n#include \"SEGGER_SYSVIEW_Int.h\"\n#include \"SEGGER_RTT.h\"\n\n/*********************************************************************\n*\n*       Defines, fixed\n*\n**********************************************************************\n*/\n#if SEGGER_SYSVIEW_ID_SHIFT\n#define SHRINK_ID(Id)   (((Id) - _SYSVIEW_Globals.RAMBaseAddress) >> SEGGER_SYSVIEW_ID_SHIFT)\n#else\n#define SHRINK_ID(Id)   ((Id) - _SYSVIEW_Globals.RAMBaseAddress)\n#endif\n\n#if SEGGER_SYSVIEW_RTT_CHANNEL > 0\n#define CHANNEL_ID_UP   SEGGER_SYSVIEW_RTT_CHANNEL\n#define CHANNEL_ID_DOWN SEGGER_SYSVIEW_RTT_CHANNEL\n#else\n#define CHANNEL_ID_UP   _SYSVIEW_Globals.UpChannel\n#define CHANNEL_ID_DOWN _SYSVIEW_Globals.DownChannel\n#endif\n\n#if SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE\n#if (SEGGER_SYSVIEW_RTT_BUFFER_SIZE % SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE)\n#error \"SEGGER_SYSVIEW_RTT_BUFFER_SIZE must be a multiple of SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE\"\n#endif\n#endif\n\n/*********************************************************************\n*\n*       Defines, configurable\n*\n**********************************************************************\n*/\n// Timestamps may be less than full 32-bits, in which case we need to zero\n// the unused bits to properly handle overflows.\n// Note that this is a quite common scenario, as a 32-bit time such as\n// SysTick might be scaled down to reduce bandwidth\n// or a 16-bit hardware time might be used.\n#if SEGGER_SYSVIEW_TIMESTAMP_BITS < 32  // Eliminate unused bits in case hardware timestamps are less than 32 bits\n#define MAKE_DELTA_32BIT(Delta) Delta <<= 32 - SEGGER_SYSVIEW_TIMESTAMP_BITS; \\\n                                  Delta >>= 32 - SEGGER_SYSVIEW_TIMESTAMP_BITS;\n#else\n#define MAKE_DELTA_32BIT(Delta)\n#endif\n\n#if SEGGER_SYSVIEW_SUPPORT_LONG_ID\n#define _MAX_ID_BYTES       5u\n#else\n#define _MAX_ID_BYTES       2u\n#endif\n\n#if SEGGER_SYSVIEW_SUPPORT_LONG_DATA\n#define _MAX_DATA_BYTES     5u\n#else\n#define _MAX_DATA_BYTES     2u\n#endif\n\n/*********************************************************************\n*\n*       Defines, fixed\n*\n**********************************************************************\n*/\n#define ENABLE_STATE_OFF        0\n#define ENABLE_STATE_ON         1\n#define ENABLE_STATE_DROPPING   2\n\n#define FORMAT_FLAG_LEFT_JUSTIFY   (1u << 0)\n#define FORMAT_FLAG_PAD_ZERO       (1u << 1)\n#define FORMAT_FLAG_PRINT_SIGN     (1u << 2)\n#define FORMAT_FLAG_ALTERNATE      (1u << 3)\n\n#define MODULE_EVENT_OFFSET        (512)\n\n/*********************************************************************\n*\n*       Types, local\n*\n**********************************************************************\n*/\ntypedef struct {\n    U8       *pBuffer;\n    U8       *pPayload;\n    U8       *pPayloadStart;\n    U32       Options;\n    unsigned  Cnt;\n} SEGGER_SYSVIEW_PRINTF_DESC;\n\ntypedef struct {\n    U8                      EnableState;   // 0: Disabled, 1: Enabled, (2: Dropping)\n    U8                      UpChannel;\n    U8                      RecursionCnt;\n    U32                     SysFreq;\n    U32                     CPUFreq;\n    U32                     LastTxTimeStamp;\n    U32                     RAMBaseAddress;\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE == 1)\n    U32                     PacketCount;\n#else\n    U32                     DropCount;\n    U8                      DownChannel;\n#endif\n    U32                     DisabledEvents;\n    const SEGGER_SYSVIEW_OS_API  *pOSAPI;\n    SEGGER_SYSVIEW_SEND_SYS_DESC_FUNC   *pfSendSysDesc;\n} SEGGER_SYSVIEW_GLOBALS;\n\n/*********************************************************************\n*\n*       Function prototypes, required\n*\n**********************************************************************\n*/\nstatic void _SendPacket(U8 *pStartPacket, U8 *pEndPacket, unsigned int EventId);\n\n/*********************************************************************\n*\n*       Static data\n*\n**********************************************************************\n*/\nstatic const U8 _abSync[10] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n\n#if SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE\n#ifdef SEGGER_SYSVIEW_SECTION\n//\n// Alignment + special section required\n//\n#if (defined __GNUC__)\n__attribute__ ((section (SEGGER_SYSVIEW_SECTION), aligned (SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE))) static char _UpBuffer  [SEGGER_SYSVIEW_RTT_BUFFER_SIZE];\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1)\n__attribute__ ((section (SEGGER_SYSVIEW_SECTION), aligned (SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE))) static char _DownBuffer[8];  // Small, fixed-size buffer, for back-channel comms\n#endif\n#elif (defined __ICCARM__) || (defined __ICCRX__)\n#pragma location=SEGGER_SYSVIEW_SECTION\n#pragma data_alignment=SEGGER_RTT_CPU_CACHE_LINE_SIZE\nstatic char _UpBuffer  [SEGGER_SYSVIEW_RTT_BUFFER_SIZE];\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1)\n#pragma location=SEGGER_SYSVIEW_SECTION\n#pragma data_alignment=SEGGER_RTT_CPU_CACHE_LINE_SIZE\nstatic char _DownBuffer[8];  // Small, fixed-size buffer, for back-channel comms\n#endif\n#elif (defined __CC_ARM)\n__attribute__ ((section (SEGGER_SYSVIEW_SECTION), aligned (SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE), zero_init)) static char _UpBuffer  [SEGGER_SYSVIEW_RTT_BUFFER_SIZE];\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1)\n__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\n#endif\n#else\n#error \"Do not know how to place SystemView buffers in specific section\"\n#endif\n#else\n//\n// Only alignment required\n//\n#if (defined __GNUC__)\n__attribute__ ((aligned (SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE))) static char _UpBuffer  [SEGGER_SYSVIEW_RTT_BUFFER_SIZE];\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1)\n__attribute__ ((aligned (SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE))) static char _DownBuffer[8];  // Small, fixed-size buffer, for back-channel comms\n#endif\n#elif (defined __ICCARM__) || (defined __ICCRX__)\n#pragma data_alignment=SEGGER_RTT_CPU_CACHE_LINE_SIZE\nstatic char _UpBuffer  [SEGGER_SYSVIEW_RTT_BUFFER_SIZE];\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1)\n#pragma data_alignment=SEGGER_RTT_CPU_CACHE_LINE_SIZE\nstatic char _DownBuffer[8];  // Small, fixed-size buffer, for back-channel comms\n#endif\n#elif (defined __CC_ARM)\n__attribute__ ((aligned (SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE), zero_init)) static char _UpBuffer  [SEGGER_SYSVIEW_RTT_BUFFER_SIZE];\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1)\n__attribute__ ((aligned (SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE), zero_init)) static char _DownBuffer[8];  // Small, fixed-size buffer, for back-channel comms\n#endif\n#else\n#error \"Do not know how to align SystemView buffers to cache line size\"\n#endif\n#endif\n#else\n#ifdef SEGGER_SYSVIEW_SECTION\n//\n// Only special section required\n//\n#if (defined __GNUC__)\n__attribute__ ((section (SEGGER_SYSVIEW_SECTION))) static char _UpBuffer  [SEGGER_SYSVIEW_RTT_BUFFER_SIZE];\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1)\n__attribute__ ((section (SEGGER_SYSVIEW_SECTION))) static char _DownBuffer[8];  // Small, fixed-size buffer, for back-channel comms\n#endif\n#elif (defined __ICCARM__) || (defined __ICCRX__)\n#pragma location=SEGGER_SYSVIEW_SECTION\nstatic char _UpBuffer  [SEGGER_SYSVIEW_RTT_BUFFER_SIZE];\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1)\n#pragma location=SEGGER_SYSVIEW_SECTION\nstatic char _DownBuffer[8];  // Small, fixed-size buffer, for back-channel comms\n#endif\n#elif (defined __CC_ARM)\n__attribute__ ((section (SEGGER_SYSVIEW_SECTION), zero_init)) static char _UpBuffer  [SEGGER_SYSVIEW_RTT_BUFFER_SIZE];\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1)\n__attribute__ ((section (SEGGER_SYSVIEW_SECTION), zero_init)) static char _DownBuffer[8];  // Small, fixed-size buffer, for back-channel comms\n#endif\n#else\n#error \"Do not know how to place SystemView buffers in specific section\"\n#endif\n#else\n//\n// Neither special section nor alignment required\n//\nstatic char _UpBuffer  [SEGGER_SYSVIEW_RTT_BUFFER_SIZE];\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1)\nstatic char _DownBuffer[8];  // Small, fixed-size buffer, for back-channel comms\n#endif\n#endif\n#endif\n\nstatic SEGGER_SYSVIEW_GLOBALS _SYSVIEW_Globals;\n\nstatic SEGGER_SYSVIEW_MODULE *_pFirstModule;\nstatic U8                     _NumModules;\n\n/*********************************************************************\n*\n*       Static code\n*\n**********************************************************************\n*/\n\n#define ENCODE_U32(pDest, Value) {                                                  \\\n                                   U8* pSysviewPointer;                             \\\n                                   U32 SysViewData;                                 \\\n                                   pSysviewPointer = pDest;                         \\\n                                   SysViewData = Value;                             \\\n                                   while(SysViewData > 0x7F) {                      \\\n                                     *pSysviewPointer++ = (U8)(SysViewData | 0x80); \\\n                                     SysViewData >>= 7;                             \\\n                                   };                                               \\\n                                   *pSysviewPointer++ = (U8)SysViewData;            \\\n                                   pDest = pSysviewPointer;                         \\\n                                 };\n\n#if (SEGGER_SYSVIEW_USE_STATIC_BUFFER == 1)\nstatic U8 _aPacket[SEGGER_SYSVIEW_MAX_PACKET_SIZE];\n\n#define RECORD_START(PacketSize)  SEGGER_SYSVIEW_LOCK();                            \\\n                                  pPayloadStart = _PreparePacket(_aPacket);\n\n#define RECORD_END()              SEGGER_SYSVIEW_UNLOCK()\n\n#else\n\n#define RECORD_START(PacketSize)  U8 aPacket[(PacketSize)];                         \\\n                                  pPayloadStart = _PreparePacket(aPacket);          \\\n\n#define RECORD_END()\n\n#endif\n\n/*********************************************************************\n*\n*       _EncodeData()\n*\n*  Function description\n*    Encode a byte buffer in variable-length format.\n*\n*  Parameters\n*    pPayload - Pointer to where string will be encoded.\n*    pSrc     - Pointer to data buffer to be encoded.\n*    NumBytes - Number of bytes in the buffer to be encoded.\n*\n*  Return value\n*    Pointer to the byte following the value, i.e. the first free\n*    byte in the payload and the next position to store payload\n*    content.\n*\n*  Additional information\n*    The data is encoded as a count byte followed by the contents\n*    of the data buffer.\n*    Make sure NumBytes + 1 bytes are free for the payload.\n*/\nstatic U8 *_EncodeData(U8 *pPayload, const char *pSrc, unsigned int NumBytes)\n{\n    unsigned int  n;\n    const U8     *p;\n\n    // Espressif doesn't support larger packages yet. Encode data length must be less than 255.\n    assert(NumBytes < 255);\n    //\n    n = 0;\n    p = (const U8 *)pSrc;\n    //\n    // Write Len\n    //\n    if (NumBytes < 255)  {\n        *pPayload++ = (U8)NumBytes;\n    } else {\n        *pPayload++ = 255;\n        *pPayload++ = ((NumBytes >> 8) & 255);\n        *pPayload++ = (NumBytes & 255);\n    }\n    while (n < NumBytes) {\n        *pPayload++ = *p++;\n        n++;\n    }\n    return pPayload;\n}\n\n/*********************************************************************\n*\n*       _EncodeFloat()\n*\n*  Function description\n*    Encode a float value in variable-length format.\n*\n*  Parameters\n*    pPayload - Pointer to where value will be encoded.\n*    Value    - Value to be encoded.\n*\n*  Return value\n*    Pointer to the byte following the value, i.e. the first free\n*    byte in the payload and the next position to store payload\n*    content.\n*/\nstatic U8 *_EncodeFloat(U8 *pPayload, float Value)\n{\n    float Val = Value;\n    U8 *pSysviewPointer;\n    U32 *SysViewData;\n    pSysviewPointer = pPayload;\n    SysViewData = (U32 *)&Val;\n    while ((*SysViewData) > 0x7F) {\n        *pSysviewPointer++ = (U8)((*SysViewData) | 0x80);\n        (*SysViewData) >>= 7;\n    };\n    *pSysviewPointer++ = (U8)(*SysViewData);\n    pPayload = pSysviewPointer;\n\n    return pPayload;\n}\n\n/*********************************************************************\n*\n*       _EncodeStr()\n*\n*  Function description\n*    Encode a string in variable-length format.\n*\n*  Parameters\n*    pPayload - Pointer to where string will be encoded.\n*    pText    - String to encode.\n*    Limit    - Maximum number of characters to encode from string.\n*\n*  Return value\n*    Pointer to the byte following the value, i.e. the first free\n*    byte in the payload and the next position to store payload\n*    content.\n*\n*  Additional information\n*    The string is encoded as a count byte followed by the contents\n*    of the string.\n*    No more than 1 + Limit bytes will be encoded to the payload.\n*/\nstatic U8 *_EncodeStr(U8 *pPayload, const char *pText, unsigned int Limit)\n{\n    U8 *pLen;\n    const char *sStart;\n\n    if (pText == NULL) {\n        *pPayload++ = (U8)0;\n    } else {\n        sStart = pText; // Remember start of string.\n        //\n        // Save space to store count byte(s).\n        //\n        pLen = pPayload++;\n#if (SEGGER_SYSVIEW_MAX_STRING_LEN >= 255)  // Length always encodes in 3 bytes\n        pPayload += 2;\n#endif\n        //\n        // Limit string to maximum length and copy into payload buffer.\n        //\n        if (Limit > SEGGER_SYSVIEW_MAX_STRING_LEN) {\n            Limit = SEGGER_SYSVIEW_MAX_STRING_LEN;\n        }\n        while ((Limit-- > 0) && (*pText != '\\0')) {\n            *pPayload++ = *pText++;\n        }\n        //\n        // Save string length to buffer.\n        //\n#if (SEGGER_SYSVIEW_MAX_STRING_LEN >= 255)  // Length always encodes in 3 bytes\n        Limit = (unsigned int)(pText - sStart);\n        *pLen++ = (U8)255;\n        *pLen++ = (U8)((Limit >> 8) & 255);\n        *pLen++ = (U8)(Limit & 255);\n#else   // Length always encodes in 1 byte\n        *pLen = (U8)(pText - sStart);\n#endif\n    }\n    //\n    return pPayload;\n}\n\n/*********************************************************************\n*\n*       _PreparePacket()\n*\n*  Function description\n*    Prepare a SystemView event packet header.\n*\n*  Parameters\n*    pPacket - Pointer to start of packet to initialize.\n*\n*  Return value\n*    Pointer to first byte of packet payload.\n*\n*  Additional information\n*    The payload length and evnetId are not initialized.\n*    PreparePacket only reserves space for them and they are\n*    computed and filled in by the sending function.\n*/\nstatic U8 *_PreparePacket(U8 *pPacket)\n{\n    return pPacket + _MAX_ID_BYTES + _MAX_DATA_BYTES;\n}\n\n/*********************************************************************\n*\n*       _HandleIncomingPacket()\n*\n*  Function description\n*    Read an incoming command from the down channel and process it.\n*\n*  Additional information\n*    This function is called each time after sending a packet.\n*    Processing incoming packets is done asynchronous. SystemView might\n*    already have sent event packets after the host has sent a command.\n*/\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1)\nstatic void _HandleIncomingPacket(void)\n{\n    U8  Cmd;\n    unsigned int Status;\n    //\n    Status = SEGGER_RTT_ReadNoLock(CHANNEL_ID_DOWN, &Cmd, 1);\n    if (Status > 0) {\n        switch (Cmd) {\n        case SEGGER_SYSVIEW_COMMAND_ID_START:\n            SEGGER_SYSVIEW_Start();\n            break;\n        case SEGGER_SYSVIEW_COMMAND_ID_STOP:\n            SEGGER_SYSVIEW_Stop();\n            break;\n        case SEGGER_SYSVIEW_COMMAND_ID_GET_SYSTIME:\n            SEGGER_SYSVIEW_RecordSystime();\n            break;\n        case SEGGER_SYSVIEW_COMMAND_ID_GET_TASKLIST:\n            SEGGER_SYSVIEW_SendTaskList();\n            break;\n        case SEGGER_SYSVIEW_COMMAND_ID_GET_SYSDESC:\n            SEGGER_SYSVIEW_GetSysDesc();\n            break;\n        case SEGGER_SYSVIEW_COMMAND_ID_GET_NUMMODULES:\n            SEGGER_SYSVIEW_SendNumModules();\n            break;\n        case SEGGER_SYSVIEW_COMMAND_ID_GET_MODULEDESC:\n            SEGGER_SYSVIEW_SendModuleDescription();\n            break;\n        case SEGGER_SYSVIEW_COMMAND_ID_GET_MODULE:\n            Status = SEGGER_RTT_ReadNoLock(CHANNEL_ID_DOWN, &Cmd, 1);\n            if (Status > 0) {\n                SEGGER_SYSVIEW_SendModule(Cmd);\n            }\n            break;\n        case SEGGER_SYSVIEW_COMMAND_ID_HEARTBEAT:\n            break;\n        default:\n            if (Cmd >= 128) { // Unknown extended command. Dummy read its parameter.\n                SEGGER_RTT_ReadNoLock(CHANNEL_ID_DOWN, &Cmd, 1);\n            }\n            break;\n        }\n    }\n}\n#endif // (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1)\n\n/*********************************************************************\n*\n*       _TrySendOverflowPacket()\n*\n*  Function description\n*    Try to transmit an SystemView Overflow packet containing the\n*    number of dropped packets.\n*\n*  Additional information\n*    Format as follows:\n*      01 <DropCnt><TimeStamp>  Max. packet len is 1 + 5 + 5 = 11\n*\n*    Example packets sent\n*      01 20 40\n*\n*  Return value\n*    !=0:  Success, Message sent (stored in RTT-Buffer)\n*    ==0:  Buffer full, Message *NOT* stored\n*\n*/\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1)\nstatic int _TrySendOverflowPacket(void)\n{\n    U32 TimeStamp;\n    I32 Delta;\n    int Status;\n    U8  aPacket[11];\n    U8 *pPayload;\n\n    aPacket[0] = SYSVIEW_EVTID_OVERFLOW;      // 1\n    pPayload   = &aPacket[1];\n    ENCODE_U32(pPayload, _SYSVIEW_Globals.DropCount);\n    //\n    // Compute time stamp delta and append it to packet.\n    //\n    TimeStamp  = SEGGER_SYSVIEW_GET_TIMESTAMP();\n    Delta = TimeStamp - _SYSVIEW_Globals.LastTxTimeStamp;\n    MAKE_DELTA_32BIT(Delta);\n    ENCODE_U32(pPayload, Delta);\n    //\n    // Try to store packet in RTT buffer and update time stamp when this was successful\n    //\n    Status = (int)SEGGER_RTT_WriteSkipNoLock(CHANNEL_ID_UP, aPacket, (unsigned int)(pPayload - aPacket));\n    SEGGER_SYSVIEW_ON_EVENT_RECORDED(pPayload - aPacket);\n    if (Status) {\n        _SYSVIEW_Globals.LastTxTimeStamp = TimeStamp;\n        _SYSVIEW_Globals.EnableState--; // EnableState has been 2, will be 1. Always.\n    } else {\n        _SYSVIEW_Globals.DropCount++;\n    }\n    //\n    return Status;\n}\n#endif  // (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1)\n\n/*********************************************************************\n*\n*       _SendSyncInfo()\n*\n*  Function description\n*    Send SystemView sync packet and system information in\n*    post mortem mode.\n*\n*  Additional information\n*    Sync is 10 * 0x00 without timestamp\n*/\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE == 1)\nstatic void _SendSyncInfo(void)\n{\n    //\n    // Add sync packet ( 10 * 0x00)\n    // Send system description\n    // Send system time\n    // Send task list\n    // Send module description\n    // Send module information\n    //\n    SEGGER_RTT_WriteWithOverwriteNoLock(CHANNEL_ID_UP, _abSync, 10);\n    SEGGER_SYSVIEW_ON_EVENT_RECORDED(10);\n    SEGGER_SYSVIEW_RecordVoid(SYSVIEW_EVTID_TRACE_START);\n    {\n        U8 *pPayload;\n        U8 *pPayloadStart;\n        RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 4 * SEGGER_SYSVIEW_QUANTA_U32);\n        //\n        pPayload = pPayloadStart;\n        ENCODE_U32(pPayload, _SYSVIEW_Globals.SysFreq);\n        ENCODE_U32(pPayload, _SYSVIEW_Globals.CPUFreq);\n        ENCODE_U32(pPayload, _SYSVIEW_Globals.RAMBaseAddress);\n        ENCODE_U32(pPayload, SEGGER_SYSVIEW_ID_SHIFT);\n        _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_INIT);\n        RECORD_END();\n    }\n    if (_SYSVIEW_Globals.pfSendSysDesc) {\n        _SYSVIEW_Globals.pfSendSysDesc();\n    }\n    SEGGER_SYSVIEW_RecordSystime();\n    SEGGER_SYSVIEW_SendTaskList();\n    if (_NumModules > 0) {\n        int n;\n        SEGGER_SYSVIEW_SendNumModules();\n        for (n = 0; n < _NumModules; n++) {\n            SEGGER_SYSVIEW_SendModule(n);\n        }\n    }\n}\n#endif  // (SEGGER_SYSVIEW_POST_MORTEM_MODE == 1)\n\n/*********************************************************************\n*\n*       _SendPacket()\n*\n*  Function description\n*    Send a SystemView packet over RTT. RTT channel and mode are\n*    configured by macros when the SystemView component is initialized.\n*    This function takes care of maintaining the packet drop count\n*    and sending overflow packets when necessary.\n*    The packet must be passed without Id and Length because this\n*    function prepends it to the packet before transmission.\n*\n*  Parameters\n*    pStartPacket - Pointer to start of packet payload.\n*                   There must be at least 4 bytes free to prepend Id and Length.\n*    pEndPacket   - Pointer to end of packet payload.\n*    EventId      - Id of the event to send.\n*\n*/\nstatic void _SendPacket(U8 *pStartPacket, U8 *pEndPacket, unsigned int EventId)\n{\n    unsigned int  NumBytes;\n    U32           TimeStamp;\n    U32           Delta;\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1)\n    unsigned int  Status;\n#endif\n\n#if (SEGGER_SYSVIEW_USE_STATIC_BUFFER == 0)\n    SEGGER_SYSVIEW_LOCK();\n#endif\n\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE == 1)\n    if (_SYSVIEW_Globals.EnableState == 0) {\n        goto SendDone;\n    }\n#else\n    if (_SYSVIEW_Globals.EnableState == 1) {  // Enabled, no dropped packets remaining\n        goto Send;\n    }\n    if (_SYSVIEW_Globals.EnableState == 0) {\n        goto SendDone;\n    }\n    //\n    // Handle buffer full situations:\n    // Have packets been dropped before because buffer was full?\n    // In this case try to send and overflow packet.\n    //\n    if (_SYSVIEW_Globals.EnableState == 2) {\n        _TrySendOverflowPacket();\n        if (_SYSVIEW_Globals.EnableState != 1) {\n            goto SendDone;\n        }\n    }\nSend:\n#endif\n    //\n    // Check if event is disabled from being recorded.\n    //\n    if (EventId < 32) {\n        if (_SYSVIEW_Globals.DisabledEvents & ((U32)1u << EventId)) {\n            goto SendDone;\n        }\n    }\n    //\n    // Prepare actual packet.\n    // If it is a known packet, prepend eventId only,\n    // otherwise prepend packet length and eventId.\n    //\n    if (EventId < 24) {\n        *--pStartPacket = (U8)EventId;\n    } else {\n        //\n        // Get data length and prepend it.\n        //\n        NumBytes = (unsigned int)(pEndPacket - pStartPacket);\n#if SEGGER_SYSVIEW_SUPPORT_LONG_DATA\n        if (NumBytes < 127) {\n#error \"Seems EventId should be changed to NumBytes in the next line. Please check.\"\n            *--pStartPacket = EventId;\n        } else {\n            //\n            // Backwards U32 encode EventId.\n            //\n            if (NumBytes < (1ul << 14)) { // Encodes in 2 bytes\n                *--pStartPacket = (U8)(NumBytes >>  7);\n                *--pStartPacket = (U8)(NumBytes | 0x80);\n            } else if (NumBytes < (1ul << 21)) {    // Encodes in 3 bytes\n                *--pStartPacket = (U8)(NumBytes >> 14);\n                *--pStartPacket = (U8)((NumBytes >>  7) | 0x80);\n                *--pStartPacket = (U8)(NumBytes | 0x80);\n            } else if (NumBytes < (1ul << 28)) {    // Encodes in 4 bytes\n                *--pStartPacket = (U8)(NumBytes >> 21);\n                *--pStartPacket = (U8)((NumBytes >> 14) | 0x80);\n                *--pStartPacket = (U8)((NumBytes >>  7) | 0x80);\n                *--pStartPacket = (U8)(NumBytes | 0x80);\n            } else {                              // Encodes in 5 bytes\n                *--pStartPacket = (U8)(NumBytes >> 28);\n                *--pStartPacket = (U8)((NumBytes >> 21) | 0x80);\n                *--pStartPacket = (U8)((NumBytes >> 14) | 0x80);\n                *--pStartPacket = (U8)((NumBytes >>  7) | 0x80);\n                *--pStartPacket = (U8)(NumBytes | 0x80);\n            }\n        }\n#else\n        if (NumBytes > 127) {\n            *--pStartPacket = (U8)(NumBytes >> 7);\n            *--pStartPacket = (U8)(NumBytes | 0x80);\n        } else {\n            *--pStartPacket = (U8)NumBytes;\n        }\n#endif\n        //\n        // Prepend EventId.\n        //\n#if SEGGER_SYSVIEW_SUPPORT_LONG_ID\n        if (EventId < 127) {\n            *--pStartPacket = (U8)EventId;\n        } else {\n            //\n            // Backwards U32 encode EventId.\n            //\n            if (EventId < (1u << 14)) { // Encodes in 2 bytes\n                *--pStartPacket = (U8)(EventId >>  7);\n                *--pStartPacket = (U8)(EventId | 0x80);\n            } else if (EventId < (1ul << 21)) {    // Encodes in 3 bytes\n                *--pStartPacket = (U8)(EventId >> 14);\n                *--pStartPacket = (U8)((EventId >>  7) | 0x80);\n                *--pStartPacket = (U8)(EventId | 0x80);\n            } else if (EventId < (1ul << 28)) {    // Encodes in 4 bytes\n                *--pStartPacket = (U8)(EventId >> 21);\n                *--pStartPacket = (U8)((EventId >> 14) | 0x80);\n                *--pStartPacket = (U8)((EventId >>  7) | 0x80);\n                *--pStartPacket = (U8)(EventId | 0x80);\n            } else {                              // Encodes in 5 bytes\n                *--pStartPacket = (U8)(EventId >> 28);\n                *--pStartPacket = (U8)((EventId >> 21) | 0x80);\n                *--pStartPacket = (U8)((EventId >> 14) | 0x80);\n                *--pStartPacket = (U8)((EventId >>  7) | 0x80);\n                *--pStartPacket = (U8)(EventId | 0x80);\n            }\n        }\n#else\n        if (EventId > 127) {\n            *--pStartPacket = (U8)(EventId >> 7);\n            *--pStartPacket = (U8)(EventId | 0x80);\n        } else {\n            *--pStartPacket = (U8)EventId;\n        }\n#endif\n    }\n    //\n    // Compute time stamp delta and append it to packet.\n    //\n    TimeStamp  = SEGGER_SYSVIEW_GET_TIMESTAMP();\n    Delta = TimeStamp - _SYSVIEW_Globals.LastTxTimeStamp;\n    MAKE_DELTA_32BIT(Delta);\n    ENCODE_U32(pEndPacket, Delta);\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE == 1)\n    //\n    // Store packet in RTT buffer by overwriting old data and update time stamp\n    //\n    SEGGER_RTT_WriteWithOverwriteNoLock(CHANNEL_ID_UP, pStartPacket, pEndPacket - pStartPacket);\n    SEGGER_SYSVIEW_ON_EVENT_RECORDED(pEndPacket - pStartPacket);\n    _SYSVIEW_Globals.LastTxTimeStamp = TimeStamp;\n#else\n    //\n    // Try to store packet in RTT buffer and update time stamp when this was successful\n    //\n    Status = SEGGER_RTT_WriteSkipNoLock(CHANNEL_ID_UP, pStartPacket, (unsigned int)(pEndPacket - pStartPacket));\n    SEGGER_SYSVIEW_ON_EVENT_RECORDED(pEndPacket - pStartPacket);\n    if (Status) {\n        _SYSVIEW_Globals.LastTxTimeStamp = TimeStamp;\n    } else {\n        _SYSVIEW_Globals.EnableState++; // EnableState has been 1, will be 2. Always.\n    }\n#endif\n\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE == 1)\n    //\n    // Add sync and system information periodically if we are in post mortem mode\n    //\n    if (_SYSVIEW_Globals.RecursionCnt == 0) {   // Avoid uncontrolled nesting. This way, this routine can call itself once, but no more often than that.\n        _SYSVIEW_Globals.RecursionCnt = 1;\n        if (_SYSVIEW_Globals.PacketCount++ & (1 << SEGGER_SYSVIEW_SYNC_PERIOD_SHIFT)) {\n            _SendSyncInfo();\n            _SYSVIEW_Globals.PacketCount = 0;\n        }\n        _SYSVIEW_Globals.RecursionCnt = 0;\n    }\nSendDone:\n    ; // Avoid \"label at end of compound statement\" error when using static buffer\n#else\nSendDone:\n    //\n    // Check if host is sending data which needs to be processed.\n    // Note that since this code is called for every packet, it is very time critical, so we do\n    // only what is really needed here, which is checking if there is any data\n    //\n    if (SEGGER_RTT_HASDATA(CHANNEL_ID_DOWN)) {\n        if (_SYSVIEW_Globals.RecursionCnt == 0) {   // Avoid uncontrolled nesting. This way, this routine can call itself once, but no more often than that.\n            _SYSVIEW_Globals.RecursionCnt = 1;\n            _HandleIncomingPacket();\n            _SYSVIEW_Globals.RecursionCnt = 0;\n        }\n    }\n#endif\n    //\n#if (SEGGER_SYSVIEW_USE_STATIC_BUFFER == 0)\n    SEGGER_SYSVIEW_UNLOCK();  // We are done. Unlock and return\n#endif\n}\n\n#ifndef SEGGER_SYSVIEW_EXCLUDE_PRINTF // Define in project to avoid warnings about variable parameter list\n/*********************************************************************\n*\n*       _VPrintHost()\n*\n*  Function description\n*    Send a format string and its parameters to the host.\n*\n*  Parameters\n*    s            Pointer to format string.\n*    Options      Options to be sent to the host.\n*    pParamList   Pointer to the list of arguments for the format string.\n*/\nstatic int _VPrintHost(const char *s, U32 Options, va_list *pParamList)\n{\n    U32         aParas[SEGGER_SYSVIEW_MAX_ARGUMENTS];\n    U32        *pParas;\n    U32         NumArguments;\n    const char *p;\n    char        c;\n    U8         *pPayload;\n    U8         *pPayloadStart;\n#if SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT\n    U8 HasNonScalar;\n\n    HasNonScalar = 0;\n#endif\n    //\n    // Count number of arguments by counting '%' characters in string.\n    // If enabled, check for non-scalar modifier flags to format string on the target.\n    //\n    p = s;\n    NumArguments = 0;\n    for (;;) {\n        c = *p++;\n        if (c == 0) {\n            break;\n        }\n        if (c == '%') {\n            c = *p;\n#if SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT == 0\n            aParas[NumArguments++] = (U32)(va_arg(*pParamList, int));\n            if (NumArguments == SEGGER_SYSVIEW_MAX_ARGUMENTS) {\n                break;\n            }\n#else\n            if (c == 's') {\n                HasNonScalar = 1;\n                break;\n            } else {\n                aParas[NumArguments++] = (U32)(va_arg(*pParamList, int));\n                if (NumArguments == SEGGER_SYSVIEW_MAX_ARGUMENTS) {\n                    break;\n                }\n            }\n#endif\n        }\n    }\n\n#if SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT\n    if (HasNonScalar) {\n        return -1;\n    }\n#endif\n    //\n    // Send string and parameters to host\n    //\n    {\n        RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_MAX_STRING_LEN + 2 * SEGGER_SYSVIEW_QUANTA_U32 + SEGGER_SYSVIEW_MAX_ARGUMENTS * SEGGER_SYSVIEW_QUANTA_U32);\n        pPayload = _EncodeStr(pPayloadStart, s, SEGGER_SYSVIEW_MAX_STRING_LEN);\n        ENCODE_U32(pPayload, Options);\n        ENCODE_U32(pPayload, NumArguments);\n        pParas = aParas;\n        while (NumArguments--) {\n            ENCODE_U32(pPayload, (*pParas));\n            pParas++;\n        }\n        _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_PRINT_FORMATTED);\n        RECORD_END();\n    }\n    return 0;\n}\n\n/*********************************************************************\n*\n*       _StoreChar()\n*\n*  Function description\n*    Stores a character in the printf-buffer and sends the buffer when\n*     it is filled.\n*\n*  Parameters\n*    p            Pointer to the buffer description.\n*    c            Character to be printed.\n*/\nstatic void _StoreChar(SEGGER_SYSVIEW_PRINTF_DESC *p, char c)\n{\n    unsigned int  Cnt;\n    U8           *pPayload;\n    U32           Options;\n\n    Cnt = p->Cnt;\n    if ((Cnt + 1u) <= SEGGER_SYSVIEW_MAX_STRING_LEN) {\n        *(p->pPayload++) = (U8)c;\n        p->Cnt = Cnt + 1u;\n    }\n    //\n    // Write part of string, when the buffer is full\n    //\n    if (p->Cnt == SEGGER_SYSVIEW_MAX_STRING_LEN) {\n        *(p->pPayloadStart) = (U8)p->Cnt;\n        pPayload = p->pPayload;\n        Options = p->Options;\n        ENCODE_U32(pPayload, Options);\n        ENCODE_U32(pPayload, 0);\n        _SendPacket(p->pPayloadStart, pPayload, SYSVIEW_EVTID_PRINT_FORMATTED);\n        p->pPayloadStart = _PreparePacket(p->pBuffer);\n        p->pPayload = p->pPayloadStart + 1u;\n        p->Cnt = 0u;\n    }\n}\n\n/*********************************************************************\n*\n*       _PrintUnsigned()\n*\n*  Function description\n*    Print an unsigned integer with the given formatting into the\n*     formatted string.\n*\n*  Parameters\n*    pBufferDesc  Pointer to the buffer description.\n*    v            Value to be printed.\n*    Base         Base of the value.\n*    NumDigits    Number of digits to be printed.\n*    FieldWidth   Width of the printed field.\n*    FormatFlags  Flags for formatting the value.\n*/\nstatic void _PrintUnsigned(SEGGER_SYSVIEW_PRINTF_DESC *pBufferDesc, unsigned int v, unsigned int Base, unsigned int NumDigits, unsigned int FieldWidth, unsigned int FormatFlags)\n{\n    static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };\n    unsigned int      Div;\n    unsigned int      Digit;\n    unsigned int      Number;\n    unsigned int      Width;\n    char              c;\n\n    Number = v;\n    Digit = 1u;\n    //\n    // Get actual field width\n    //\n    Width = 1u;\n    while (Number >= Base) {\n        Number = (Number / Base);\n        Width++;\n    }\n    if (NumDigits > Width) {\n        Width = NumDigits;\n    }\n    //\n    // Print leading chars if necessary\n    //\n    if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) {\n        if (FieldWidth != 0u) {\n            if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0u)) {\n                c = '0';\n            } else {\n                c = ' ';\n            }\n            while ((FieldWidth != 0u) && (Width < FieldWidth)) {\n                FieldWidth--;\n                _StoreChar(pBufferDesc, c);\n            }\n        }\n    }\n    //\n    // Compute Digit.\n    // Loop until Digit has the value of the highest digit required.\n    // Example: If the output is 345 (Base 10), loop 2 times until Digit is 100.\n    //\n    while (1) {\n        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)\n            NumDigits--;\n        } else {\n            Div = v / Digit;\n            if (Div < Base) {        // Is our divider big enough to extract the highest digit from value? => Done\n                break;\n            }\n        }\n        Digit *= Base;\n    }\n    //\n    // Output digits\n    //\n    do {\n        Div = v / Digit;\n        v -= Div * Digit;\n        _StoreChar(pBufferDesc, _aV2C[Div]);\n        Digit /= Base;\n    } while (Digit);\n    //\n    // Print trailing spaces if necessary\n    //\n    if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) {\n        if (FieldWidth != 0u) {\n            while ((FieldWidth != 0u) && (Width < FieldWidth)) {\n                FieldWidth--;\n                _StoreChar(pBufferDesc, ' ');\n            }\n        }\n    }\n}\n\n/*********************************************************************\n*\n*       _PrintInt()\n*\n*  Function description\n*    Print a signed integer with the given formatting into the\n*     formatted string.\n*\n*  Parameters\n*    pBufferDesc  Pointer to the buffer description.\n*    v            Value to be printed.\n*    Base         Base of the value.\n*    NumDigits    Number of digits to be printed.\n*    FieldWidth   Width of the printed field.\n*    FormatFlags  Flags for formatting the value.\n*/\nstatic void _PrintInt(SEGGER_SYSVIEW_PRINTF_DESC *pBufferDesc, int v, unsigned int Base, unsigned int NumDigits, unsigned int FieldWidth, unsigned int FormatFlags)\n{\n    unsigned int  Width;\n    int           Number;\n\n    Number = (v < 0) ? -v : v;\n\n    //\n    // Get actual field width\n    //\n    Width = 1u;\n    while (Number >= (int)Base) {\n        Number = (Number / (int)Base);\n        Width++;\n    }\n    if (NumDigits > Width) {\n        Width = NumDigits;\n    }\n    if ((FieldWidth > 0u) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) {\n        FieldWidth--;\n    }\n\n    //\n    // Print leading spaces if necessary\n    //\n    if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u)) {\n        if (FieldWidth != 0u) {\n            while ((FieldWidth != 0u) && (Width < FieldWidth)) {\n                FieldWidth--;\n                _StoreChar(pBufferDesc, ' ');\n            }\n        }\n    }\n    //\n    // Print sign if necessary\n    //\n    if (v < 0) {\n        v = -v;\n        _StoreChar(pBufferDesc, '-');\n    } else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) {\n        _StoreChar(pBufferDesc, '+');\n    } else {\n\n    }\n    //\n    // Print leading zeros if necessary\n    //\n    if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u)) {\n        if (FieldWidth != 0u) {\n            while ((FieldWidth != 0u) && (Width < FieldWidth)) {\n                FieldWidth--;\n                _StoreChar(pBufferDesc, '0');\n            }\n        }\n    }\n    //\n    // Print number without sign\n    //\n    _PrintUnsigned(pBufferDesc, (unsigned int)v, Base, NumDigits, FieldWidth, FormatFlags);\n}\n\n/*********************************************************************\n*\n*       _VPrintTarget()\n*\n*  Function description\n*    Stores a formatted string.\n*    This data is read by the host.\n*\n*  Parameters\n*    sFormat      Pointer to format string.\n*    Options      Options to be sent to the host.\n*    pParamList   Pointer to the list of arguments for the format string.\n*/\nstatic void _VPrintTarget(const char *sFormat, U32 Options, va_list *pParamList)\n{\n    SEGGER_SYSVIEW_PRINTF_DESC BufferDesc;\n    char          c;\n    int           v;\n    unsigned int  NumDigits;\n    unsigned int  FormatFlags;\n    unsigned int  FieldWidth;\n    U8           *pPayloadStart;\n    const char   *s;\n#if SEGGER_SYSVIEW_USE_STATIC_BUFFER == 0\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_MAX_STRING_LEN + 1 + 2 * SEGGER_SYSVIEW_QUANTA_U32);\n    SEGGER_SYSVIEW_LOCK();\n#else\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_MAX_STRING_LEN + 1 + 2 * SEGGER_SYSVIEW_QUANTA_U32);\n#endif\n\n#if SEGGER_SYSVIEW_USE_STATIC_BUFFER == 0\n    BufferDesc.pBuffer        = aPacket;\n#else\n    BufferDesc.pBuffer        = _aPacket;\n#endif\n    BufferDesc.Cnt            = 0u;\n    BufferDesc.pPayloadStart  = pPayloadStart;\n    BufferDesc.pPayload       = BufferDesc.pPayloadStart + 1u;\n    BufferDesc.Options        =  Options;\n\n    do {\n        c = *sFormat;\n        sFormat++;\n        if (c == 0u) {\n            break;\n        }\n        if (c == '%') {\n            //\n            // Filter out flags\n            //\n            FormatFlags = 0u;\n            v = 1;\n            do {\n                c = *sFormat;\n                switch (c) {\n                case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break;\n                case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO;     sFormat++; break;\n                case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN;   sFormat++; break;\n                case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE;    sFormat++; break;\n                default:  v = 0; break;\n                }\n            } while (v);\n            //\n            // filter out field with\n            //\n            FieldWidth = 0u;\n            do {\n                c = *sFormat;\n                if ((c < '0') || (c > '9')) {\n                    break;\n                }\n                sFormat++;\n                FieldWidth = (FieldWidth * 10u) + ((unsigned int)c - '0');\n            } while (1);\n\n            //\n            // Filter out precision (number of digits to display)\n            //\n            NumDigits = 0u;\n            c = *sFormat;\n            if (c == '.') {\n                sFormat++;\n                do {\n                    c = *sFormat;\n                    if ((c < '0') || (c > '9')) {\n                        break;\n                    }\n                    sFormat++;\n                    NumDigits = NumDigits * 10u + ((unsigned int)c - '0');\n                } while (1);\n            }\n            //\n            // Filter out length modifier\n            //\n            c = *sFormat;\n            do {\n                if ((c == 'l') || (c == 'h')) {\n                    c = *sFormat;\n                    sFormat++;\n                } else {\n                    break;\n                }\n            } while (1);\n            //\n            // Handle specifiers\n            //\n            switch (c) {\n            case 'c': {\n                char c0;\n                v = va_arg(*pParamList, int);\n                c0 = (char)v;\n                _StoreChar(&BufferDesc, c0);\n                break;\n            }\n            case 'd':\n                v = va_arg(*pParamList, int);\n                _PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags);\n                break;\n            case 'u':\n                v = va_arg(*pParamList, int);\n                _PrintUnsigned(&BufferDesc, (unsigned int)v, 10u, NumDigits, FieldWidth, FormatFlags);\n                break;\n            case 'x':\n            case 'X':\n                v = va_arg(*pParamList, int);\n                _PrintUnsigned(&BufferDesc, (unsigned int)v, 16u, NumDigits, FieldWidth, FormatFlags);\n                break;\n            case 's':\n                s = va_arg(*pParamList, const char *);\n                if (s == NULL) {\n                    s = \"(null)\";\n                }\n                do {\n                    c = *s;\n                    s++;\n                    if (c == '\\0') {\n                        break;\n                    }\n                    _StoreChar(&BufferDesc, c);\n                } while (BufferDesc.Cnt < SEGGER_SYSVIEW_MAX_STRING_LEN);\n                break;\n            case 'p':\n                v = va_arg(*pParamList, int);\n                _PrintUnsigned(&BufferDesc, (unsigned int)v, 16u, 8u, 8u, 0u);\n                break;\n            case '%':\n                _StoreChar(&BufferDesc, '%');\n                break;\n            default:\n                break;\n            }\n            sFormat++;\n        } else {\n            _StoreChar(&BufferDesc, c);\n        }\n    } while (*sFormat);\n\n    //\n    // Write remaining data, if any\n    //\n    if (BufferDesc.Cnt != 0u) {\n        *(BufferDesc.pPayloadStart) = (U8)BufferDesc.Cnt;\n        ENCODE_U32(BufferDesc.pPayload, BufferDesc.Options);\n        ENCODE_U32(BufferDesc.pPayload, 0);\n        _SendPacket(BufferDesc.pPayloadStart, BufferDesc.pPayload, SYSVIEW_EVTID_PRINT_FORMATTED);\n    }\n#if SEGGER_SYSVIEW_USE_STATIC_BUFFER == 0\n    SEGGER_SYSVIEW_UNLOCK();\n    RECORD_END();\n#else\n    RECORD_END();\n#endif\n}\n#endif // SEGGER_SYSVIEW_EXCLUDE_PRINTF\n\n/*********************************************************************\n*\n*       Public code\n*\n**********************************************************************\n*/\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_Init()\n*\n*  Function description\n*    Initializes the SYSVIEW module.\n*    Must be called before the SystemView Application connects to\n*    the system.\n*\n*  Parameters\n*    SysFreq        - Frequency of timestamp, usually CPU core clock frequency.\n*    CPUFreq        - CPU core clock frequency.\n*    pOSAPI         - Pointer to the API structure for OS-specific functions.\n*    pfSendSysDesc  - Pointer to record system description callback function.\n*\n*  Additional information\n*    This function initializes the RTT channel used to transport\n*    SEGGER SystemView packets.\n*    The channel is assigned the label \"SysView\" for client software\n*    to identify the SystemView channel.\n*\n*    The channel is configured with the macro SEGGER_SYSVIEW_RTT_CHANNEL.\n*/\nvoid SEGGER_SYSVIEW_Init(U32 SysFreq, U32 CPUFreq, const SEGGER_SYSVIEW_OS_API *pOSAPI, SEGGER_SYSVIEW_SEND_SYS_DESC_FUNC pfSendSysDesc)\n{\n#ifdef SEGGER_RTT_SECTION\n    //\n    // Explicitly initialize the RTT Control Block if it is in its dedicated section.\n    //\n    SEGGER_RTT_Init();\n#endif\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE == 1)\n#if SEGGER_SYSVIEW_RTT_CHANNEL > 0\n    SEGGER_RTT_ConfigUpBuffer(SEGGER_SYSVIEW_RTT_CHANNEL, \"SysView\", &_UpBuffer[0],   sizeof(_UpBuffer),   SEGGER_RTT_MODE_NO_BLOCK_SKIP);\n#else\n    _SYSVIEW_Globals.UpChannel = (U8)SEGGER_RTT_AllocUpBuffer  (\"SysView\", &_UpBuffer[0],   sizeof(_UpBuffer),   SEGGER_RTT_MODE_NO_BLOCK_SKIP);\n#endif\n    _SYSVIEW_Globals.RAMBaseAddress   = SEGGER_SYSVIEW_ID_BASE;\n    _SYSVIEW_Globals.LastTxTimeStamp  = SEGGER_SYSVIEW_GET_TIMESTAMP();\n    _SYSVIEW_Globals.pOSAPI           = pOSAPI;\n    _SYSVIEW_Globals.SysFreq          = SysFreq;\n    _SYSVIEW_Globals.CPUFreq          = CPUFreq;\n    _SYSVIEW_Globals.pfSendSysDesc    = pfSendSysDesc;\n    _SYSVIEW_Globals.EnableState      = 0;\n    _SYSVIEW_Globals.PacketCount      = 0;\n#else // (SEGGER_SYSVIEW_POST_MORTEM_MODE == 1)\n#if SEGGER_SYSVIEW_RTT_CHANNEL > 0\n    SEGGER_RTT_ConfigUpBuffer   (SEGGER_SYSVIEW_RTT_CHANNEL, \"SysView\", &_UpBuffer[0],   sizeof(_UpBuffer),   SEGGER_RTT_MODE_NO_BLOCK_SKIP);\n    SEGGER_RTT_ConfigDownBuffer (SEGGER_SYSVIEW_RTT_CHANNEL, \"SysView\", &_DownBuffer[0], sizeof(_DownBuffer), SEGGER_RTT_MODE_NO_BLOCK_SKIP);\n#else\n    _SYSVIEW_Globals.UpChannel = (U8)SEGGER_RTT_AllocUpBuffer  (\"SysView\", &_UpBuffer[0],   sizeof(_UpBuffer),   SEGGER_RTT_MODE_NO_BLOCK_SKIP);\n    _SYSVIEW_Globals.DownChannel = _SYSVIEW_Globals.UpChannel;\n    SEGGER_RTT_ConfigDownBuffer (_SYSVIEW_Globals.DownChannel, \"SysView\", &_DownBuffer[0], sizeof(_DownBuffer), SEGGER_RTT_MODE_NO_BLOCK_SKIP);\n#endif\n    _SYSVIEW_Globals.RAMBaseAddress   = SEGGER_SYSVIEW_ID_BASE;\n    _SYSVIEW_Globals.LastTxTimeStamp  = SEGGER_SYSVIEW_GET_TIMESTAMP();\n    _SYSVIEW_Globals.pOSAPI           = pOSAPI;\n    _SYSVIEW_Globals.SysFreq          = SysFreq;\n    _SYSVIEW_Globals.CPUFreq          = CPUFreq;\n    _SYSVIEW_Globals.pfSendSysDesc    = pfSendSysDesc;\n    _SYSVIEW_Globals.EnableState      = 0;\n#endif  // (SEGGER_SYSVIEW_POST_MORTEM_MODE == 1)\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_SetRAMBase()\n*\n*  Function description\n*    Sets the RAM base address, which is subtracted from IDs in order\n*     to save bandwidth.\n*\n*  Parameters\n*    RAMBaseAddress - Lowest RAM Address. (i.e. 0x20000000 on most Cortex-M)\n*/\nvoid SEGGER_SYSVIEW_SetRAMBase(U32 RAMBaseAddress)\n{\n    _SYSVIEW_Globals.RAMBaseAddress = RAMBaseAddress;\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordVoid()\n*\n*  Function description\n*    Formats and sends a SystemView packet with an empty payload.\n*\n*  Parameters\n*    EventID - SystemView event ID.\n*/\nvoid SEGGER_SYSVIEW_RecordVoid(unsigned int EventID)\n{\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE);\n    //\n    _SendPacket(pPayloadStart, pPayloadStart, EventID);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordU32()\n*\n*  Function description\n*    Formats and sends a SystemView packet containing a single U32\n*    parameter payload.\n*\n*  Parameters\n*    EventID - SystemView event ID.\n*    Value   - The 32-bit parameter encoded to SystemView packet payload.\n*/\nvoid SEGGER_SYSVIEW_RecordU32(unsigned int EventID, U32 Value)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, Value);\n    _SendPacket(pPayloadStart, pPayload, EventID);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordU32x2()\n*\n*  Function description\n*    Formats and sends a SystemView packet containing 2 U32 parameter payload.\n*\n*  Parameters\n*    EventID - SystemView event ID.\n*    Para0   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para1   - The 32-bit parameter encoded to SystemView packet payload.\n*/\nvoid SEGGER_SYSVIEW_RecordU32x2(unsigned int EventID, U32 Para0, U32 Para1)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, Para0);\n    ENCODE_U32(pPayload, Para1);\n    _SendPacket(pPayloadStart, pPayload, EventID);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordU32x3()\n*\n*  Function description\n*    Formats and sends a SystemView packet containing 3 U32 parameter payload.\n*\n*  Parameters\n*    EventID - SystemView event ID.\n*    Para0   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para1   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para2   - The 32-bit parameter encoded to SystemView packet payload.\n*/\nvoid SEGGER_SYSVIEW_RecordU32x3(unsigned int EventID, U32 Para0, U32 Para1, U32 Para2)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 3 * SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, Para0);\n    ENCODE_U32(pPayload, Para1);\n    ENCODE_U32(pPayload, Para2);\n    _SendPacket(pPayloadStart, pPayload, EventID);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordU32x4()\n*\n*  Function description\n*    Formats and sends a SystemView packet containing 4 U32 parameter payload.\n*\n*  Parameters\n*    EventID - SystemView event ID.\n*    Para0   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para1   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para2   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para3   - The 32-bit parameter encoded to SystemView packet payload.\n*/\nvoid SEGGER_SYSVIEW_RecordU32x4(unsigned int EventID, U32 Para0, U32 Para1, U32 Para2, U32 Para3)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 4 * SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, Para0);\n    ENCODE_U32(pPayload, Para1);\n    ENCODE_U32(pPayload, Para2);\n    ENCODE_U32(pPayload, Para3);\n    _SendPacket(pPayloadStart, pPayload, EventID);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordU32x5()\n*\n*  Function description\n*    Formats and sends a SystemView packet containing 5 U32 parameter payload.\n*\n*  Parameters\n*    EventID - SystemView event ID.\n*    Para0   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para1   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para2   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para3   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para4   - The 32-bit parameter encoded to SystemView packet payload.\n*/\nvoid SEGGER_SYSVIEW_RecordU32x5(unsigned int EventID, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 5 * SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, Para0);\n    ENCODE_U32(pPayload, Para1);\n    ENCODE_U32(pPayload, Para2);\n    ENCODE_U32(pPayload, Para3);\n    ENCODE_U32(pPayload, Para4);\n    _SendPacket(pPayloadStart, pPayload, EventID);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordU32x6()\n*\n*  Function description\n*    Formats and sends a SystemView packet containing 6 U32 parameter payload.\n*\n*  Parameters\n*    EventID - SystemView event ID.\n*    Para0   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para1   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para2   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para3   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para4   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para5   - The 32-bit parameter encoded to SystemView packet payload.\n*/\nvoid SEGGER_SYSVIEW_RecordU32x6(unsigned int EventID, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 6 * SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, Para0);\n    ENCODE_U32(pPayload, Para1);\n    ENCODE_U32(pPayload, Para2);\n    ENCODE_U32(pPayload, Para3);\n    ENCODE_U32(pPayload, Para4);\n    ENCODE_U32(pPayload, Para5);\n    _SendPacket(pPayloadStart, pPayload, EventID);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordU32x7()\n*\n*  Function description\n*    Formats and sends a SystemView packet containing 7 U32 parameter payload.\n*\n*  Parameters\n*    EventID - SystemView event ID.\n*    Para0   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para1   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para2   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para3   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para4   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para5   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para6   - The 32-bit parameter encoded to SystemView packet payload.\n*/\nvoid SEGGER_SYSVIEW_RecordU32x7(unsigned int EventID, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5, U32 Para6)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 7 * SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, Para0);\n    ENCODE_U32(pPayload, Para1);\n    ENCODE_U32(pPayload, Para2);\n    ENCODE_U32(pPayload, Para3);\n    ENCODE_U32(pPayload, Para4);\n    ENCODE_U32(pPayload, Para5);\n    ENCODE_U32(pPayload, Para6);\n    _SendPacket(pPayloadStart, pPayload, EventID);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordU32x8()\n*\n*  Function description\n*    Formats and sends a SystemView packet containing 8 U32 parameter payload.\n*\n*  Parameters\n*    EventID - SystemView event ID.\n*    Para0   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para1   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para2   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para3   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para4   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para5   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para6   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para7   - The 32-bit parameter encoded to SystemView packet payload.\n*/\nvoid SEGGER_SYSVIEW_RecordU32x8(unsigned int EventID, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5, U32 Para6, U32 Para7)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 8 * SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, Para0);\n    ENCODE_U32(pPayload, Para1);\n    ENCODE_U32(pPayload, Para2);\n    ENCODE_U32(pPayload, Para3);\n    ENCODE_U32(pPayload, Para4);\n    ENCODE_U32(pPayload, Para5);\n    ENCODE_U32(pPayload, Para6);\n    ENCODE_U32(pPayload, Para7);\n    _SendPacket(pPayloadStart, pPayload, EventID);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordU32x9()\n*\n*  Function description\n*    Formats and sends a SystemView packet containing 9 U32 parameter payload.\n*\n*  Parameters\n*    EventID - SystemView event ID.\n*    Para0   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para1   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para2   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para3   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para4   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para5   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para6   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para7   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para8   - The 32-bit parameter encoded to SystemView packet payload.\n*/\nvoid SEGGER_SYSVIEW_RecordU32x9(unsigned int EventID, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5, U32 Para6, U32 Para7, U32 Para8)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 9 * SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, Para0);\n    ENCODE_U32(pPayload, Para1);\n    ENCODE_U32(pPayload, Para2);\n    ENCODE_U32(pPayload, Para3);\n    ENCODE_U32(pPayload, Para4);\n    ENCODE_U32(pPayload, Para5);\n    ENCODE_U32(pPayload, Para6);\n    ENCODE_U32(pPayload, Para7);\n    ENCODE_U32(pPayload, Para8);\n    _SendPacket(pPayloadStart, pPayload, EventID);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordU32x10()\n*\n*  Function description\n*    Formats and sends a SystemView packet containing 10 U32 parameter payload.\n*\n*  Parameters\n*    EventID - SystemView event ID.\n*    Para0   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para1   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para2   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para3   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para4   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para5   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para6   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para7   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para8   - The 32-bit parameter encoded to SystemView packet payload.\n*    Para9   - The 32-bit parameter encoded to SystemView packet payload.\n*/\nvoid 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)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 10 * SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, Para0);\n    ENCODE_U32(pPayload, Para1);\n    ENCODE_U32(pPayload, Para2);\n    ENCODE_U32(pPayload, Para3);\n    ENCODE_U32(pPayload, Para4);\n    ENCODE_U32(pPayload, Para5);\n    ENCODE_U32(pPayload, Para6);\n    ENCODE_U32(pPayload, Para7);\n    ENCODE_U32(pPayload, Para8);\n    ENCODE_U32(pPayload, Para9);\n    _SendPacket(pPayloadStart, pPayload, EventID);\n    RECORD_END();\n}\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordString()\n*\n*  Function description\n*    Formats and sends a SystemView packet containing a string.\n*\n*  Parameters\n*    EventID - SystemView event ID.\n*    pString - The string to be sent in the SystemView packet payload.\n*\n*  Additional information\n*    The string is encoded as a count byte followed by the contents\n*    of the string.\n*    No more than SEGGER_SYSVIEW_MAX_STRING_LEN bytes will be encoded to the payload.\n*/\nvoid SEGGER_SYSVIEW_RecordString(unsigned int EventID, const char *pString)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 1 + SEGGER_SYSVIEW_MAX_STRING_LEN);\n    //\n    pPayload = _EncodeStr(pPayloadStart, pString, SEGGER_SYSVIEW_MAX_STRING_LEN);\n    _SendPacket(pPayloadStart, pPayload, EventID);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_Start()\n*\n*  Function description\n*    Start recording SystemView events.\n*\n*    This function is triggered by the SystemView Application on connect.\n*    For single-shot or post-mortem mode recording, it needs to be called\n*    by the application.\n*\n*  Additional information\n*    This function enables transmission of SystemView packets recorded\n*    by subsequent trace calls and records a SystemView Start event.\n*\n*    As part of start, a SystemView Init packet is sent, containing the system\n*    frequency. The list of current tasks, the current system time and the\n*    system description string is sent, too.\n*\n*  Notes\n*    SEGGER_SYSVIEW_Start and SEGGER_SYSVIEW_Stop do not nest.\n*    When SEGGER_SYSVIEW_CAN_RESTART is 1, each received start command\n*    records the system information. This is required to enable restart\n*    of recordings when SystemView unexpectedly disconnects without sending\n*    a stop command before.\n*/\nvoid SEGGER_SYSVIEW_Start(void)\n{\n#if (SEGGER_SYSVIEW_CAN_RESTART == 0)\n    if (_SYSVIEW_Globals.EnableState == 0) {\n#endif\n        _SYSVIEW_Globals.EnableState = 1;\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE == 1)\n        _SendSyncInfo();\n#else\n        SEGGER_SYSVIEW_LOCK();\n        SEGGER_RTT_WriteSkipNoLock(CHANNEL_ID_UP, _abSync, 10);\n        SEGGER_SYSVIEW_UNLOCK();\n        SEGGER_SYSVIEW_ON_EVENT_RECORDED(10);\n        SEGGER_SYSVIEW_RecordVoid(SYSVIEW_EVTID_TRACE_START);\n        {\n            U8 *pPayload;\n            U8 *pPayloadStart;\n            RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 4 * SEGGER_SYSVIEW_QUANTA_U32);\n            //\n            pPayload = pPayloadStart;\n            ENCODE_U32(pPayload, _SYSVIEW_Globals.SysFreq);\n            ENCODE_U32(pPayload, _SYSVIEW_Globals.CPUFreq);\n            ENCODE_U32(pPayload, _SYSVIEW_Globals.RAMBaseAddress);\n            ENCODE_U32(pPayload, SEGGER_SYSVIEW_ID_SHIFT);\n            _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_INIT);\n            RECORD_END();\n        }\n        if (_SYSVIEW_Globals.pfSendSysDesc) {\n            _SYSVIEW_Globals.pfSendSysDesc();\n        }\n        SEGGER_SYSVIEW_RecordSystime();\n        SEGGER_SYSVIEW_SendTaskList();\n        SEGGER_SYSVIEW_SendNumModules();\n#endif\n#if (SEGGER_SYSVIEW_CAN_RESTART == 0)\n    }\n#endif\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_Stop()\n*\n*  Function description\n*    Stop recording SystemView events.\n*\n*    This function is triggered by the SystemView Application on disconnect.\n*    For single-shot or postmortem mode recording, it can be called\n*    by the application.\n*\n*  Additional information\n*    This function disables transmission of SystemView packets recorded\n*    by subsequent trace calls.  If transmission is enabled when\n*    this function is called, a single SystemView Stop event is recorded\n*    to the trace, send, and then trace transmission is halted.\n*/\nvoid SEGGER_SYSVIEW_Stop(void)\n{\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE);\n    // We should send answer for the Stop command in any case.\n    _SYSVIEW_Globals.EnableState = 1;\n    if (_SYSVIEW_Globals.EnableState) {\n        _SendPacket(pPayloadStart, pPayloadStart, SYSVIEW_EVTID_TRACE_STOP);\n        _SYSVIEW_Globals.EnableState = 0;\n    }\n    RECORD_END();\n}\n\nU8 SEGGER_SYSVIEW_Started(void)\n{\n    return _SYSVIEW_Globals.EnableState;\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_GetChannelID()\n*\n*  Function description\n*    Returns the RTT <Up> / <Down> channel ID used by SystemView.\n*/\nint SEGGER_SYSVIEW_GetChannelID(void)\n{\n    return CHANNEL_ID_UP;\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_GetSysDesc()\n*\n*  Function description\n*    Triggers a send of the system information and description.\n*\n*/\nvoid SEGGER_SYSVIEW_GetSysDesc(void)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + SEGGER_SYSVIEW_MAX_STRING_LEN + 3/*1 or 3 bytes for string length*/);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, _SYSVIEW_Globals.SysFreq);\n    ENCODE_U32(pPayload, _SYSVIEW_Globals.CPUFreq);\n    ENCODE_U32(pPayload, _SYSVIEW_Globals.RAMBaseAddress);\n    ENCODE_U32(pPayload, SEGGER_SYSVIEW_ID_SHIFT);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_INIT);\n    RECORD_END();\n    if (_SYSVIEW_Globals.pfSendSysDesc) {\n        _SYSVIEW_Globals.pfSendSysDesc();\n    }\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_SendTaskInfo()\n*\n*  Function description\n*    Send a Task Info Packet, containing TaskId for identification,\n*    task priority and task name.\n*\n*  Parameters\n*    pInfo - Pointer to task information to send.\n*/\nvoid SEGGER_SYSVIEW_SendTaskInfo(const SEGGER_SYSVIEW_TASKINFO *pInfo)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32 + 1 + 32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, SHRINK_ID(pInfo->TaskID));\n    ENCODE_U32(pPayload, pInfo->Prio);\n    pPayload = _EncodeStr(pPayload, pInfo->sName, 32);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_TASK_INFO);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, SHRINK_ID(pInfo->TaskID));\n    ENCODE_U32(pPayload, pInfo->StackBase);\n    ENCODE_U32(pPayload, pInfo->StackSize);\n    ENCODE_U32(pPayload, pInfo->StackUsage);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_STACK_INFO);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_SendStackInfo()\n*\n*  Function description\n*    Send a Stack Info Packet, containing TaskId for identification,\n*    stack base, stack size and stack usage.\n*\n*\n*  Parameters\n*    pInfo - Pointer to stack information to send.\n*/\nvoid SEGGER_SYSVIEW_SendStackInfo(const SEGGER_SYSVIEW_STACKINFO *pInfo)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 4 * SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, SHRINK_ID(pInfo->TaskID));\n    ENCODE_U32(pPayload, pInfo->StackBase);\n    ENCODE_U32(pPayload, pInfo->StackSize);\n    ENCODE_U32(pPayload, pInfo->StackUsage);\n\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*        SEGGER_SYSVIEW_SampleData()\n*\n*  Function description\n*    Send a Data Sample Packet, containing the data Id and the value.\n*\n*\n*  Parameters\n*    pInfo - Pointer to data sample struct to send.\n*/\nvoid SEGGER_SYSVIEW_SampleData(const SEGGER_SYSVIEW_DATA_SAMPLE *pInfo)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, pInfo->ID);\n    pPayload = _EncodeFloat(pPayload, *(pInfo->pFloat_Value));\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_DATA_SAMPLE);\n\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_SendTaskList()\n*\n*  Function description\n*    Send all tasks descriptors to the host.\n*/\nvoid SEGGER_SYSVIEW_SendTaskList(void)\n{\n    if (_SYSVIEW_Globals.pOSAPI && _SYSVIEW_Globals.pOSAPI->pfSendTaskList) {\n        _SYSVIEW_Globals.pOSAPI->pfSendTaskList();\n    }\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_SendSysDesc()\n*\n*  Function description\n*    Send the system description string to the host.\n*    The system description is used by the SystemView Application\n*    to identify the current application and handle events accordingly.\n*\n*    The system description is usually called by the system description\n*    callback, to ensure it is only sent when the SystemView Application\n*    is connected.\n*\n*  Parameters\n*    sSysDesc - Pointer to the 0-terminated system description string.\n*\n*  Additional information\n*    One system description string may not exceed SEGGER_SYSVIEW_MAX_STRING_LEN characters.\n*    Multiple description strings can be recorded.\n*\n*    The Following items can be described in a system description string.\n*    Each item is identified by its identifier, followed by '=' and the value.\n*    Items are separated by ','.\n*/\nvoid SEGGER_SYSVIEW_SendSysDesc(const char *sSysDesc)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 1 + SEGGER_SYSVIEW_MAX_STRING_LEN);\n    //\n    pPayload = _EncodeStr(pPayloadStart, sSysDesc, SEGGER_SYSVIEW_MAX_STRING_LEN);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_SYSDESC);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordSystime()\n*\n*  Function description\n*    Formats and sends a SystemView Systime containing a single U64 or U32\n*    parameter payload.\n*/\nvoid SEGGER_SYSVIEW_RecordSystime(void)\n{\n    U64 Systime;\n    // This code requeued because SystemView expect the answer from the device.\n    // If there is no answer, then communication will be broken.\n    U8 old_en = _SYSVIEW_Globals.EnableState;\n    _SYSVIEW_Globals.EnableState = 1;\n\n    if (_SYSVIEW_Globals.pOSAPI && _SYSVIEW_Globals.pOSAPI->pfGetTime) {\n        Systime = _SYSVIEW_Globals.pOSAPI->pfGetTime();\n        SEGGER_SYSVIEW_RecordU32x2(SYSVIEW_EVTID_SYSTIME_US,\n                                   (U32)(Systime),\n                                   (U32)(Systime >> 32));\n    } else {\n        SEGGER_SYSVIEW_RecordU32(SYSVIEW_EVTID_SYSTIME_CYCLES, SEGGER_SYSVIEW_GET_TIMESTAMP());\n    }\n    _SYSVIEW_Globals.EnableState = old_en;\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordEnterISR()\n*\n*  Function description\n*    Format and send an ISR entry event.\n*\n*  Additional information\n*    Example packets sent\n*      02 0F 50              // ISR(15) Enter. Timestamp is 80 (0x50)\n*/\nvoid SEGGER_SYSVIEW_RecordEnterISR(U32 IrqId)\n{\n    unsigned v;\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    v = IrqId; // SEGGER_SYSVIEW_GET_INTERRUPT_ID();\n    ENCODE_U32(pPayload, v);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_ISR_ENTER);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordExitISR()\n*\n*  Function description\n*    Format and send an ISR exit event.\n*\n*  Additional information\n*    Format as follows:\n*      03 <TimeStamp>        // Max. packet len is 6\n*\n*    Example packets sent\n*      03 20                // ISR Exit. Timestamp is 32 (0x20)\n*/\nvoid SEGGER_SYSVIEW_RecordExitISR(void)\n{\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE);\n    //\n    _SendPacket(pPayloadStart, pPayloadStart, SYSVIEW_EVTID_ISR_EXIT);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordExitISRToScheduler()\n*\n*  Function description\n*    Format and send an ISR exit into scheduler event.\n*\n*  Additional information\n*    Format as follows:\n*      18 <TimeStamp>        // Max. packet len is 6\n*\n*    Example packets sent\n*      18 20                // ISR Exit to Scheduler. Timestamp is 32 (0x20)\n*/\nvoid SEGGER_SYSVIEW_RecordExitISRToScheduler(void)\n{\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE);\n    //\n    _SendPacket(pPayloadStart, pPayloadStart, SYSVIEW_EVTID_ISR_TO_SCHEDULER);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordEnterTimer()\n*\n*  Function description\n*    Format and send a Timer entry event.\n*\n*  Parameters\n*    TimerId - Id of the timer which starts.\n*/\nvoid SEGGER_SYSVIEW_RecordEnterTimer(U32 TimerId)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, SHRINK_ID(TimerId));\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_TIMER_ENTER);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordExitTimer()\n*\n*  Function description\n*    Format and send a Timer exit event.\n*/\nvoid SEGGER_SYSVIEW_RecordExitTimer(void)\n{\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE);\n    //\n    _SendPacket(pPayloadStart, pPayloadStart, SYSVIEW_EVTID_TIMER_EXIT);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordEndCall()\n*\n*  Function description\n*    Format and send an End API Call event without return value.\n*\n*  Parameters\n*    EventID - Id of API function which ends.\n*/\nvoid SEGGER_SYSVIEW_RecordEndCall(unsigned int EventID)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, EventID);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_END_CALL);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordEndCallU32()\n*\n*  Function description\n*    Format and send an End API Call event with return value.\n*\n*  Parameters\n*    EventID      - Id of API function which ends.\n*    Para0        - Return value which will be returned by the API function.\n*/\nvoid SEGGER_SYSVIEW_RecordEndCallU32(unsigned int EventID, U32 Para0)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, EventID);\n    ENCODE_U32(pPayload, Para0);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_END_CALL);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_OnIdle()\n*\n*  Function description\n*    Record an Idle event.\n*/\nvoid SEGGER_SYSVIEW_OnIdle(void)\n{\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE);\n    //\n    _SendPacket(pPayloadStart, pPayloadStart, SYSVIEW_EVTID_IDLE);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_OnTaskCreate()\n*\n*  Function description\n*    Record a Task Create event.  The Task Create event corresponds\n*    to creating a task in the OS.\n*\n*  Parameters\n*    TaskId        - Task ID of created task.\n*/\nvoid SEGGER_SYSVIEW_OnTaskCreate(U32 TaskId)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    TaskId = SHRINK_ID(TaskId);\n    ENCODE_U32(pPayload, TaskId);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_TASK_CREATE);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_OnTaskTerminate()\n*\n*  Function description\n*    Record a Task termination event.\n*    The Task termination event corresponds to terminating a task in\n*    the OS. If the TaskId is the currently active task,\n*    SEGGER_SYSVIEW_OnTaskStopExec may be used, either.\n*\n*  Parameters\n*    TaskId        - Task ID of terminated task.\n*/\nvoid SEGGER_SYSVIEW_OnTaskTerminate(U32 TaskId)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    TaskId = SHRINK_ID(TaskId);\n    ENCODE_U32(pPayload, TaskId);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_TASK_TERMINATE);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_OnTaskStartExec()\n*\n*  Function description\n*    Record a Task Start Execution event.  The Task Start event\n*    corresponds to when a task has started to execute rather than\n*    when it is ready to execute.\n*\n*  Parameters\n*    TaskId - Task ID of task that started to execute.\n*/\nvoid SEGGER_SYSVIEW_OnTaskStartExec(U32 TaskId)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    TaskId = SHRINK_ID(TaskId);\n    ENCODE_U32(pPayload, TaskId);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_TASK_START_EXEC);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_OnTaskStopExec()\n*\n*  Function description\n*    Record a Task Stop Execution event.  The Task Stop event\n*    corresponds to when a task stops executing and terminates.\n*/\nvoid SEGGER_SYSVIEW_OnTaskStopExec(void)\n{\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE);\n    //\n    _SendPacket(pPayloadStart, pPayloadStart, SYSVIEW_EVTID_TASK_STOP_EXEC);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_OnTaskStartReady()\n*\n*  Function description\n*    Record a Task Start Ready event.\n*\n*  Parameters\n*    TaskId - Task ID of task that started to execute.\n*/\nvoid SEGGER_SYSVIEW_OnTaskStartReady(U32 TaskId)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    TaskId = SHRINK_ID(TaskId);\n    ENCODE_U32(pPayload, TaskId);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_TASK_START_READY);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_OnTaskStopReady()\n*\n*  Function description\n*    Record a Task Stop Ready event.\n*\n*  Parameters\n*    TaskId - Task ID of task that completed execution.\n*    Cause  - Reason for task to stop (i.e. Idle/Sleep)\n*/\nvoid SEGGER_SYSVIEW_OnTaskStopReady(U32 TaskId, unsigned int Cause)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    TaskId = SHRINK_ID(TaskId);\n    ENCODE_U32(pPayload, TaskId);\n    ENCODE_U32(pPayload, Cause);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_TASK_STOP_READY);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_MarkStart()\n*\n*  Function description\n*    Record a Performance Marker Start event to start measuring runtime.\n*\n*  Parameters\n*    MarkerId  - User defined ID for the marker.\n*/\nvoid SEGGER_SYSVIEW_MarkStart(unsigned MarkerId)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, MarkerId);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_MARK_START);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_MarkStop()\n*\n*  Function description\n*    Record a Performance Marker Stop event to stop measuring runtime.\n*\n*  Parameters\n*    MarkerId  - User defined ID for the marker.\n*/\nvoid SEGGER_SYSVIEW_MarkStop(unsigned MarkerId)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, MarkerId);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_MARK_STOP);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_Mark()\n*\n*  Function description\n*    Record a Performance Marker intermediate event.\n*\n*  Parameters\n*    MarkerId  - User defined ID for the marker.\n*/\nvoid SEGGER_SYSVIEW_Mark(unsigned int MarkerId)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, SYSVIEW_EVTID_EX_MARK);\n    ENCODE_U32(pPayload, MarkerId);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_EX);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_NameMarker()\n*\n*  Function description\n*    Send the name of a Performance Marker to be displayed in SystemView.\n*\n*    Marker names are usually set in the system description\n*    callback, to ensure it is only sent when the SystemView Application\n*    is connected.\n*\n*  Parameters\n*    MarkerId   - User defined ID for the marker.\n*    sName      - Pointer to the marker name. (Max. SEGGER_SYSVIEW_MAX_STRING_LEN Bytes)\n*/\nvoid SEGGER_SYSVIEW_NameMarker(unsigned int MarkerId, const char *sName)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + 1 + SEGGER_SYSVIEW_MAX_STRING_LEN);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, SYSVIEW_EVTID_EX_NAME_MARKER);\n    ENCODE_U32(pPayload, MarkerId);\n    pPayload = _EncodeStr(pPayload, sName, SEGGER_SYSVIEW_MAX_STRING_LEN);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_EX);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_NameResource()\n*\n*  Function description\n*    Send the name of a resource to be displayed in SystemView.\n*\n*    Marker names are usually set in the system description\n*    callback, to ensure it is only sent when the SystemView Application\n*    is connected.\n*\n*  Parameters\n*    ResourceId - Id of the resource to be named. i.e. its address.\n*    sName      - Pointer to the resource name. (Max. SEGGER_SYSVIEW_MAX_STRING_LEN Bytes)\n*/\nvoid SEGGER_SYSVIEW_NameResource(U32 ResourceId, const char *sName)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32 + 1 + SEGGER_SYSVIEW_MAX_STRING_LEN);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, SHRINK_ID(ResourceId));\n    pPayload = _EncodeStr(pPayload, sName, SEGGER_SYSVIEW_MAX_STRING_LEN);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_NAME_RESOURCE);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RegisterData()\n*\n*  Function description\n*    Register data to sample the values via SystemView.\n*\n*    Register functions are usually set in the system description\n*    callback, to ensure it is only sent when the SystemView Application\n*    is connected.\n*\n*  Parameters\n*    pInfo - Struct containing all possible properties that can be sent via this registration event.\n*/\nvoid SEGGER_SYSVIEW_RegisterData(SEGGER_SYSVIEW_DATA_REGISTER *pInfo)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 8 * SEGGER_SYSVIEW_QUANTA_U32 + 1 + SEGGER_SYSVIEW_MAX_STRING_LEN);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, SYSVIEW_EVTID_EX_REGISTER_DATA);\n    ENCODE_U32(pPayload, pInfo->ID);\n    pPayload = _EncodeStr(pPayload, pInfo->sName, SEGGER_SYSVIEW_MAX_STRING_LEN);\n\n    if (pInfo->sName != 0) {\n        ENCODE_U32(pPayload, pInfo->DataType);\n        ENCODE_U32(pPayload, pInfo->Offset);\n        ENCODE_U32(pPayload, pInfo->RangeMin);\n        ENCODE_U32(pPayload, pInfo->RangeMax);\n        pPayload = _EncodeFloat(pPayload, pInfo->ScalingFactor);\n        pPayload = _EncodeStr(pPayload, pInfo->sUnit, SEGGER_SYSVIEW_MAX_STRING_LEN);\n    } else if (pInfo->ScalingFactor != 0) {\n        ENCODE_U32(pPayload, pInfo->DataType);\n        ENCODE_U32(pPayload, pInfo->Offset);\n        ENCODE_U32(pPayload, pInfo->RangeMin);\n        ENCODE_U32(pPayload, pInfo->RangeMax);\n        pPayload = _EncodeFloat(pPayload, pInfo->ScalingFactor);\n    } else if (pInfo->RangeMax != 0) {\n        ENCODE_U32(pPayload, pInfo->DataType);\n        ENCODE_U32(pPayload, pInfo->Offset);\n        ENCODE_U32(pPayload, pInfo->RangeMin);\n        ENCODE_U32(pPayload, pInfo->RangeMax);\n    } else if (pInfo->RangeMin != 0) {\n        ENCODE_U32(pPayload, pInfo->DataType);\n        ENCODE_U32(pPayload, pInfo->Offset);\n        ENCODE_U32(pPayload, pInfo->RangeMin);\n    } else if (pInfo->Offset != 0) {\n        ENCODE_U32(pPayload, pInfo->DataType);\n        ENCODE_U32(pPayload, pInfo->Offset);\n    } else if (pInfo->DataType != 0) {\n        ENCODE_U32(pPayload, pInfo->DataType);\n    }\n\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_EX);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_HeapDefine()\n*\n*  Function description\n*    Define heap.\n*\n*  Parameters\n*    pHeap        - Pointer to heap control structure.\n*    pBase        - Pointer to managed heap memory.\n*    HeapSize     - Size of managed heap memory in bytes.\n*    MetadataSize - Size of metadata associated with each heap allocation.\n*\n*  Additional information\n*    SystemView can track allocations across multiple heaps.\n*\n*    HeapSize must be a multiple of the natural alignment unit of the\n*    target.  This size is subject to compression, controlled by the\n*    specific setting of SEGGER_SYSVIEW_ID_SHIFT.\n*\n*    MetadataSize defines the size of the per-allocation metadata.\n*    For many heap implementations, the metadata size is a multiple of\n*    the word size of the machine and typically contains the size\n*    of the allocated block (used upon deallocation), optional\n*    pointers to the preceding and/or following blocks, and optionally\n*    a tag identifying the owner of the block.  Note that MetadataSize\n*    is not compressed within the SystemView packet and is not\n*    required to be a multiple of 1<<SEGGER_SYSVIEW_ID_SHIFT.\n*/\nvoid SEGGER_SYSVIEW_HeapDefine(void *pHeap, void *pBase, unsigned int HeapSize, unsigned int MetadataSize)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 4 * SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, SYSVIEW_EVTID_EX_HEAP_DEFINE);\n    ENCODE_U32(pPayload, SHRINK_ID((U32)pHeap));\n    ENCODE_U32(pPayload, SHRINK_ID((U32)pBase));\n    ENCODE_U32(pPayload, HeapSize >> SEGGER_SYSVIEW_ID_SHIFT);\n    ENCODE_U32(pPayload, MetadataSize);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_EX);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_HeapAlloc()\n*\n*  Function description\n*    Record a system-heap allocation event.\n*\n*  Parameters\n*    pHeap       - Pointer to heap where allocation was made.\n*    pUserData   - Pointer to allocated user data.\n*    UserDataLen - Size of block allocated to hold user data, excluding any metadata.\n*\n*  Additional information\n*    The user data must be correctly aligned for the architecture, which\n*    typically requires that the alignment is at least the alignment\n*    of a double or a long long.  pUserData is, therefore, compressed by\n*    shrinking as IDs are compressed, controlled by the specific setting\n*    of SEGGER_SYSVIEW_ID_SHIFT.\n*\n*    In the same way, UserDataLen must reflect the size of the allocated\n*    block, not the allocation size requested by the application.  This\n*    size is also subject to compression, controlled by the specific setting\n*    of SEGGER_SYSVIEW_ID_SHIFT.\n*\n*    As an example, assume the allocator is running on a Cortex-M device\n*    with SEGGER_SYSVIEW_ID_SHIFT set to 2 (the word alignment of the device).\n*    If a user requests an allocation of 5 bytes, a hypothetical heap\n*    allocator could allocate a block with size 32 bytes for this.  The value\n*    of UserDataLen sent to SystemView for recording should be 32, not 5,\n*    and the 32 is compressed by shifting by two bits, the configured value\n*    of SEGGER_SYSVIEW_ID_SHIFT, and describes the number of bytes that are\n*    consumed from managed memory from which SystemView can calculate\n*    accurate heap metrics.\n*/\nvoid SEGGER_SYSVIEW_HeapAlloc(void *pHeap, void *pUserData, unsigned int UserDataLen)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 3 * SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, SYSVIEW_EVTID_EX_HEAP_ALLOC);\n    ENCODE_U32(pPayload, SHRINK_ID((U32)pHeap));\n    ENCODE_U32(pPayload, SHRINK_ID((U32)pUserData));\n    ENCODE_U32(pPayload, UserDataLen >> SEGGER_SYSVIEW_ID_SHIFT);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_EX);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_HeapAllocEx()\n*\n*  Function description\n*    Record a per-heap allocation event.\n*\n*  Parameters\n*    pHeap       - Pointer to heap where allocation was made.\n*    pUserData   - Pointer to allocated user data.\n*    UserDataLen - Size of block allocated to hold user data, excluding any metadata.\n*    Tag         - Block tag, typically used to identify the owner of the block.\n*\n*  Additional information\n*    The user data must be correctly aligned for the architecture, which\n*    typically requires that the alignment is at least the alignment\n*    of a double or a long long.  pUserData is, therefore, compressed by\n*    shrinking as IDs are compressed, controlled by the specific setting\n*    of SEGGER_SYSVIEW_ID_SHIFT.\n*\n*    In the same way, UserDataLen must reflect the size of the allocated\n*    block, not the allocation size requested by the application.  This\n*    size is also subject to compression, controlled by the specific setting\n*    of SEGGER_SYSVIEW_ID_SHIFT.\n*\n*    As an example, assume the allocator is running on a Cortex-M device\n*    with SEGGER_SYSVIEW_ID_SHIFT set to 2 (the word alignment of the device).\n*    If a user requests an allocation of 5 bytes, a hypothetical heap\n*    allocator could allocate a block with size 32 bytes for this.  The value\n*    of UserDataLen sent to SystemView for recording should be 32, not 5,\n*    and the 32 is compressed by shifting by two bits, the configured value\n*    of SEGGER_SYSVIEW_ID_SHIFT, and describes the number of bytes that are\n*    consumed from managed memory from which SystemView can calculate\n*    accurate heap metrics.\n*\n*  See also\n*    SEGGER_SYSVIEW_HeapAlloc().\n*/\nvoid SEGGER_SYSVIEW_HeapAllocEx(void *pHeap, void *pUserData, unsigned int UserDataLen, unsigned int Tag)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 5 * SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, SYSVIEW_EVTID_EX_HEAP_ALLOC_EX);\n    ENCODE_U32(pPayload, SHRINK_ID((U32)pHeap));\n    ENCODE_U32(pPayload, SHRINK_ID((U32)pUserData));\n    ENCODE_U32(pPayload, UserDataLen >> SEGGER_SYSVIEW_ID_SHIFT);\n    ENCODE_U32(pPayload, Tag);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_EX);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_HeapFree()\n*\n*  Function description\n*    Record a heap deallocation event.\n*\n*  Parameters\n*    pHeap     - Pointer to heap where allocation was made.\n*    pUserData - Pointer to allocated user data.\n*\n*  Additional information\n*    SystemViews track allocations and knows the size of the\n*    allocated data.\n*/\nvoid SEGGER_SYSVIEW_HeapFree(void *pHeap, void *pUserData)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32);\n    //\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, SYSVIEW_EVTID_EX_HEAP_FREE);\n    ENCODE_U32(pPayload, SHRINK_ID((U32)pHeap));\n    ENCODE_U32(pPayload, SHRINK_ID((U32)pUserData));\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_EX);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_SendPacket()\n*\n*  Function description\n*    Send an event packet.\n*\n*  Parameters\n*    pPacket      - Pointer to the start of the packet.\n*    pPayloadEnd  - Pointer to the end of the payload.\n*                   Make sure there are at least 5 bytes free after the payload.\n*    EventId      - Id of the event packet.\n*\n*  Return value\n*    !=0:  Success, Message sent.\n*    ==0:  Buffer full, Message *NOT* sent.\n*/\nint SEGGER_SYSVIEW_SendPacket(U8 *pPacket, U8 *pPayloadEnd, unsigned int EventId)\n{\n#if (SEGGER_SYSVIEW_USE_STATIC_BUFFER == 1)\n    SEGGER_SYSVIEW_LOCK();\n#endif\n    _SendPacket(pPacket + 4, pPayloadEnd, EventId);\n#if (SEGGER_SYSVIEW_USE_STATIC_BUFFER == 1)\n    SEGGER_SYSVIEW_UNLOCK();\n#endif\n    return 0;\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_EncodeU32()\n*\n*  Function description\n*    Encode a U32 in variable-length format.\n*\n*  Parameters\n*    pPayload - Pointer to where U32 will be encoded.\n*    Value    - The 32-bit value to be encoded.\n*\n*  Return value\n*    Pointer to the byte following the value, i.e. the first free\n*    byte in the payload and the next position to store payload\n*    content.\n*/\nU8 *SEGGER_SYSVIEW_EncodeU32(U8 *pPayload, U32 Value)\n{\n    ENCODE_U32(pPayload, Value);\n    return pPayload;\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_EncodeString()\n*\n*  Function description\n*    Encode a string in variable-length format.\n*\n*  Parameters\n*    pPayload - Pointer to where string will be encoded.\n*    s        - String to encode.\n*    MaxLen   - Maximum number of characters to encode from string.\n*\n*  Return value\n*    Pointer to the byte following the value, i.e. the first free\n*    byte in the payload and the next position to store payload\n*    content.\n*\n*  Additional information\n*    The string is encoded as a count byte followed by the contents\n*    of the string.\n*    No more than 1 + MaxLen bytes will be encoded to the payload.\n*/\nU8 *SEGGER_SYSVIEW_EncodeString(U8 *pPayload, const char *s, unsigned int MaxLen)\n{\n    return _EncodeStr(pPayload, s, MaxLen);\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_EncodeData()\n*\n*  Function description\n*    Encode a byte buffer in variable-length format.\n*\n*  Parameters\n*    pPayload - Pointer to where string will be encoded.\n*    pSrc     - Pointer to data buffer to be encoded.\n*    NumBytes - Number of bytes in the buffer to be encoded.\n*\n*  Return value\n*    Pointer to the byte following the value, i.e. the first free\n*    byte in the payload and the next position to store payload\n*    content.\n*\n*  Additional information\n*    The data is encoded as a count byte followed by the contents\n*    of the data buffer.\n*    Make sure NumBytes + 1 bytes are free for the payload.\n*/\nU8 *SEGGER_SYSVIEW_EncodeData(U8 *pPayload, const char *pSrc, unsigned int NumBytes)\n{\n    return _EncodeData(pPayload, pSrc, NumBytes);\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_EncodeId()\n*\n*  Function description\n*    Encode a 32-bit Id in shrunken variable-length format.\n*\n*  Parameters\n*    pPayload - Pointer to where the Id will be encoded.\n*    Id       - The 32-bit value to be encoded.\n*\n*  Return value\n*    Pointer to the byte following the value, i.e. the first free\n*    byte in the payload and the next position to store payload\n*    content.\n*\n*  Additional information\n*    The parameters to shrink an Id can be configured in\n*    SEGGER_SYSVIEW_Conf.h and via SEGGER_SYSVIEW_SetRAMBase().\n*     SEGGER_SYSVIEW_ID_BASE: Lowest Id reported by the application.\n*       (i.e. 0x20000000 when all Ids are an address in this RAM)\n*     SEGGER_SYSVIEW_ID_SHIFT: Number of bits to shift the Id to\n*       save bandwidth. (i.e. 2 when Ids are 4 byte aligned)\n*/\nU8 *SEGGER_SYSVIEW_EncodeId(U8 *pPayload, U32 Id)\n{\n    Id = SHRINK_ID(Id);\n    ENCODE_U32(pPayload, Id);\n    return pPayload;\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_ShrinkId()\n*\n*  Function description\n*    Get the shrunken value of an Id for further processing like in\n*    SEGGER_SYSVIEW_NameResource().\n*\n*  Parameters\n*    Id       - The 32-bit value to be shrunken.\n*\n*  Return value\n*    Shrunken Id.\n*\n*  Additional information\n*    The parameters to shrink an Id can be configured in\n*    SEGGER_SYSVIEW_Conf.h and via SEGGER_SYSVIEW_SetRAMBase().\n*     SEGGER_SYSVIEW_ID_BASE: Lowest Id reported by the application.\n*       (i.e. 0x20000000 when all Ids are an address in this RAM)\n*     SEGGER_SYSVIEW_ID_SHIFT: Number of bits to shift the Id to\n*       save bandwidth. (i.e. 2 when Ids are 4 byte aligned)\n*/\nU32 SEGGER_SYSVIEW_ShrinkId(U32 Id)\n{\n    return SHRINK_ID(Id);\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RegisterModule()\n*\n*  Function description\n*    Register a middleware module for recording its events.\n*\n*  Parameters\n*    pModule  - The middleware module information.\n*\n*  Additional information\n*    SEGGER_SYSVIEW_MODULE elements:\n*      sDescription      - Pointer to a string containing the module name and optionally the module event description.\n*      NumEvents         - Number of events the module wants to register.\n*      EventOffset       - Offset to be added to the event Ids. Out parameter, set by this function. Do not modify after calling this function.\n*      pfSendModuleDesc  - Callback function pointer to send more detailed module description to SystemView Application.\n*      pNext             - Pointer to next registered module. Out parameter, set by this function. Do not modify after calling this function.\n*/\nvoid SEGGER_SYSVIEW_RegisterModule(SEGGER_SYSVIEW_MODULE *pModule)\n{\n    SEGGER_SYSVIEW_LOCK();\n    if (_pFirstModule == 0) {\n        //\n        // No module registered, yet.\n        // Start list with new module.\n        // EventOffset is the base offset for modules\n        //\n        pModule->EventOffset = MODULE_EVENT_OFFSET;\n        pModule->pNext = 0;\n        _pFirstModule = pModule;\n        _NumModules = 1;\n    } else {\n        //\n        // Registreded module(s) present.\n        // Prepend new module in list.\n        // EventOffset set from number of events and offset of previous module.\n        //\n        pModule->EventOffset = _pFirstModule->EventOffset + _pFirstModule->NumEvents;\n        pModule->pNext = _pFirstModule;\n        _pFirstModule = pModule;\n        _NumModules++;\n    }\n    SEGGER_SYSVIEW_SendModule(0);\n    SEGGER_SYSVIEW_UNLOCK();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_RecordModuleDescription()\n*\n*  Function description\n*    Sends detailed information of a registered module to the host.\n*\n*  Parameters\n*    pModule      - Pointer to the described module.\n*    sDescription - Pointer to a description string.\n*/\nvoid SEGGER_SYSVIEW_RecordModuleDescription(const SEGGER_SYSVIEW_MODULE *pModule, const char *sDescription)\n{\n    U8  ModuleId;\n    SEGGER_SYSVIEW_MODULE *p;\n\n    p = _pFirstModule;\n    ModuleId = 0;\n    do {\n        if (p == pModule) {\n            break;\n        }\n        ModuleId++;\n        p = p->pNext;\n    } while (p);\n    {\n        U8 *pPayload;\n        U8 *pPayloadStart;\n        RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + 1 + SEGGER_SYSVIEW_MAX_STRING_LEN);\n        //\n        pPayload = pPayloadStart;\n        //\n        // Send module description\n        // Send event offset and number of events\n        //\n        ENCODE_U32(pPayload, ModuleId);\n        ENCODE_U32(pPayload, (pModule->EventOffset));\n        pPayload = _EncodeStr(pPayload, sDescription, SEGGER_SYSVIEW_MAX_STRING_LEN);\n        _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_MODULEDESC);\n        RECORD_END();\n    }\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_SendModule()\n*\n*  Function description\n*    Sends the information of a registered module to the host.\n*\n*  Parameters\n*    ModuleId   - Id of the requested module.\n*/\nvoid SEGGER_SYSVIEW_SendModule(U8 ModuleId)\n{\n    SEGGER_SYSVIEW_MODULE *pModule;\n    U32 n;\n\n    if (_pFirstModule != 0) {\n        pModule = _pFirstModule;\n        for (n = 0; n < ModuleId; n++) {\n            pModule = pModule->pNext;\n            if (pModule == 0) {\n                break;\n            }\n        }\n        if (pModule != 0) {\n            U8 *pPayload;\n            U8 *pPayloadStart;\n            RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + 1 + SEGGER_SYSVIEW_MAX_STRING_LEN);\n            //\n            pPayload = pPayloadStart;\n            //\n            // Send module description\n            // Send event offset and number of events\n            //\n            ENCODE_U32(pPayload, ModuleId);\n            ENCODE_U32(pPayload, (pModule->EventOffset));\n            pPayload = _EncodeStr(pPayload, pModule->sModule, SEGGER_SYSVIEW_MAX_STRING_LEN);\n            _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_MODULEDESC);\n            RECORD_END();\n        }\n        if (pModule && pModule->pfSendModuleDesc) {\n            pModule->pfSendModuleDesc();\n        }\n    }\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_SendModuleDescription()\n*\n*  Function description\n*    Triggers a send of the registered module descriptions.\n*\n*/\nvoid SEGGER_SYSVIEW_SendModuleDescription(void)\n{\n    SEGGER_SYSVIEW_MODULE *pModule;\n\n    if (_pFirstModule != 0) {\n        pModule = _pFirstModule;\n        do {\n            if (pModule->pfSendModuleDesc) {\n                pModule->pfSendModuleDesc();\n            }\n            pModule = pModule->pNext;\n        } while (pModule);\n    }\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_SendNumModules()\n*\n*  Function description\n*    Send the number of registered modules to the host.\n*/\nvoid SEGGER_SYSVIEW_SendNumModules(void)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32);\n    pPayload = pPayloadStart;\n    ENCODE_U32(pPayload, _NumModules);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_NUMMODULES);\n    RECORD_END();\n}\n\n#ifndef SEGGER_SYSVIEW_EXCLUDE_PRINTF // Define in project to avoid warnings about variable parameter list\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_PrintfHostEx()\n*\n*  Function description\n*    Print a string which is formatted on the host by the SystemView Application\n*    with Additional information.\n*\n*  Parameters\n*    s        - String to be formatted.\n*    Options  - Options for the string. i.e. Log level.\n*\n*  Additional information\n*    All format arguments are treated as 32-bit scalar values.\n*/\nvoid SEGGER_SYSVIEW_PrintfHostEx(const char *s, U32 Options, ...)\n{\n    va_list ParamList;\n#if SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT\n    int r;\n\n    va_start(ParamList, Options);\n    r = _VPrintHost(s, Options, &ParamList);\n    va_end(ParamList);\n\n    if (r == -1) {\n        va_start(ParamList, Options);\n        _VPrintTarget(s, Options, &ParamList);\n        va_end(ParamList);\n    }\n#else\n    va_start(ParamList, Options);\n    _VPrintHost(s, Options, &ParamList);\n    va_end(ParamList);\n#endif\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_VPrintfHostEx()\n*\n*  Function description\n*    Print a string which is formatted on the host by the SystemView Application\n*    with Additional information.\n*\n*  Parameters\n*    s          - String to be formatted.\n*    Options    - Options for the string. i.e. Log level.\n*    pParamList - Pointer to the list of arguments for the format string\n*\n*  Additional information\n*    All format arguments are treated as 32-bit scalar values.\n*/\nvoid SEGGER_SYSVIEW_VPrintfHostEx(const char *s, U32 Options, va_list *pParamList)\n{\n#if SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT\n    int r;\n    va_list ParamListCopy;\n    va_copy(ParamListCopy, *pParamList);\n\n    r = _VPrintHost(s, Options, pParamList);\n\n    if (r == -1) {\n        _VPrintTarget(s, Options, &ParamListCopy);\n    }\n    va_end(ParamListCopy);\n#else\n    _VPrintHost(s, Options, pParamList);\n#endif\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_PrintfHost()\n*\n*  Function description\n*    Print a string which is formatted on the host by the SystemView Application.\n*\n*  Parameters\n*    s        - String to be formatted.\n*\n*  Additional information\n*    All format arguments are treated as 32-bit scalar values.\n*/\nvoid SEGGER_SYSVIEW_PrintfHost(const char *s, ...)\n{\n    va_list ParamList;\n#if SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT\n    int r;\n\n    va_start(ParamList, s);\n    r = _VPrintHost(s, SEGGER_SYSVIEW_LOG, &ParamList);\n    va_end(ParamList);\n\n    if (r == -1) {\n        va_start(ParamList, s);\n        _VPrintTarget(s, SEGGER_SYSVIEW_LOG, &ParamList);\n        va_end(ParamList);\n    }\n#else\n    va_start(ParamList, s);\n    _VPrintHost(s, SEGGER_SYSVIEW_LOG, &ParamList);\n    va_end(ParamList);\n#endif\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_VPrintfHost()\n*\n*  Function description\n*    Print a string which is formatted on the host by the SystemView Application.\n*\n*  Parameters\n*    s          - String to be formatted.\n*    pParamList - Pointer to the list of arguments for the format string\n*\n*  Additional information\n*    All format arguments are treated as 32-bit scalar values.\n*/\nvoid SEGGER_SYSVIEW_VPrintfHost(const char *s, va_list *pParamList)\n{\n#if SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT\n    int r;\n    va_list ParamListCopy;\n    va_copy(ParamListCopy, *pParamList);\n\n    r = _VPrintHost(s, SEGGER_SYSVIEW_LOG, pParamList);\n\n    if (r == -1) {\n        _VPrintTarget(s, SEGGER_SYSVIEW_LOG, &ParamListCopy);\n    }\n    va_end(ParamListCopy);\n#else\n    _VPrintHost(s, SEGGER_SYSVIEW_LOG, pParamList);\n#endif\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_WarnfHost()\n*\n*  Function description\n*    Print a warning string which is formatted on the host by\n*    the SystemView Application.\n*\n*  Parameters\n*    s        - String to be formatted.\n*\n*  Additional information\n*    All format arguments are treated as 32-bit scalar values.\n*/\nvoid SEGGER_SYSVIEW_WarnfHost(const char *s, ...)\n{\n    va_list ParamList;\n#if SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT\n    int r;\n\n    va_start(ParamList, s);\n    r = _VPrintHost(s, SEGGER_SYSVIEW_WARNING, &ParamList);\n    va_end(ParamList);\n\n    if (r == -1) {\n        va_start(ParamList, s);\n        _VPrintTarget(s, SEGGER_SYSVIEW_WARNING, &ParamList);\n        va_end(ParamList);\n    }\n#else\n    va_start(ParamList, s);\n    _VPrintHost(s, SEGGER_SYSVIEW_WARNING, &ParamList);\n    va_end(ParamList);\n#endif\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_VWarnfHost()\n*\n*  Function description\n*    Print a warning string which is formatted on the host by\n*    the SystemView Application.\n*\n*  Parameters\n*    s          - String to be formatted.\n*    pParamList - Pointer to the list of arguments for the format string\n*\n*  Additional information\n*    All format arguments are treated as 32-bit scalar values.\n*/\nvoid SEGGER_SYSVIEW_VWarnfHost(const char *s, va_list *pParamList)\n{\n#if SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT\n    int r;\n    va_list ParamListCopy;\n    va_copy(ParamListCopy, *pParamList);\n\n    r = _VPrintHost(s, SEGGER_SYSVIEW_WARNING, pParamList);\n\n    if (r == -1) {\n        _VPrintTarget(s, SEGGER_SYSVIEW_WARNING, &ParamListCopy);\n    }\n    va_end(ParamListCopy);\n#else\n    _VPrintHost(s, SEGGER_SYSVIEW_WARNING, pParamList);\n#endif\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_ErrorfHost()\n*\n*  Function description\n*    Print an error string which is formatted on the host by\n*    the SystemView Application.\n*\n*  Parameters\n*    s        - String to be formatted.\n*\n*  Additional information\n*    All format arguments are treated as 32-bit scalar values.\n*/\nvoid SEGGER_SYSVIEW_ErrorfHost(const char *s, ...)\n{\n    va_list ParamList;\n#if SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT\n    int r;\n\n    va_start(ParamList, s);\n    r = _VPrintHost(s, SEGGER_SYSVIEW_ERROR, &ParamList);\n    va_end(ParamList);\n\n    if (r == -1) {\n        va_start(ParamList, s);\n        _VPrintTarget(s, SEGGER_SYSVIEW_ERROR, &ParamList);\n        va_end(ParamList);\n    }\n#else\n    va_start(ParamList, s);\n    _VPrintHost(s, SEGGER_SYSVIEW_ERROR, &ParamList);\n    va_end(ParamList);\n#endif\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_VErrorfHost()\n*\n*  Function description\n*    Print a warning string which is formatted on the host by\n*    the SystemView Application.\n*\n*  Parameters\n*    s          - String to be formatted.\n*    pParamList - Pointer to the list of arguments for the format string\n*\n*  Additional information\n*    All format arguments are treated as 32-bit scalar values.\n*/\nvoid SEGGER_SYSVIEW_VErrorfHost(const char *s, va_list *pParamList)\n{\n#if SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT\n    int r;\n    va_list ParamListCopy;\n    va_copy(ParamListCopy, *pParamList);\n\n    r = _VPrintHost(s, SEGGER_SYSVIEW_ERROR, pParamList);\n\n    if (r == -1) {\n        _VPrintTarget(s, SEGGER_SYSVIEW_ERROR, &ParamListCopy);\n    }\n    va_end(ParamListCopy);\n#else\n    _VPrintHost(s, SEGGER_SYSVIEW_ERROR, pParamList);\n#endif\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_PrintfTargetEx()\n*\n*  Function description\n*    Print a string which is formatted on the target before sent to\n*    the host with Additional information.\n*\n*  Parameters\n*    s        - String to be formatted.\n*    Options  - Options for the string. i.e. Log level.\n*/\nvoid SEGGER_SYSVIEW_PrintfTargetEx(const char *s, U32 Options, ...)\n{\n    va_list ParamList;\n\n    va_start(ParamList, Options);\n    _VPrintTarget(s, Options, &ParamList);\n    va_end(ParamList);\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_VPrintfTargetEx()\n*\n*  Function description\n*    Print a string which is formatted on the target before sent to\n*    the host with Additional information.\n*\n*  Parameters\n*    s          - String to be formatted.\n*    Options    - Options for the string. i.e. Log level.\n*    pParamList - Pointer to the list of arguments for the format string\n*/\nvoid SEGGER_SYSVIEW_VPrintfTargetEx(const char *s, U32 Options, va_list *pParamList)\n{\n    _VPrintTarget(s, Options, pParamList);\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_PrintfTarget()\n*\n*  Function description\n*    Print a string which is formatted on the target before sent to\n*    the host.\n*\n*  Parameters\n*    s        - String to be formatted.\n*/\nvoid SEGGER_SYSVIEW_PrintfTarget(const char *s, ...)\n{\n    va_list ParamList;\n\n    va_start(ParamList, s);\n    _VPrintTarget(s, SEGGER_SYSVIEW_LOG, &ParamList);\n    va_end(ParamList);\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_VPrintfTarget()\n*\n*  Function description\n*    Print a string which is formatted on the target before sent to\n*    the host.\n*\n*  Parameters\n*    s          - String to be formatted.\n*    pParamList - Pointer to the list of arguments for the format string\n*/\nvoid SEGGER_SYSVIEW_VPrintfTarget(const char *s, va_list *pParamList)\n{\n    _VPrintTarget(s, SEGGER_SYSVIEW_LOG, pParamList);\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_WarnfTarget()\n*\n*  Function description\n*    Print a warning string which is formatted on the target before\n*    sent to the host.\n*\n*  Parameters\n*    s        - String to be formatted.\n*/\nvoid SEGGER_SYSVIEW_WarnfTarget(const char *s, ...)\n{\n    va_list ParamList;\n\n    va_start(ParamList, s);\n    _VPrintTarget(s, SEGGER_SYSVIEW_WARNING, &ParamList);\n    va_end(ParamList);\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_VWarnfTarget()\n*\n*  Function description\n*    Print a warning string which is formatted on the target before\n*    sent to the host.\n*\n*  Parameters\n*    s          - String to be formatted.\n*    pParamList - Pointer to the list of arguments for the format string\n*/\nvoid SEGGER_SYSVIEW_VWarnfTarget(const char *s, va_list *pParamList)\n{\n    _VPrintTarget(s, SEGGER_SYSVIEW_WARNING, pParamList);\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_ErrorfTarget()\n*\n*  Function description\n*    Print an error string which is formatted on the target before\n*    sent to the host.\n*\n*  Parameters\n*    s        - String to be formatted.\n*/\nvoid SEGGER_SYSVIEW_ErrorfTarget(const char *s, ...)\n{\n    va_list ParamList;\n\n    va_start(ParamList, s);\n    _VPrintTarget(s, SEGGER_SYSVIEW_ERROR, &ParamList);\n    va_end(ParamList);\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_VErrorfTarget()\n*\n*  Function description\n*    Print an error string which is formatted on the target before\n*    sent to the host.\n*\n*  Parameters\n*    s          - String to be formatted.\n*    pParamList - Pointer to the list of arguments for the format string\n*/\nvoid SEGGER_SYSVIEW_VErrorfTarget(const char *s, va_list *pParamList)\n{\n    _VPrintTarget(s, SEGGER_SYSVIEW_ERROR, pParamList);\n}\n#endif // SEGGER_SYSVIEW_EXCLUDE_PRINTF\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_Print()\n*\n*  Function description\n*    Print a string to the host.\n*\n*  Parameters\n*    s        - String to sent.\n*/\nvoid SEGGER_SYSVIEW_Print(const char *s)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + SEGGER_SYSVIEW_MAX_STRING_LEN);\n    //\n    pPayload = _EncodeStr(pPayloadStart, s, SEGGER_SYSVIEW_MAX_STRING_LEN);\n    ENCODE_U32(pPayload, SEGGER_SYSVIEW_LOG);\n    ENCODE_U32(pPayload, 0);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_PRINT_FORMATTED);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_Warn()\n*\n*  Function description\n*    Print a warning string to the host.\n*\n*  Parameters\n*    s        - String to sent.\n*/\nvoid SEGGER_SYSVIEW_Warn(const char *s)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + SEGGER_SYSVIEW_MAX_STRING_LEN);\n    //\n    pPayload = _EncodeStr(pPayloadStart, s, SEGGER_SYSVIEW_MAX_STRING_LEN);\n    ENCODE_U32(pPayload, SEGGER_SYSVIEW_WARNING);\n    ENCODE_U32(pPayload, 0);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_PRINT_FORMATTED);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_Error()\n*\n*  Function description\n*    Print an error string to the host.\n*\n*  Parameters\n*    s        - String to sent.\n*/\nvoid SEGGER_SYSVIEW_Error(const char *s)\n{\n    U8 *pPayload;\n    U8 *pPayloadStart;\n    RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + SEGGER_SYSVIEW_MAX_STRING_LEN);\n    //\n    pPayload = _EncodeStr(pPayloadStart, s, SEGGER_SYSVIEW_MAX_STRING_LEN);\n    ENCODE_U32(pPayload, SEGGER_SYSVIEW_ERROR);\n    ENCODE_U32(pPayload, 0);\n    _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_PRINT_FORMATTED);\n    RECORD_END();\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_EnableEvents()\n*\n*  Function description\n*    Enable standard SystemView events to be generated.\n*\n*  Parameters\n*    EnableMask   - Events to be enabled.\n*/\nvoid SEGGER_SYSVIEW_EnableEvents(U32 EnableMask)\n{\n    _SYSVIEW_Globals.DisabledEvents &= ~EnableMask;\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_DisableEvents()\n*\n*  Function description\n*    Disable standard SystemView events to not be generated.\n*\n*  Parameters\n*    DisableMask  - Events to be disabled.\n*/\nvoid SEGGER_SYSVIEW_DisableEvents(U32 DisableMask)\n{\n    _SYSVIEW_Globals.DisabledEvents |= DisableMask;\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_IsStarted()\n*\n*  Function description\n*    Handle incoming packets if any and check if recording is started.\n*\n*  Return value\n*      0: Recording not started.\n*    > 0: Recording started.\n*/\nint SEGGER_SYSVIEW_IsStarted(void)\n{\n#if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1)\n    //\n    // Check if host is sending data which needs to be processed.\n    //\n    if (SEGGER_RTT_HASDATA(CHANNEL_ID_DOWN)) {\n        if (_SYSVIEW_Globals.RecursionCnt == 0) {   // Avoid uncontrolled nesting. This way, this routine can call itself once, but no more often than that.\n            _SYSVIEW_Globals.RecursionCnt = 1;\n            _HandleIncomingPacket();\n            _SYSVIEW_Globals.RecursionCnt = 0;\n        }\n    }\n#endif\n    return _SYSVIEW_Globals.EnableState;\n}\n\n\n/*************************** End of file ****************************/\n"
  },
  {
    "path": "esp_sysview/src/SEGGER/SEGGER_SYSVIEW.h",
    "content": "/*\n * SPDX-FileCopyrightText: 1995-2021 SEGGER Microcontroller GmbH\n *\n * SPDX-License-Identifier: BSD-1-Clause\n *\n * SPDX-FileContributor: 2023-2024 Espressif Systems (Shanghai) CO LTD\n */\n/*********************************************************************\n*                    SEGGER Microcontroller GmbH                     *\n*                        The Embedded Experts                        *\n**********************************************************************\n*                                                                    *\n*            (c) 1995 - 2024 SEGGER Microcontroller GmbH             *\n*                                                                    *\n*       www.segger.com     Support: support@segger.com               *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SEGGER SystemView * Real-time application analysis           *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n* All rights reserved.                                               *\n*                                                                    *\n* SEGGER strongly recommends to not make any changes                 *\n* to or modify the source code of this software in order to stay     *\n* compatible with the SystemView and RTT protocol, and J-Link.       *\n*                                                                    *\n* Redistribution and use in source and binary forms, with or         *\n* without modification, are permitted provided that the following    *\n* condition is met:                                                  *\n*                                                                    *\n* o Redistributions of source code must retain the above copyright   *\n*   notice, this condition and the following disclaimer.             *\n*                                                                    *\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             *\n* CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,        *\n* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           *\n* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           *\n* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *\n* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR           *\n* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  *\n* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;    *\n* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF      *\n* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT          *\n* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE  *\n* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *\n* DAMAGE.                                                            *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SystemView version: 3.56                                    *\n*                                                                    *\n**********************************************************************\n-------------------------- END-OF-HEADER -----------------------------\nFile    : SEGGER_SYSVIEW.h\nPurpose : System visualization API.\nRevision: $Rev: 28768 $\n*/\n\n#ifndef SEGGER_SYSVIEW_H\n#define SEGGER_SYSVIEW_H\n\n/*********************************************************************\n*\n*       #include Section\n*\n**********************************************************************\n*/\n\n#include \"SEGGER.h\"\n#include \"SEGGER_SYSVIEW_ConfDefaults.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n/*********************************************************************\n*\n*       Defines, fixed\n*\n**********************************************************************\n*/\n\n#define SEGGER_SYSVIEW_MAJOR          3\n#define SEGGER_SYSVIEW_MINOR          32\n#define SEGGER_SYSVIEW_REV            0\n#define SEGGER_SYSVIEW_VERSION        ((SEGGER_SYSVIEW_MAJOR * 10000) + (SEGGER_SYSVIEW_MINOR * 100) + SEGGER_SYSVIEW_REV)\n\n#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.\n#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.\n\n#define SEGGER_SYSVIEW_LOG            (0u)\n#define SEGGER_SYSVIEW_WARNING        (1u)\n#define SEGGER_SYSVIEW_ERROR          (2u)\n#define SEGGER_SYSVIEW_FLAG_APPEND    (1u << 6)\n\n#define SEGGER_SYSVIEW_PREPARE_PACKET(p)  (p) + 4\n//\n// SystemView events. First 32 IDs from 0 .. 31 are reserved for these\n//\n#define   SYSVIEW_EVTID_NOP                0  // Dummy packet.\n#define   SYSVIEW_EVTID_OVERFLOW           1\n#define   SYSVIEW_EVTID_ISR_ENTER          2\n#define   SYSVIEW_EVTID_ISR_EXIT           3\n#define   SYSVIEW_EVTID_TASK_START_EXEC    4\n#define   SYSVIEW_EVTID_TASK_STOP_EXEC     5\n#define   SYSVIEW_EVTID_TASK_START_READY   6\n#define   SYSVIEW_EVTID_TASK_STOP_READY    7\n#define   SYSVIEW_EVTID_TASK_CREATE        8\n#define   SYSVIEW_EVTID_TASK_INFO          9\n#define   SYSVIEW_EVTID_TRACE_START       10\n#define   SYSVIEW_EVTID_TRACE_STOP        11\n#define   SYSVIEW_EVTID_SYSTIME_CYCLES    12\n#define   SYSVIEW_EVTID_SYSTIME_US        13\n#define   SYSVIEW_EVTID_SYSDESC           14\n#define   SYSVIEW_EVTID_MARK_START        15\n#define   SYSVIEW_EVTID_MARK_STOP         16\n#define   SYSVIEW_EVTID_IDLE              17\n#define   SYSVIEW_EVTID_ISR_TO_SCHEDULER  18\n#define   SYSVIEW_EVTID_TIMER_ENTER       19\n#define   SYSVIEW_EVTID_TIMER_EXIT        20\n#define   SYSVIEW_EVTID_STACK_INFO        21\n#define   SYSVIEW_EVTID_MODULEDESC        22\n#define   SYSVIEW_EVTID_DATA_SAMPLE       23\n#define   SYSVIEW_EVTID_INIT              24\n#define   SYSVIEW_EVTID_NAME_RESOURCE     25\n#define   SYSVIEW_EVTID_PRINT_FORMATTED   26\n#define   SYSVIEW_EVTID_NUMMODULES        27\n#define   SYSVIEW_EVTID_END_CALL          28\n#define   SYSVIEW_EVTID_TASK_TERMINATE    29\n\n#define   SYSVIEW_EVTID_EX                31\n//\n// SystemView extended events. Sent with ID 31.\n//\n#define   SYSVIEW_EVTID_EX_MARK           0\n#define   SYSVIEW_EVTID_EX_NAME_MARKER    1\n#define   SYSVIEW_EVTID_EX_HEAP_DEFINE    2\n#define   SYSVIEW_EVTID_EX_HEAP_ALLOC     3\n#define   SYSVIEW_EVTID_EX_HEAP_ALLOC_EX  4\n#define   SYSVIEW_EVTID_EX_HEAP_FREE      5\n#define   SYSVIEW_EVTID_EX_REGISTER_DATA  6\n//\n// Event masks to disable/enable events\n//\n#define   SYSVIEW_EVTMASK_NOP               (1 << SYSVIEW_EVTID_NOP)\n#define   SYSVIEW_EVTMASK_OVERFLOW          (1 << SYSVIEW_EVTID_OVERFLOW)\n#define   SYSVIEW_EVTMASK_ISR_ENTER         (1 << SYSVIEW_EVTID_ISR_ENTER)\n#define   SYSVIEW_EVTMASK_ISR_EXIT          (1 << SYSVIEW_EVTID_ISR_EXIT)\n#define   SYSVIEW_EVTMASK_TASK_START_EXEC   (1 << SYSVIEW_EVTID_TASK_START_EXEC)\n#define   SYSVIEW_EVTMASK_TASK_STOP_EXEC    (1 << SYSVIEW_EVTID_TASK_STOP_EXEC)\n#define   SYSVIEW_EVTMASK_TASK_START_READY  (1 << SYSVIEW_EVTID_TASK_START_READY)\n#define   SYSVIEW_EVTMASK_TASK_STOP_READY   (1 << SYSVIEW_EVTID_TASK_STOP_READY)\n#define   SYSVIEW_EVTMASK_TASK_CREATE       (1 << SYSVIEW_EVTID_TASK_CREATE)\n#define   SYSVIEW_EVTMASK_TASK_INFO         (1 << SYSVIEW_EVTID_TASK_INFO)\n#define   SYSVIEW_EVTMASK_TRACE_START       (1 << SYSVIEW_EVTID_TRACE_START)\n#define   SYSVIEW_EVTMASK_TRACE_STOP        (1 << SYSVIEW_EVTID_TRACE_STOP)\n#define   SYSVIEW_EVTMASK_SYSTIME_CYCLES    (1 << SYSVIEW_EVTID_SYSTIME_CYCLES)\n#define   SYSVIEW_EVTMASK_SYSTIME_US        (1 << SYSVIEW_EVTID_SYSTIME_US)\n#define   SYSVIEW_EVTMASK_SYSDESC           (1 << SYSVIEW_EVTID_SYSDESC)\n#define   SYSVIEW_EVTMASK_USER_START        (1 << SYSVIEW_EVTID_USER_START)\n#define   SYSVIEW_EVTMASK_USER_STOP         (1 << SYSVIEW_EVTID_USER_STOP)\n#define   SYSVIEW_EVTMASK_IDLE              (1 << SYSVIEW_EVTID_IDLE)\n#define   SYSVIEW_EVTMASK_ISR_TO_SCHEDULER  (1 << SYSVIEW_EVTID_ISR_TO_SCHEDULER)\n#define   SYSVIEW_EVTMASK_TIMER_ENTER       (1 << SYSVIEW_EVTID_TIMER_ENTER)\n#define   SYSVIEW_EVTMASK_TIMER_EXIT        (1 << SYSVIEW_EVTID_TIMER_EXIT)\n#define   SYSVIEW_EVTMASK_STACK_INFO        (1 << SYSVIEW_EVTID_STACK_INFO)\n#define   SYSVIEW_EVTMASK_MODULEDESC        (1 << SYSVIEW_EVTID_MODULEDESC)\n#define   SYSVIEW_EVTMASK_DATA_SAMPLE       (1 << SYSVIEW_EVTID_DATA_SAMPLE)\n#define   SYSVIEW_EVTMASK_INIT              (1 << SYSVIEW_EVTID_INIT)\n#define   SYSVIEW_EVTMASK_NAME_RESOURCE     (1 << SYSVIEW_EVTID_NAME_RESOURCE)\n#define   SYSVIEW_EVTMASK_PRINT_FORMATTED   (1 << SYSVIEW_EVTID_PRINT_FORMATTED)\n#define   SYSVIEW_EVTMASK_NUMMODULES        (1 << SYSVIEW_EVTID_NUMMODULES)\n#define   SYSVIEW_EVTMASK_END_CALL          (1 << SYSVIEW_EVTID_END_CALL)\n#define   SYSVIEW_EVTMASK_TASK_TERMINATE    (1 << SYSVIEW_EVTID_TASK_TERMINATE)\n\n#define   SYSVIEW_EVTMASK_EX                (1 << SYSVIEW_EVTID_EX)\n\n#define   SYSVIEW_EVTMASK_ALL_INTERRUPTS    ( SYSVIEW_EVTMASK_ISR_ENTER           \\\n                                            | SYSVIEW_EVTMASK_ISR_EXIT            \\\n                                            | SYSVIEW_EVTMASK_ISR_TO_SCHEDULER)\n#define   SYSVIEW_EVTMASK_ALL_TASKS         ( SYSVIEW_EVTMASK_TASK_START_EXEC     \\\n                                            | SYSVIEW_EVTMASK_TASK_STOP_EXEC      \\\n                                            | SYSVIEW_EVTMASK_TASK_START_READY    \\\n                                            | SYSVIEW_EVTMASK_TASK_STOP_READY     \\\n                                            | SYSVIEW_EVTMASK_TASK_CREATE         \\\n                                            | SYSVIEW_EVTMASK_TASK_INFO           \\\n                                            | SYSVIEW_EVTMASK_STACK_INFO          \\\n                                            | SYSVIEW_EVTMASK_TASK_TERMINATE)\n\n/*********************************************************************\n*\n*       Structures\n*\n**********************************************************************\n*/\n\ntypedef struct {\n    U32          TaskID;\n    const char  *sName;\n    U32          Prio;\n    U32          StackBase;\n    U32          StackSize;\n    U32          StackUsage;\n} SEGGER_SYSVIEW_TASKINFO;\n\ntypedef struct {\n    U32          TaskID;\n    U32          StackBase;\n    U32          StackSize;\n    U32          StackUsage;\n} SEGGER_SYSVIEW_STACKINFO;\n\ntypedef struct {\n    U32          ID;\n    union {\n        U32   *pU32_Value;\n        I32   *pI32_Value;\n        float *pFloat_Value;\n    };\n} SEGGER_SYSVIEW_DATA_SAMPLE;\n\ntypedef enum {\n    SEGGER_SYSVIEW_TYPE_U32   = 0,\n    SEGGER_SYSVIEW_TYPE_I32   = 1,\n    SEGGER_SYSVIEW_TYPE_FLOAT = 2\n} SEGGER_SYSVIEW_DATA_TYPE;\n\ntypedef struct {\n    U32                           ID;\n    SEGGER_SYSVIEW_DATA_TYPE      DataType;\n    I32                           Offset;\n    I32                           RangeMin;\n    I32                           RangeMax;\n    float                         ScalingFactor;\n    const char                   *sName;\n    const char                   *sUnit;\n}  SEGGER_SYSVIEW_DATA_REGISTER;\n\ntypedef struct SEGGER_SYSVIEW_MODULE_STRUCT SEGGER_SYSVIEW_MODULE;\n\nstruct SEGGER_SYSVIEW_MODULE_STRUCT {\n    const char                   *sModule;\n    U32                     NumEvents;\n    U32                     EventOffset;\n    void                    (*pfSendModuleDesc)(void);\n    SEGGER_SYSVIEW_MODULE  *pNext;\n};\n\ntypedef void (SEGGER_SYSVIEW_SEND_SYS_DESC_FUNC)(void);\n\n\n/*********************************************************************\n*\n*       Global data\n*\n**********************************************************************\n*/\n\n#ifdef   EXTERN\n#undef EXTERN\n#endif\n\n#ifndef SEGGER_SYSVIEW_C       // Defined in SEGGER_SYSVIEW.c which includes this header beside other C-files\n#define EXTERN extern\n#else\n#define EXTERN\n#endif\n\nEXTERN unsigned int SEGGER_SYSVIEW_TickCnt;\nEXTERN unsigned int SEGGER_SYSVIEW_InterruptId;\n\n#undef EXTERN\n\n/*********************************************************************\n*\n*       API functions\n*\n**********************************************************************\n*/\n\ntypedef struct {\n    U64  (*pfGetTime)               (void);\n    void (*pfSendTaskList)          (void);\n} SEGGER_SYSVIEW_OS_API;\n\n/*********************************************************************\n*\n*       Control and initialization functions\n*/\nvoid SEGGER_SYSVIEW_Init                          (U32 SysFreq, U32 CPUFreq, const SEGGER_SYSVIEW_OS_API *pOSAPI, SEGGER_SYSVIEW_SEND_SYS_DESC_FUNC pfSendSysDesc);\nvoid SEGGER_SYSVIEW_SetRAMBase                    (U32 RAMBaseAddress);\nvoid SEGGER_SYSVIEW_Start                         (void);\nvoid SEGGER_SYSVIEW_Stop                          (void);\nvoid SEGGER_SYSVIEW_GetSysDesc                    (void);\nvoid SEGGER_SYSVIEW_SendTaskList                  (void);\nvoid SEGGER_SYSVIEW_SendTaskInfo                  (const SEGGER_SYSVIEW_TASKINFO *pInfo);\nvoid SEGGER_SYSVIEW_SendStackInfo                 (const SEGGER_SYSVIEW_STACKINFO *pInfo);\nvoid SEGGER_SYSVIEW_SendSysDesc                   (const char *sSysDesc);\nint  SEGGER_SYSVIEW_IsStarted                     (void);\nint  SEGGER_SYSVIEW_GetChannelID                  (void);\n\nvoid  SEGGER_SYSVIEW_SampleData                   (const SEGGER_SYSVIEW_DATA_SAMPLE *pInfo);\n\n// Checks whether tracing has been started\nU8 SEGGER_SYSVIEW_Started(void);\n\n/*********************************************************************\n*\n*       Event recording functions\n*/\nvoid SEGGER_SYSVIEW_RecordVoid                    (unsigned int EventId);\nvoid SEGGER_SYSVIEW_RecordU32                     (unsigned int EventId, U32 Para0);\nvoid SEGGER_SYSVIEW_RecordU32x2                   (unsigned int EventId, U32 Para0, U32 Para1);\nvoid SEGGER_SYSVIEW_RecordU32x3                   (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2);\nvoid SEGGER_SYSVIEW_RecordU32x4                   (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2, U32 Para3);\nvoid SEGGER_SYSVIEW_RecordU32x5                   (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4);\nvoid SEGGER_SYSVIEW_RecordU32x6                   (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5);\nvoid SEGGER_SYSVIEW_RecordU32x7                   (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5, U32 Para6);\nvoid SEGGER_SYSVIEW_RecordU32x8                   (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5, U32 Para6, U32 Para7);\nvoid SEGGER_SYSVIEW_RecordU32x9                   (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5, U32 Para6, U32 Para7, U32 Para8);\nvoid 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);\nvoid SEGGER_SYSVIEW_RecordString                  (unsigned int EventId, const char *pString);\nvoid SEGGER_SYSVIEW_RecordSystime                 (void);\nvoid SEGGER_SYSVIEW_RecordEnterISR                (U32 IrqId);\nvoid SEGGER_SYSVIEW_RecordExitISR                 (void);\nvoid SEGGER_SYSVIEW_RecordExitISRToScheduler      (void);\nvoid SEGGER_SYSVIEW_RecordEnterTimer              (U32 TimerId);\nvoid SEGGER_SYSVIEW_RecordExitTimer               (void);\nvoid SEGGER_SYSVIEW_RecordEndCall                 (unsigned int EventID);\nvoid SEGGER_SYSVIEW_RecordEndCallU32              (unsigned int EventID, U32 Para0);\n\nvoid SEGGER_SYSVIEW_OnIdle                        (void);\nvoid SEGGER_SYSVIEW_OnTaskCreate                  (U32 TaskId);\nvoid SEGGER_SYSVIEW_OnTaskTerminate               (U32 TaskId);\nvoid SEGGER_SYSVIEW_OnTaskStartExec               (U32 TaskId);\nvoid SEGGER_SYSVIEW_OnTaskStopExec                (void);\nvoid SEGGER_SYSVIEW_OnTaskStartReady              (U32 TaskId);\nvoid SEGGER_SYSVIEW_OnTaskStopReady               (U32 TaskId, unsigned int Cause);\nvoid SEGGER_SYSVIEW_MarkStart                     (unsigned int MarkerId);\nvoid SEGGER_SYSVIEW_MarkStop                      (unsigned int MarkerId);\nvoid SEGGER_SYSVIEW_Mark                          (unsigned int MarkerId);\nvoid SEGGER_SYSVIEW_NameMarker                    (unsigned int MarkerId, const char *sName);\n\nvoid SEGGER_SYSVIEW_HeapDefine                    (void *pHeap, void *pBase, unsigned int HeapSize, unsigned int MetadataSize);\nvoid SEGGER_SYSVIEW_HeapAlloc                     (void *pHeap, void *pUserData, unsigned int UserDataLen);\nvoid SEGGER_SYSVIEW_HeapAllocEx                   (void *pHeap, void *pUserData, unsigned int UserDataLen, unsigned int Tag);\nvoid SEGGER_SYSVIEW_HeapFree                      (void *pHeap, void *pUserData);\n\nvoid SEGGER_SYSVIEW_NameResource                  (U32 ResourceId, const char *sName);\nvoid SEGGER_SYSVIEW_RegisterData                  ( SEGGER_SYSVIEW_DATA_REGISTER *pInfo);\n\nint  SEGGER_SYSVIEW_SendPacket                    (U8 *pPacket, U8 *pPayloadEnd, unsigned int EventId);\n\n/*********************************************************************\n*\n*       Event parameter encoding functions\n*/\nU8  *SEGGER_SYSVIEW_EncodeU32                     (U8 *pPayload, U32 Value);\nU8  *SEGGER_SYSVIEW_EncodeData                    (U8 *pPayload, const char *pSrc, unsigned int Len);\nU8  *SEGGER_SYSVIEW_EncodeString                  (U8 *pPayload, const char *s, unsigned int MaxLen);\nU8  *SEGGER_SYSVIEW_EncodeId                      (U8 *pPayload, U32 Id);\nU32  SEGGER_SYSVIEW_ShrinkId                      (U32 Id);\n\n\n/*********************************************************************\n*\n*       Middleware module registration\n*/\nvoid SEGGER_SYSVIEW_RegisterModule                (SEGGER_SYSVIEW_MODULE *pModule);\nvoid SEGGER_SYSVIEW_RecordModuleDescription       (const SEGGER_SYSVIEW_MODULE *pModule, const char *sDescription);\nvoid SEGGER_SYSVIEW_SendModule                    (U8 ModuleId);\nvoid SEGGER_SYSVIEW_SendModuleDescription         (void);\nvoid SEGGER_SYSVIEW_SendNumModules                (void);\n\n/*********************************************************************\n*\n*       printf-Style functions\n*/\n#ifndef SEGGER_SYSVIEW_EXCLUDE_PRINTF // Define in project to avoid warnings about variable parameter list\nvoid SEGGER_SYSVIEW_PrintfHostEx                  (const char *s, U32 Options, ...);\nvoid SEGGER_SYSVIEW_VPrintfHostEx                 (const char *s, U32 Options, va_list *pParamList);\nvoid SEGGER_SYSVIEW_PrintfTargetEx                (const char *s, U32 Options, ...);\nvoid SEGGER_SYSVIEW_VPrintfTargetEx               (const char *s, U32 Options, va_list *pParamList);\nvoid SEGGER_SYSVIEW_PrintfHost                    (const char *s, ...);\nvoid SEGGER_SYSVIEW_VPrintfHost                   (const char *s, va_list *pParamList);\nvoid SEGGER_SYSVIEW_PrintfTarget                  (const char *s, ...);\nvoid SEGGER_SYSVIEW_VPrintfTarget                 (const char *s, va_list *pParamList);\nvoid SEGGER_SYSVIEW_WarnfHost                     (const char *s, ...);\nvoid SEGGER_SYSVIEW_VWarnfHost                    (const char *s, va_list *pParamList);\nvoid SEGGER_SYSVIEW_WarnfTarget                   (const char *s, ...);\nvoid SEGGER_SYSVIEW_VWarnfTarget                  (const char *s, va_list *pParamList);\nvoid SEGGER_SYSVIEW_ErrorfHost                    (const char *s, ...);\nvoid SEGGER_SYSVIEW_VErrorfHost                   (const char *s, va_list *pParamList);\nvoid SEGGER_SYSVIEW_ErrorfTarget                  (const char *s, ...);\nvoid SEGGER_SYSVIEW_VErrorfTarget                 (const char *s, va_list *pParamList);\n#endif\n\nvoid SEGGER_SYSVIEW_Print                         (const char *s);\nvoid SEGGER_SYSVIEW_Warn                          (const char *s);\nvoid SEGGER_SYSVIEW_Error                         (const char *s);\n\n/*********************************************************************\n*\n*       Run-time configuration functions\n*/\nvoid SEGGER_SYSVIEW_EnableEvents                  (U32 EnableMask);\nvoid SEGGER_SYSVIEW_DisableEvents                 (U32 DisableMask);\n\n/*********************************************************************\n*\n*       Application-provided functions\n*/\nvoid SEGGER_SYSVIEW_Conf                          (void);\nU32  SEGGER_SYSVIEW_X_GetTimestamp                (void);\nU32  SEGGER_SYSVIEW_X_GetInterruptId              (void);\n\nvoid SEGGER_SYSVIEW_X_StartComm                   (void);\nvoid SEGGER_SYSVIEW_X_OnEventRecorded             (unsigned NumBytes);\n\n/*********************************************************************\n*\n*       Espressif specific functions\n*/\nint SEGGER_SYSVIEW_ESP_SetEncoder(void *encoder);\nvoid *SEGGER_SYSVIEW_ESP_GetEncoder(void);\nint SEGGER_SYSVIEW_ESP_GetDestCpu(void);\n\n#ifdef __cplusplus\n}\n#endif\n\n/*********************************************************************\n*\n*       Compatibility API defines\n*/\n#define SEGGER_SYSVIEW_OnUserStart      SEGGER_SYSVIEW_MarkStart\n#define SEGGER_SYSVIEW_OnUserStop       SEGGER_SYSVIEW_MarkStop\n\n#endif\n\n/*************************** End of file ****************************/\n"
  },
  {
    "path": "esp_sysview/src/SEGGER/SEGGER_SYSVIEW_ConfDefaults.h",
    "content": "/*\n * SPDX-FileCopyrightText: 1995-2021 SEGGER Microcontroller GmbH\n *\n * SPDX-License-Identifier: BSD-1-Clause\n *\n * SPDX-FileContributor: 2023-2024 Espressif Systems (Shanghai) CO LTD\n */\n/*********************************************************************\n*                    SEGGER Microcontroller GmbH                     *\n*                        The Embedded Experts                        *\n**********************************************************************\n*                                                                    *\n*            (c) 1995 - 2024 SEGGER Microcontroller GmbH             *\n*                                                                    *\n*       www.segger.com     Support: support@segger.com               *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SEGGER SystemView * Real-time application analysis           *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n* All rights reserved.                                               *\n*                                                                    *\n* SEGGER strongly recommends to not make any changes                 *\n* to or modify the source code of this software in order to stay     *\n* compatible with the SystemView and RTT protocol, and J-Link.       *\n*                                                                    *\n* Redistribution and use in source and binary forms, with or         *\n* without modification, are permitted provided that the following    *\n* condition is met:                                                  *\n*                                                                    *\n* o Redistributions of source code must retain the above copyright   *\n*   notice, this condition and the following disclaimer.             *\n*                                                                    *\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             *\n* CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,        *\n* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           *\n* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           *\n* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *\n* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR           *\n* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  *\n* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;    *\n* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF      *\n* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT          *\n* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE  *\n* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *\n* DAMAGE.                                                            *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SystemView version: 3.56                                    *\n*                                                                    *\n**********************************************************************\n-------------------------- END-OF-HEADER -----------------------------\nFile    : SEGGER_SYSVIEW_ConfDefaults.h\nPurpose : Defines defaults for configurable defines used in\n          SEGGER SystemView.\nRevision: $Rev: 26230 $\n*/\n\n#ifndef SEGGER_SYSVIEW_CONFDEFAULTS_H\n#define SEGGER_SYSVIEW_CONFDEFAULTS_H\n\n/*********************************************************************\n*\n*       #include Section\n*\n**********************************************************************\n*/\n\n#include \"SEGGER_SYSVIEW_Conf.h\"\n#include \"SEGGER_RTT_Conf.h\"\n\n#include \"esp_assert.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*********************************************************************\n*\n*       Defines, fixed\n*\n**********************************************************************\n*/\n//\n// Use auto-detection for SEGGER_SYSVIEW_CORE define\n// based on compiler-/toolchain-specific defines\n// to define SEGGER_SYSVIEW_GET_INTERRUPT_ID and SEGGER_SYSVIEW_GET_TIMESTAMP\n//\n#define SEGGER_SYSVIEW_CORE_OTHER   0\n#define SEGGER_SYSVIEW_CORE_CM0     1 // Cortex-M0/M0+/M1\n#define SEGGER_SYSVIEW_CORE_CM3     2 // Cortex-M3/M4/M7\n#define SEGGER_SYSVIEW_CORE_RX      3 // Renesas RX\n#ifndef SEGGER_SYSVIEW_CORE\n#if (defined __SES_ARM) || (defined __CROSSWORKS_ARM) || (defined __SEGGER_CC__) || (defined __GNUC__) || (defined __clang__)\n#if (defined __ARM_ARCH_6M__) || (defined __ARM_ARCH_8M_BASE__)\n#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM0\n#elif (defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__))\n#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM3\n#endif\n#elif defined(__ICCARM__)\n#if (defined (__ARM6M__)          && (__CORE__ == __ARM6M__))          \\\n     || (defined (__ARM8M_BASELINE__) && (__CORE__ == __ARM8M_BASELINE__))\n#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM0\n#elif (defined (__ARM7EM__)         && (__CORE__ == __ARM7EM__))         \\\n       || (defined (__ARM7M__)          && (__CORE__ == __ARM7M__))          \\\n       || (defined (__ARM8M_MAINLINE__) && (__CORE__ == __ARM8M_MAINLINE__)) \\\n       || (defined (__ARM8M_MAINLINE__) && (__CORE__ == __ARM8M_MAINLINE__))\n#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM3\n#endif\n#elif defined(__CC_ARM)\n#if (defined(__TARGET_ARCH_6S_M))\n#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM0\n#elif (defined(__TARGET_ARCH_7_M) || defined(__TARGET_ARCH_7E_M))\n#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM3\n#endif\n#elif defined(__TI_ARM__)\n#ifdef __TI_ARM_V6M0__\n#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM0\n#elif (defined(__TI_ARM_V7M3__) || defined(__TI_ARM_V7M4__))\n#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM3\n#endif\n#elif defined(__ICCRX__)\n#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_RX\n#elif defined(__RX)\n#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_RX\n#endif\n\n#ifndef   SEGGER_SYSVIEW_CORE\n#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_OTHER\n#endif\n#endif\n\n\n/*********************************************************************\n*\n*       Defines, defaults\n*\n**********************************************************************\n*/\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_APP_NAME\n*\n*  Description\n*    The application name to be displayed in SystemView.\n*  Default\n*    \"SystemView-enabled Application\"\n*  Notes\n*    Convenience define to be used for SEGGER_SYSVIEW_SendSysDesc().\n*/\n#ifndef   SEGGER_SYSVIEW_APP_NAME\n#define SEGGER_SYSVIEW_APP_NAME                 \"SystemView-enabled Application\"\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_DEVICE_NAME\n*\n*  Description\n*    The target device name to be displayed in SystemView.\n*  Default\n*    \"undefined device\"\n*  Notes\n*    Convenience define to be used for SEGGER_SYSVIEW_SendSysDesc().\n*/\n#ifndef   SEGGER_SYSVIEW_DEVICE_NAME\n#define SEGGER_SYSVIEW_DEVICE_NAME              \"undefined device\"\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_GET_INTERRUPT_ID()\n*\n*  Description\n*    Function macro to retrieve the Id of the currently active\n*    interrupt.\n*  Default\n*    Call user-supplied function SEGGER_SYSVIEW_X_GetInterruptId().\n*  Notes\n*    For some known compilers and cores, a ready-to-use, core-specific\n*    default is set.\n*    ARMv7M: Read ICSR[8:0] (active vector)\n*    ARMv6M: Read ICSR[5:0] (active vector)\n*/\n#ifndef SEGGER_SYSVIEW_GET_INTERRUPT_ID\n#if SEGGER_SYSVIEW_CORE == SEGGER_SYSVIEW_CORE_CM3\n#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)\n#elif SEGGER_SYSVIEW_CORE == SEGGER_SYSVIEW_CORE_CM0\n#if defined(__ICCARM__)\n#if (__VER__ > 6010000)\n#define SEGGER_SYSVIEW_GET_INTERRUPT_ID() (__get_IPSR())                          // Workaround for IAR, which might do a byte-access to 0xE000ED04. Read IPSR instead.\n#else\n#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.\n#endif\n#else\n#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)\n#endif\n#else\n#define SEGGER_SYSVIEW_GET_INTERRUPT_ID()     SEGGER_SYSVIEW_X_GetInterruptId()       // Get the currently active interrupt Id from the user-provided function.\n#endif\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_GET_TIMESTAMP()\n*\n*  Description\n*    Function macro to retrieve a system timestamp for SYSVIEW events.\n*  Default\n*    Call user-supplied function SEGGER_SYSVIEW_X_GetTimestamp().\n*  Notes\n*    For some known compilers and cores, a ready-to-use, core-specific\n*    default is set.\n*    ARMv7M: Read Cortex-M Cycle Count register.\n*\n*    The system timestamp clock frequency has to be passed in\n*    SEGGER_SYSVIEW_Init().\n*/\n#ifndef SEGGER_SYSVIEW_GET_TIMESTAMP\n#if defined (SEGGER_SYSVIEW_CORE) && (SEGGER_SYSVIEW_CORE == SEGGER_SYSVIEW_CORE_CM3)\n#define SEGGER_SYSVIEW_GET_TIMESTAMP()        (*(U32 *)(0xE0001004))                  // Retrieve a system timestamp. Cortex-M cycle counter.\n#else\n#define SEGGER_SYSVIEW_GET_TIMESTAMP()        SEGGER_SYSVIEW_X_GetTimestamp()         // Retrieve a system timestamp via user-defined function\n#endif\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_TIMESTAMP_BITS\n*\n*  Description\n*    Number of valid (low-order) bits delivered in system timestamp.\n*  Default\n*    32\n*  Notes\n*    Value has to match system timestamp clock source.\n*/\n// Define number of valid bits low-order delivered by clock source.\n#ifndef   SEGGER_SYSVIEW_TIMESTAMP_BITS\n#define SEGGER_SYSVIEW_TIMESTAMP_BITS           32\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_RTT_CHANNEL\n*\n*  Description\n*    The RTT channel that SystemView will use.\n*  Default\n*    0: Auto selection.\n*  Notes\n*    Value has to be lower than SEGGER_RTT_MAX_NUM_UP_BUFFERS.\n*/\n#ifndef   SEGGER_SYSVIEW_RTT_CHANNEL\n#define SEGGER_SYSVIEW_RTT_CHANNEL              1\n#endif\n// Sanity check of RTT channel\n#if (SEGGER_SYSVIEW_RTT_CHANNEL == 0) && (SEGGER_RTT_MAX_NUM_UP_BUFFERS < 2)\n#error \"SEGGER_RTT_MAX_NUM_UP_BUFFERS in SEGGER_RTT_Conf.h has to be > 1!\"\n#elif (SEGGER_SYSVIEW_RTT_CHANNEL >= SEGGER_RTT_MAX_NUM_UP_BUFFERS)\n#error \"SEGGER_RTT_MAX_NUM_UP_BUFFERS  in SEGGER_RTT_Conf.h has to be > SEGGER_SYSVIEW_RTT_CHANNEL!\"\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_RTT_BUFFER_SIZE\n*\n*  Description\n*    Number of bytes that SystemView uses for the RTT buffer.\n*  Default\n*    1024\n*/\n#ifndef   SEGGER_SYSVIEW_RTT_BUFFER_SIZE\n#define SEGGER_SYSVIEW_RTT_BUFFER_SIZE          1024\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_SECTION\n*\n*  Description\n*    Section to place the SystemView RTT Buffer into.\n*  Default\n*    undefined: Do not place into a specific section.\n*  Notes\n*    If SEGGER_RTT_SECTION is defined, the default changes to use\n*    this section for the SystemView RTT Buffer, too.\n*/\n#if !(defined SEGGER_SYSVIEW_SECTION) && (defined SEGGER_RTT_SECTION)\n#define SEGGER_SYSVIEW_SECTION                  SEGGER_RTT_SECTION\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE\n*\n*  Description\n*    Largest cache line size (in bytes) in the target system.\n*  Default\n*    0\n*  Notes\n*    Required in systems with caches to make sure that the SystemView\n*    RTT buffer can be aligned accordingly.\n*/\n#ifndef SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE\n#define SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE      0\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_ID_BASE\n*\n*  Description\n*    Lowest Id reported by the application.\n*  Default\n*    0\n*  Notes\n*    Value is usually subtracted from mailboxes, semaphores, tasks,\n*    .... addresses, to compress event parameters.\n*    Should be the lowest RAM address of the system.\n*/\n#ifndef   SEGGER_SYSVIEW_ID_BASE\n#define SEGGER_SYSVIEW_ID_BASE                  0\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_ID_SHIFT\n*\n*  Description\n*    Number of bits to shift Ids.\n*  Default\n*    0\n*  Notes\n*    Ids are shifted to compress event parameters.\n*    Should match the alignment of Ids (addresses),\n*    e.g. 2 when Ids are 4 byte aligned.\n*/\n#ifndef   SEGGER_SYSVIEW_ID_SHIFT\n#define SEGGER_SYSVIEW_ID_SHIFT                 0\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_MAX_ARGUMENTS\n*\n*  Description\n*    Maximum number of arguments which are handled with SystemView\n*    print routines or may be encoded in one recording function.\n*    routines.\n*  Default\n*    16\n*/\n#ifndef   SEGGER_SYSVIEW_MAX_ARGUMENTS\n#define SEGGER_SYSVIEW_MAX_ARGUMENTS            16\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_MAX_STRING_LEN\n*\n*  Description\n*    Maximum string length which can be used in SystemView print and\n*    system description routines.\n*  Default\n*    128\n*/\n#ifndef   SEGGER_SYSVIEW_MAX_STRING_LEN\n#define SEGGER_SYSVIEW_MAX_STRING_LEN           128\n#endif\n\nESP_STATIC_ASSERT(SEGGER_SYSVIEW_MAX_STRING_LEN < 255, \"SEGGER Sysview string length must be less than 255.\");\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_SUPPORT_LONG_ID\n*\n*  Description\n*    It set, support encoding Evend Ids longer than 14 bit.\n*  Default\n*    1\n*/\n#ifndef   SEGGER_SYSVIEW_SUPPORT_LONG_ID\n#define SEGGER_SYSVIEW_SUPPORT_LONG_ID          1\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_SUPPORT_LONG_DATA\n*\n*  Description\n*    It set, support encoding event data longer than 14 bit.\n*  Default\n*    0\n*/\n#ifndef   SEGGER_SYSVIEW_SUPPORT_LONG_DATA\n#define SEGGER_SYSVIEW_SUPPORT_LONG_DATA        0\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT\n*\n*  Description\n*    If enabled, on SEGGER_SYSVIEW_PrintHost, check the format string\n*    and if it includes unsupported formatters, use formatting on the\n*    target instead.\n*  Default\n*    0: Disabled.\n*/\n#ifndef   SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT\n#define SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT   0\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_USE_INTERNAL_RECORDER\n*\n*  Description\n*    If set, an internal recorder, such as UART or IP is used.\n*  Default\n*    0: Disabled.\n*  Notes\n*    Convenience define to be used by SEGGER_SYSVIEW_Conf(),\n*    such as in embOS configuration to enable Cortex-M cycle counter.\n*/\n#ifndef   SEGGER_SYSVIEW_USE_INTERNAL_RECORDER\n#define SEGGER_SYSVIEW_USE_INTERNAL_RECORDER    0\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_CAN_RESTART\n*\n*  Description\n*    If enabled, send the SystemView start sequence on every start\n*    command, not just on the first one.\n*    Enables restart when SystemView disconnected unexpectedly.\n*  Default\n*    1: Enabled\n*/\n#ifndef   SEGGER_SYSVIEW_CAN_RESTART\n#define SEGGER_SYSVIEW_CAN_RESTART              1\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_START_ON_INIT\n*\n*  Description\n*    Enable calling SEGGER_SYSVIEW_Start() after initialization.\n*  Default\n*    0: Disabled.\n*  Notes\n*    Convenience define to be used by SEGGER_SYSVIEW_Conf(),\n*    such as in embOS configuration.\n*/\n#ifndef   SEGGER_SYSVIEW_START_ON_INIT\n#define SEGGER_SYSVIEW_START_ON_INIT            0\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_USE_STATIC_BUFFER\n*\n*  Description\n*    If enabled, use a static buffer instead of a buffer on the stack\n*    for SystemView event packets.\n*  Default\n*    1: Enabled.\n*  Notes\n*    If enabled, the static memory use by SystemView is increased by\n*    the maximum packet size. SystemView is locked on entry of a\n*    recording function.\n*    If disabled, the stack usage by SystemView recording functions\n*    might be increased by up to the maximum packet size. SystemView\n*    is locked when writing the packet to the RTT buffer.\n*/\n#ifndef   SEGGER_SYSVIEW_USE_STATIC_BUFFER\n#define SEGGER_SYSVIEW_USE_STATIC_BUFFER        1\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_MAX_PACKET_SIZE\n*\n*  Description\n*    Maximum packet size for a SystemView event.\n*  Default\n*    Automatically calculated.\n*  Notes\n*    The maximum packet size is mainly defined by the maximum string\n*    length and the maximum number of arguments.\n*/\n#ifndef   SEGGER_SYSVIEW_MAX_PACKET_SIZE\n#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)\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_POST_MORTEM_MODE\n*\n*  Description\n*    If enabled, SystemView records for post-mortem analysis instead\n*    of real-time analysis.\n*  Default\n*    0: Disabled.\n*  Notes\n*    For more information refer to\n*    https://www.segger.com/products/development-tools/systemview/technology/post-mortem-mode\n*/\n#ifndef   SEGGER_SYSVIEW_POST_MORTEM_MODE\n#define SEGGER_SYSVIEW_POST_MORTEM_MODE         0\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_SYNC_PERIOD_SHIFT\n*\n*  Description\n*    Configure how frequently synchronization is sent in post-mortem\n*    mode.\n*  Default\n*    8: (1 << 8) = Every 256 Events.\n*  Notes\n*    In post-mortem mode, at least one sync has to be in the RTT buffer.\n*    Recommended sync frequency: Buffer Size / 16\n*    For more information refer to\n*    https://www.segger.com/products/development-tools/systemview/technology/post-mortem-mode\n*/\n#ifndef   SEGGER_SYSVIEW_SYNC_PERIOD_SHIFT\n#define SEGGER_SYSVIEW_SYNC_PERIOD_SHIFT        8\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_ON_EVENT_RECORDED()\n*\n*  Description\n*    Function macro to notify recorder about a new event in buffer.\n*  Default\n*    undefined: Do not notify recorder.\n*  Notes\n*    Used for non-J-Link recorder,\n*    such as to enable transmission via UART or notify IP task.\n*/\n#ifndef   SEGGER_SYSVIEW_ON_EVENT_RECORDED\n#define SEGGER_SYSVIEW_ON_EVENT_RECORDED(NumBytes)\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_LOCK()\n*\n*  Description\n*    Function macro to (nestable) lock SystemView recording.\n*  Default\n*    Use RTT Locking mechanism (defined by SEGGER_RTT_LOCK()).\n*  Notes\n*    If SystemView recording is not locked, recording events from\n*    interrupts and tasks may lead to unpredictable, undefined, event\n*    data.\n*/\n#ifndef   SEGGER_SYSVIEW_LOCK\nunsigned SEGGER_SYSVIEW_X_SysView_Lock(void);\n#define SEGGER_SYSVIEW_LOCK()                   unsigned _SYSVIEW_int_state = SEGGER_SYSVIEW_X_SysView_Lock()\n#endif\n\n/*********************************************************************\n*\n*       Define: SEGGER_SYSVIEW_UNLOCK\n*\n*  Description\n*    Function macro to unlock SystemView recording.\n*  Default\n*    Use RTT Unlocking mechanism (defined by SEGGER_RTT_UNLOCK()).\n*/\n#ifndef   SEGGER_SYSVIEW_UNLOCK\nvoid SEGGER_SYSVIEW_X_SysView_Unlock(unsigned int_state);\n#define SEGGER_SYSVIEW_UNLOCK()                 SEGGER_SYSVIEW_X_SysView_Unlock(_SYSVIEW_int_state)\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n\n/*************************** End of file ****************************/\n"
  },
  {
    "path": "esp_sysview/src/SEGGER/SEGGER_SYSVIEW_Int.h",
    "content": "/*\n * SPDX-FileCopyrightText: 1995-2021 SEGGER Microcontroller GmbH\n *\n * SPDX-License-Identifier: BSD-1-Clause\n */\n/*********************************************************************\n*                    SEGGER Microcontroller GmbH                     *\n*                        The Embedded Experts                        *\n**********************************************************************\n*                                                                    *\n*            (c) 1995 - 2024 SEGGER Microcontroller GmbH             *\n*                                                                    *\n*       www.segger.com     Support: support@segger.com               *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SEGGER SystemView * Real-time application analysis           *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n* All rights reserved.                                               *\n*                                                                    *\n* SEGGER strongly recommends to not make any changes                 *\n* to or modify the source code of this software in order to stay     *\n* compatible with the SystemView and RTT protocol, and J-Link.       *\n*                                                                    *\n* Redistribution and use in source and binary forms, with or         *\n* without modification, are permitted provided that the following    *\n* condition is met:                                                  *\n*                                                                    *\n* o Redistributions of source code must retain the above copyright   *\n*   notice, this condition and the following disclaimer.             *\n*                                                                    *\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             *\n* CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,        *\n* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           *\n* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           *\n* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *\n* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR           *\n* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  *\n* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;    *\n* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF      *\n* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT          *\n* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE  *\n* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *\n* DAMAGE.                                                            *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SystemView version: 3.56                                    *\n*                                                                    *\n**********************************************************************\n-------------------------- END-OF-HEADER -----------------------------\nFile    : SEGGER_SYSVIEW_Int.h\nPurpose : SEGGER SystemView internal header.\nRevision: $Rev: 21281 $\n*/\n\n#ifndef SEGGER_SYSVIEW_INT_H\n#define SEGGER_SYSVIEW_INT_H\n\n/*********************************************************************\n*\n*       #include Section\n*\n**********************************************************************\n*/\n\n#include \"SEGGER_SYSVIEW.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n/*********************************************************************\n*\n*       Private data types\n*\n**********************************************************************\n*/\n//\n// Commands that Host can send to target\n//\ntypedef enum {\n    SEGGER_SYSVIEW_COMMAND_ID_START = 1,\n    SEGGER_SYSVIEW_COMMAND_ID_STOP,\n    SEGGER_SYSVIEW_COMMAND_ID_GET_SYSTIME,\n    SEGGER_SYSVIEW_COMMAND_ID_GET_TASKLIST,\n    SEGGER_SYSVIEW_COMMAND_ID_GET_SYSDESC,\n    SEGGER_SYSVIEW_COMMAND_ID_GET_NUMMODULES,\n    SEGGER_SYSVIEW_COMMAND_ID_GET_MODULEDESC,\n    SEGGER_SYSVIEW_COMMAND_ID_HEARTBEAT = 127,\n    // Extended commands: Commands >= 128 have a second parameter\n    SEGGER_SYSVIEW_COMMAND_ID_GET_MODULE = 128\n} SEGGER_SYSVIEW_COMMAND_ID;\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n\n/*************************** End of file ****************************/\n"
  },
  {
    "path": "esp_sysview/src/Sample/FreeRTOSV10.4/Config/esp/SEGGER_SYSVIEW_Config_FreeRTOS.c",
    "content": "/*\n * SPDX-FileCopyrightText: 1995-2021 SEGGER Microcontroller GmbH\n *\n * SPDX-License-Identifier: BSD-1-Clause\n *\n * SPDX-FileContributor: 2017-2025 Espressif Systems (Shanghai) CO LTD\n */\n/*********************************************************************\n*                    SEGGER Microcontroller GmbH                     *\n*                        The Embedded Experts                        *\n**********************************************************************\n*                                                                    *\n*            (c) 1995 - 2021 SEGGER Microcontroller GmbH             *\n*                                                                    *\n*       www.segger.com     Support: support@segger.com               *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SEGGER SystemView * Real-time application analysis           *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n* All rights reserved.                                               *\n*                                                                    *\n* SEGGER strongly recommends to not make any changes                 *\n* to or modify the source code of this software in order to stay     *\n* compatible with the SystemView and RTT protocol, and J-Link.       *\n*                                                                    *\n* Redistribution and use in source and binary forms, with or         *\n* without modification, are permitted provided that the following    *\n* condition is met:                                                  *\n*                                                                    *\n* o Redistributions of source code must retain the above copyright   *\n*   notice, this condition and the following disclaimer.             *\n*                                                                    *\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             *\n* CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,        *\n* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           *\n* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           *\n* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *\n* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR           *\n* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  *\n* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;    *\n* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF      *\n* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT          *\n* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE  *\n* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *\n* DAMAGE.                                                            *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SystemView version: 3.42                                    *\n*                                                                    *\n**********************************************************************\n-------------------------- END-OF-HEADER -----------------------------\n\nFile    : SEGGER_SYSVIEW_Config_FreeRTOS.c\nPurpose : Sample setup configuration of SystemView with FreeRTOS.\nRevision: $Rev: 7745 $\n*/\n#include <string.h>\n#include \"sdkconfig.h\"\n#include \"freertos/FreeRTOS.h\"\n#include \"SEGGER_SYSVIEW.h\"\n#include \"esp_intr_alloc.h\"\n#include \"soc/soc.h\"\n#include \"soc/interrupts.h\"\n#include \"esp_trace_port_encoder.h\"\n#include \"esp_trace_port_transport.h\"\n#include \"esp_trace_util.h\"\n\nextern const SEGGER_SYSVIEW_OS_API SYSVIEW_X_OS_TraceAPI;\n\n/*********************************************************************\n*\n*       Defines, configurable\n*\n**********************************************************************\n*/\n// The application name to be displayed in SystemViewer\n#define SYSVIEW_APP_NAME        \"FreeRTOS Application\"\n\n// The target device name\n#define SYSVIEW_DEVICE_NAME     CONFIG_IDF_TARGET\n// The target core name\n#define SYSVIEW_CORE_NAME       \"core0\" // In dual core, this will be renamed by OpenOCD as core1\n\n// The lowest RAM address used for IDs (pointers)\n#define SYSVIEW_RAM_BASE        (SOC_DROM_LOW)\n\n#ifdef CONFIG_FREERTOS_TICK_SUPPORT_CORETIMER\n#if CONFIG_FREERTOS_CORETIMER_0\n#define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER0_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)\n#endif\n#if CONFIG_FREERTOS_CORETIMER_1\n#define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER1_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)\n#endif\n\n#elif CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER\n#define SYSTICK_INTR_ID (ETS_SYSTIMER_TARGET0_INTR_SOURCE)\n#endif // CONFIG_FREERTOS_TICK_SUPPORT_CORETIMER\n\n// SystemView is single core specific: it implies that SEGGER_SYSVIEW_LOCK()\n// disables IRQs (disables rescheduling globally). So we can not use finite timeouts for locks and return error\n// in case of expiration, because error will not be handled and SEGGER's code will go further implying that\n// everything is fine, so for multi-core env we have to wait on underlying lock forever\n#define SEGGER_LOCK_WAIT_TMO  ESP_TRACE_TMO_INFINITE\n\n/*********************************************************************\n*\n*       _cbSendSystemDesc()\n*\n*  Function description\n*    Sends SystemView description strings.\n*/\nstatic void _cbSendSystemDesc(void)\n{\n    char irq_str[32] = \"I#\";\n    SEGGER_SYSVIEW_SendSysDesc(\"N=\"SYSVIEW_APP_NAME\",D=\"SYSVIEW_DEVICE_NAME\",C=\"SYSVIEW_CORE_NAME\",O=FreeRTOS\");\n    strcat(itoa(SYSTICK_INTR_ID, irq_str + 2, 10), \"=SysTick\");\n    SEGGER_SYSVIEW_SendSysDesc(irq_str);\n    size_t isr_count = sizeof(esp_isr_names) / sizeof(esp_isr_names[0]);\n    for (size_t i = 0; i < isr_count; ++i) {\n        if (esp_isr_names[i] == NULL || (ETS_INTERNAL_INTR_SOURCE_OFF + i) == SYSTICK_INTR_ID) {\n            continue;\n        }\n        strcat(itoa(ETS_INTERNAL_INTR_SOURCE_OFF + i, irq_str + 2, 10), \"=\");\n        strncat(irq_str, esp_isr_names[i], sizeof(irq_str) - strlen(irq_str) - 1);\n        SEGGER_SYSVIEW_SendSysDesc(irq_str);\n    }\n}\n\n/*********************************************************************\n*\n*       Global functions\n*\n**********************************************************************\n*/\nvoid SEGGER_SYSVIEW_Conf(void)\n{\n    U32 disable_evts = 0;\n\n    int timestamp_freq = esp_trace_timestamp_init();\n    SEGGER_SYSVIEW_Init(timestamp_freq, esp_trace_cpu_freq_get(),\n                        &SYSVIEW_X_OS_TraceAPI, _cbSendSystemDesc);\n    SEGGER_SYSVIEW_SetRAMBase(SYSVIEW_RAM_BASE);\n\n#if !CONFIG_SEGGER_SYSVIEW_EVT_OVERFLOW_ENABLE\n    disable_evts |= SYSVIEW_EVTMASK_OVERFLOW;\n#endif\n#if !CONFIG_SEGGER_SYSVIEW_EVT_ISR_ENTER_ENABLE\n    disable_evts |= SYSVIEW_EVTMASK_ISR_ENTER;\n#endif\n#if !CONFIG_SEGGER_SYSVIEW_EVT_ISR_EXIT_ENABLE\n    disable_evts |= SYSVIEW_EVTMASK_ISR_EXIT;\n#endif\n#if !CONFIG_SEGGER_SYSVIEW_EVT_TASK_START_EXEC_ENABLE\n    disable_evts |= SYSVIEW_EVTMASK_TASK_START_EXEC;\n#endif\n#if !CONFIG_SEGGER_SYSVIEW_EVT_TASK_STOP_EXEC_ENABLE\n    disable_evts |= SYSVIEW_EVTMASK_TASK_STOP_EXEC;\n#endif\n#if !CONFIG_SEGGER_SYSVIEW_EVT_TASK_START_READY_ENABLE\n    disable_evts |= SYSVIEW_EVTMASK_TASK_START_READY;\n#endif\n#if !CONFIG_SEGGER_SYSVIEW_EVT_TASK_STOP_READY_ENABLE\n    disable_evts |= SYSVIEW_EVTMASK_TASK_STOP_READY;\n#endif\n#if !CONFIG_SEGGER_SYSVIEW_EVT_TASK_CREATE_ENABLE\n    disable_evts |= SYSVIEW_EVTMASK_TASK_CREATE;\n#endif\n#if !CONFIG_SEGGER_SYSVIEW_EVT_TASK_TERMINATE_ENABLE\n    disable_evts |= SYSVIEW_EVTMASK_TASK_TERMINATE;\n#endif\n#if !CONFIG_SEGGER_SYSVIEW_EVT_IDLE_ENABLE\n    disable_evts |= SYSVIEW_EVTMASK_IDLE;\n#endif\n#if !CONFIG_SEGGER_SYSVIEW_EVT_ISR_TO_SCHED_ENABLE\n    disable_evts |= SYSVIEW_EVTMASK_ISR_TO_SCHEDULER;\n#endif\n#if !CONFIG_SEGGER_SYSVIEW_EVT_TIMER_ENTER_ENABLE\n    disable_evts |= SYSVIEW_EVTMASK_TIMER_ENTER;\n#endif\n#if !CONFIG_SEGGER_SYSVIEW_EVT_TIMER_EXIT_ENABLE\n    disable_evts |= SYSVIEW_EVTMASK_TIMER_EXIT;\n#endif\n    SEGGER_SYSVIEW_DisableEvents(disable_evts);\n}\n\nU32 SEGGER_SYSVIEW_X_GetTimestamp(void)\n{\n    return esp_trace_timestamp_get();\n}\n\nvoid SEGGER_SYSVIEW_X_RTT_Lock(void)\n{\n}\n\nvoid SEGGER_SYSVIEW_X_RTT_Unlock(void)\n{\n}\n\nunsigned SEGGER_SYSVIEW_X_SysView_Lock(void)\n{\n    esp_trace_encoder_t *encoder = SEGGER_SYSVIEW_ESP_GetEncoder();\n    if (encoder) {\n        // Use encoder-level lock\n        return encoder->vt->take_lock(encoder, SEGGER_LOCK_WAIT_TMO);\n    }\n    return 0;\n}\n\nvoid SEGGER_SYSVIEW_X_SysView_Unlock(unsigned int_state)\n{\n    esp_trace_encoder_t *encoder = SEGGER_SYSVIEW_ESP_GetEncoder();\n    if (encoder) {\n        // Use encoder-level unlock\n        encoder->vt->give_lock(encoder, int_state);\n    }\n}\n\n/*************************** End of file ****************************/\n"
  },
  {
    "path": "esp_sysview/src/Sample/FreeRTOSV10.4/SEGGER_SYSVIEW_FreeRTOS.c",
    "content": "/*\n * SPDX-FileCopyrightText: 1995-2021 SEGGER Microcontroller GmbH\n *\n * SPDX-License-Identifier: BSD-1-Clause\n *\n * SPDX-FileContributor: 2023 Espressif Systems (Shanghai) CO LTD\n */\n/*********************************************************************\n*                    SEGGER Microcontroller GmbH                     *\n*                        The Embedded Experts                        *\n**********************************************************************\n*                                                                    *\n*            (c) 1995 - 2021 SEGGER Microcontroller GmbH             *\n*                                                                    *\n*       www.segger.com     Support: support@segger.com               *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SEGGER SystemView * Real-time application analysis           *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n* All rights reserved.                                               *\n*                                                                    *\n* SEGGER strongly recommends to not make any changes                 *\n* to or modify the source code of this software in order to stay     *\n* compatible with the SystemView and RTT protocol, and J-Link.       *\n*                                                                    *\n* Redistribution and use in source and binary forms, with or         *\n* without modification, are permitted provided that the following    *\n* condition is met:                                                  *\n*                                                                    *\n* o Redistributions of source code must retain the above copyright   *\n*   notice, this condition and the following disclaimer.             *\n*                                                                    *\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             *\n* CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,        *\n* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           *\n* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           *\n* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *\n* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR           *\n* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  *\n* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;    *\n* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF      *\n* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT          *\n* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE  *\n* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *\n* DAMAGE.                                                            *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SystemView version: 3.42                                    *\n*                                                                    *\n**********************************************************************\n-------------------------- END-OF-HEADER -----------------------------\n\nFile    : SEGGER_SYSVIEW_FreeRTOS.c\nPurpose : Interface between FreeRTOS and SystemView.\nRevision: $Rev: 7947 $\n*/\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"SEGGER_SYSVIEW.h\"\n#include \"SEGGER_SYSVIEW_FreeRTOS.h\"\n#include \"string.h\" // Required for memset\n\n\n\ntypedef struct SYSVIEW_FREERTOS_TASK_STATUS SYSVIEW_FREERTOS_TASK_STATUS;\n\nstruct SYSVIEW_FREERTOS_TASK_STATUS {\n    U32         xHandle;\n    const char *pcTaskName;\n    unsigned    uxCurrentPriority;\n    U32         pxStack;\n    unsigned    uStackHighWaterMark;\n};\n\nstatic SYSVIEW_FREERTOS_TASK_STATUS _aTasks[SYSVIEW_FREERTOS_MAX_NOF_TASKS];\nstatic unsigned _NumTasks;\n\n/*********************************************************************\n*\n*       _cbSendTaskList()\n*\n*  Function description\n*    This function is part of the link between FreeRTOS and SYSVIEW.\n*    Called from SystemView when asked by the host, it uses SYSVIEW\n*    functions to send the entire task list to the host.\n*/\nstatic void _cbSendTaskList(void)\n{\n    unsigned n;\n\n    for (n = 0; n < _NumTasks; n++) {\n#if INCLUDE_uxTaskGetStackHighWaterMark // Report Task Stack High Watermark\n        _aTasks[n].uStackHighWaterMark = uxTaskGetStackHighWaterMark((TaskHandle_t)_aTasks[n].xHandle);\n#endif\n        SYSVIEW_SendTaskInfo((U32)_aTasks[n].xHandle, _aTasks[n].pcTaskName, (unsigned)_aTasks[n].uxCurrentPriority, (U32)_aTasks[n].pxStack, (unsigned)_aTasks[n].uStackHighWaterMark);\n    }\n}\n\n/*********************************************************************\n*\n*       _cbGetTime()\n*\n*  Function description\n*    This function is part of the link between FreeRTOS and SYSVIEW.\n*    Called from SystemView when asked by the host, returns the\n*    current system time in micro seconds.\n*/\n__attribute__((unused)) static U64 _cbGetTime(void)\n{\n    U64 Time;\n\n    Time = xTaskGetTickCountFromISR();\n    Time *= portTICK_PERIOD_MS;\n    Time *= 1000;\n    return Time;\n}\n\n/*********************************************************************\n*\n*       Global functions\n*\n**********************************************************************\n*/\n/*********************************************************************\n*\n*       SYSVIEW_AddTask()\n*\n*  Function description\n*    Add a task to the internal list and record its information.\n*/\nvoid SYSVIEW_AddTask(U32 xHandle, const char *pcTaskName, unsigned uxCurrentPriority, U32  pxStack, unsigned uStackHighWaterMark)\n{\n\n    /* On multi-core we have several idle tasks with 'IDLEx' names\n       Not best solution, because we can filter out user tasks starting with 'IDLE'.\n       But we can not use 'xTaskGetIdleTaskHandle' because at the moment when this\n       function is called array of idle tasks handles are not initialized yet. */\n    if (memcmp(pcTaskName, \"IDLE\", 4) == 0) {\n        return;\n    }\n\n    if (_NumTasks >= SYSVIEW_FREERTOS_MAX_NOF_TASKS) {\n        SEGGER_SYSVIEW_Warn(\"SYSTEMVIEW: Could not record task information. Maximum number of tasks reached.\");\n        return;\n    }\n\n    _aTasks[_NumTasks].xHandle = xHandle;\n    _aTasks[_NumTasks].pcTaskName = pcTaskName;\n    _aTasks[_NumTasks].uxCurrentPriority = uxCurrentPriority;\n    _aTasks[_NumTasks].pxStack = pxStack;\n    _aTasks[_NumTasks].uStackHighWaterMark = uStackHighWaterMark;\n\n    _NumTasks++;\n\n    SYSVIEW_SendTaskInfo(xHandle, pcTaskName, uxCurrentPriority, pxStack, uStackHighWaterMark);\n\n}\n\n/*********************************************************************\n*\n*       SYSVIEW_UpdateTask()\n*\n*  Function description\n*    Update a task in the internal list and record its information.\n*/\nvoid SYSVIEW_UpdateTask(U32 xHandle, const char *pcTaskName, unsigned uxCurrentPriority, U32 pxStack, unsigned uStackHighWaterMark)\n{\n    unsigned n;\n\n    /* On multi-core we have several idle tasks with 'IDLEx' names\n       Not best solution, because we can filter out user tasks starting with 'IDLE'.\n       But we can not use 'xTaskGetIdleTaskHandle' because at the moment when this\n       function is called array of idle tasks handles are not initialized yet. */\n    if (memcmp(pcTaskName, \"IDLE\", 4) == 0) {\n        return;\n    }\n\n    for (n = 0; n < _NumTasks; n++) {\n        if (_aTasks[n].xHandle == xHandle) {\n            break;\n        }\n    }\n    if (n < _NumTasks) {\n        _aTasks[n].pcTaskName = pcTaskName;\n        _aTasks[n].uxCurrentPriority = uxCurrentPriority;\n        _aTasks[n].pxStack = pxStack;\n        _aTasks[n].uStackHighWaterMark = uStackHighWaterMark;\n\n        SYSVIEW_SendTaskInfo(xHandle, pcTaskName, uxCurrentPriority, pxStack, uStackHighWaterMark);\n    } else {\n        SYSVIEW_AddTask(xHandle, pcTaskName, uxCurrentPriority, pxStack, uStackHighWaterMark);\n    }\n}\n\n/*********************************************************************\n*\n*       SYSVIEW_DeleteTask()\n*\n*  Function description\n*    Delete a task from the internal list.\n*/\nvoid SYSVIEW_DeleteTask(U32 xHandle)\n{\n    unsigned n;\n\n    if (_NumTasks == 0) {\n        return; // Early out\n    }\n    for (n = 0; n < _NumTasks; n++) {\n        if (_aTasks[n].xHandle == xHandle) {\n            break;\n        }\n    }\n    if (n == (_NumTasks - 1)) {\n        //\n        // Task is last item in list.\n        // Simply zero the item and decrement number of tasks.\n        //\n        memset(&_aTasks[n], 0, sizeof(_aTasks[n]));\n        _NumTasks--;\n    } else if (n < _NumTasks) {\n        //\n        // Task is in the middle of the list.\n        // Move last item to current position and decrement number of tasks.\n        // Order of tasks does not really matter, so no need to move all following items.\n        //\n        _aTasks[n].xHandle             = _aTasks[_NumTasks - 1].xHandle;\n        _aTasks[n].pcTaskName          = _aTasks[_NumTasks - 1].pcTaskName;\n        _aTasks[n].uxCurrentPriority   = _aTasks[_NumTasks - 1].uxCurrentPriority;\n        _aTasks[n].pxStack             = _aTasks[_NumTasks - 1].pxStack;\n        _aTasks[n].uStackHighWaterMark = _aTasks[_NumTasks - 1].uStackHighWaterMark;\n        memset(&_aTasks[_NumTasks - 1], 0, sizeof(_aTasks[_NumTasks - 1]));\n        _NumTasks--;\n    }\n}\n\n/*********************************************************************\n*\n*       SYSVIEW_SendTaskInfo()\n*\n*  Function description\n*    Record task information.\n*/\nvoid SYSVIEW_SendTaskInfo(U32 TaskID, const char *sName, unsigned Prio, U32 StackBase, unsigned StackSize)\n{\n    SEGGER_SYSVIEW_TASKINFO TaskInfo;\n\n    memset(&TaskInfo, 0, sizeof(TaskInfo)); // Fill all elements with 0 to allow extending the structure in future version without breaking the code\n    TaskInfo.TaskID     = TaskID;\n    TaskInfo.sName      = sName;\n    TaskInfo.Prio       = Prio;\n    TaskInfo.StackBase  = StackBase;\n    TaskInfo.StackSize  = StackSize;\n    SEGGER_SYSVIEW_SendTaskInfo(&TaskInfo);\n}\n\n/*********************************************************************\n*\n*       Public API structures\n*\n**********************************************************************\n*/\n// Callbacks provided to SYSTEMVIEW by FreeRTOS\nconst SEGGER_SYSVIEW_OS_API SYSVIEW_X_OS_TraceAPI = {\n    /* Callback _cbGetTime locks xKernelLock inside xTaskGetTickCountFromISR, this can cause deadlock on multi-core.\n       To prevent deadlock, always lock xKernelLock before s_sys_view_lock. Omitting the callback here results in sending\n       SYSVIEW_EVTID_SYSTIME_CYCLES events instead of SYSVIEW_EVTID_SYSTIME_US */\n    NULL,\n    _cbSendTaskList,\n};\n\n/*************************** End of file ****************************/\n"
  },
  {
    "path": "esp_sysview/src/Sample/FreeRTOSV10.4/SEGGER_SYSVIEW_FreeRTOS.h",
    "content": "/*\n * SPDX-FileCopyrightText: 1995-2021 SEGGER Microcontroller GmbH\n *\n * SPDX-License-Identifier: BSD-1-Clause\n *\n * SPDX-FileContributor: 2023 Espressif Systems (Shanghai) CO LTD\n */\n/*********************************************************************\n*                    SEGGER Microcontroller GmbH                     *\n*                        The Embedded Experts                        *\n**********************************************************************\n*                                                                    *\n*            (c) 1995 - 2021 SEGGER Microcontroller GmbH             *\n*                                                                    *\n*       www.segger.com     Support: support@segger.com               *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SEGGER SystemView * Real-time application analysis           *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n* All rights reserved.                                               *\n*                                                                    *\n* SEGGER strongly recommends to not make any changes                 *\n* to or modify the source code of this software in order to stay     *\n* compatible with the SystemView and RTT protocol, and J-Link.       *\n*                                                                    *\n* Redistribution and use in source and binary forms, with or         *\n* without modification, are permitted provided that the following    *\n* condition is met:                                                  *\n*                                                                    *\n* o Redistributions of source code must retain the above copyright   *\n*   notice, this condition and the following disclaimer.             *\n*                                                                    *\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             *\n* CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,        *\n* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           *\n* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           *\n* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *\n* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR           *\n* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  *\n* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;    *\n* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF      *\n* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT          *\n* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE  *\n* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *\n* DAMAGE.                                                            *\n*                                                                    *\n**********************************************************************\n*                                                                    *\n*       SystemView version: 3.42                                    *\n*                                                                    *\n**********************************************************************\n-------------------------- END-OF-HEADER -----------------------------\n\nFile    : SEGGER_SYSVIEW_FreeRTOS.h\nPurpose : Interface between FreeRTOS and SystemView.\n          Tested with FreeRTOS V10.4.3\nRevision: $Rev: 7745 $\n\nNotes:\n  (1) Include this file at the end of FreeRTOSConfig.h\n*/\n\n#ifndef SYSVIEW_FREERTOS_H\n#define SYSVIEW_FREERTOS_H\n\n#include \"SEGGER_SYSVIEW.h\"\n\n/*********************************************************************\n*\n*       Defines, configurable\n*\n**********************************************************************\n*/\n\n#define SYSVIEW_FREERTOS_MAX_NOF_TASKS  CONFIG_SEGGER_SYSVIEW_MAX_TASKS\n\n/*********************************************************************\n*\n*       Defines, fixed\n*\n**********************************************************************\n*/\n// for dual-core targets we use event ID to keep core ID bit (0 or 1)\n// use the highest - 1 bit of event ID to indicate core ID\n// the highest bit can not be used due to event ID encoding method\n// this reduces supported ID range to [0..63] (for 1 byte IDs) plus [128..16383] (for 2 bytes IDs)\n// so original continuous event IDs range is split into two sub-ranges for 1-bytes IDs and 2-bytes ones\n\n// events which use apiFastID_OFFSET will have 1 byte ID,\n// so for the sake of bandwidth economy events which are generated more frequently should use this ID offset\n// currently all used events fall into this range\n#define apiFastID_OFFSET                          (32u)\n\n#define apiID_VTASKDELETE                         (1u)\n#define apiID_VTASKDELAY                          (2u)\n#define apiID_VTASKDELAYUNTIL                     (3u)\n#define apiID_VTASKSUSPEND                        (4u)\n#define apiID_ULTASKNOTIFYTAKE                    (5u)\n#define apiID_VTASKNOTIFYGIVEFROMISR              (6u)\n#define apiID_VTASKPRIORITYINHERIT                (7u)\n#define apiID_VTASKRESUME                         (8u)\n#define apiID_VTASKSTEPTICK                       (9u)\n#define apiID_XTASKPRIORITYDISINHERIT             (10u)\n#define apiID_XTASKRESUMEFROMISR                  (11u)\n#define apiID_XTASKGENERICNOTIFY                  (12u)\n#define apiID_XTASKGENERICNOTIFYFROMISR           (13u)\n#define apiID_XTASKNOTIFYWAIT                     (14u)\n#define apiID_XQUEUEGENERICCREATE                 (15u)\n#define apiID_VQUEUEDELETE                        (16u)\n#define apiID_XQUEUEGENERICRECEIVE                (17u)\n#define apiID_XQUEUEPEEKFROMISR                   (18u)\n#define apiID_XQUEUERECEIVEFROMISR                (19u)\n#define apiID_VQUEUEADDTOREGISTRY                 (20u)\n#define apiID_XQUEUEGENERICSEND                   (21u)\n#define apiID_XQUEUEGENERICSENDFROMISR            (22u)\n#define apiID_VTASKPRIORITYSET                    (23u)\n#define apiID_UXTASKPRIORITYGETFROMISR            (24u)\n#define apiID_XTASKGETTICKCOUNTFROMISR            (25u)\n#define apiID_XEVENTGROUPCLEARBITSFROMISR         (26u)\n#define apiID_XEVENTGROUPSETBITSFROMISR           (27u)\n#define apiID_XEVENTGROUPGETBITSFROMISR           (28u)\n#define apiID_XQUEUEGIVEFROMISR                   (29u)\n#define apiID_XQUEUEISQUEUEEMPTYFROMISR           (30u)\n#define apiID_XQUEUEISQUEUEFULLFROMISR            (31u) // the maximum allowed apiID for the first ID range\n\n// events which use apiSlowID_OFFSET will have 2-bytes ID\n#define apiSlowID_OFFSET                          (127u)\n\n#define apiID_VTASKALLOCATEMPUREGIONS             (1u)\n#define apiID_UXTASKPRIORITYGET                   (2u)\n#define apiID_ETASKGETSTATE                       (3u)\n#define apiID_VTASKSTARTSCHEDULER                 (4u)\n#define apiID_VTASKENDSCHEDULER                   (5u)\n#define apiID_VTASKSUSPENDALL                     (6u)\n#define apiID_XTASKRESUMEALL                      (7u)\n#define apiID_XTASKGETTICKCOUNT                   (8u)\n#define apiID_UXTASKGETNUMBEROFTASKS              (9u)\n#define apiID_PCTASKGETTASKNAME                   (10u)\n#define apiID_UXTASKGETSTACKHIGHWATERMARK         (11u)\n#define apiID_VTASKSETAPPLICATIONTASKTAG          (12u)\n#define apiID_XTASKGETAPPLICATIONTASKTAG          (13u)\n#define apiID_VTASKSETTHREADLOCALSTORAGEPOINTER   (14u)\n#define apiID_PVTASKGETTHREADLOCALSTORAGEPOINTER  (15u)\n#define apiID_XTASKCALLAPPLICATIONTASKHOOK        (16u)\n#define apiID_XTASKGETIDLETASKHANDLE              (17u)\n#define apiID_UXTASKGETSYSTEMSTATE                (18u)\n#define apiID_VTASKLIST                           (19u)\n#define apiID_VTASKGETRUNTIMESTATS                (20u)\n#define apiID_XTASKNOTIFYSTATECLEAR               (21u)\n#define apiID_XTASKGETCURRENTTASKHANDLE           (22u)\n#define apiID_VTASKSETTIMEOUTSTATE                (23u)\n#define apiID_XTASKCHECKFORTIMEOUT                (24u)\n#define apiID_VTASKMISSEDYIELD                    (25u)\n#define apiID_XTASKGETSCHEDULERSTATE              (26u)\n#define apiID_XTASKGENERICCREATE                  (27u)\n#define apiID_UXTASKGETTASKNUMBER                 (28u)\n#define apiID_VTASKSETTASKNUMBER                  (29u)\n#define apiID_ETASKCONFIRMSLEEPMODESTATUS         (30u)\n#define apiID_XTIMERCREATE                        (31u)\n#define apiID_PVTIMERGETTIMERID                   (32u)\n#define apiID_VTIMERSETTIMERID                    (33u)\n#define apiID_XTIMERISTIMERACTIVE                 (34u)\n#define apiID_XTIMERGETTIMERDAEMONTASKHANDLE      (35u)\n#define apiID_XTIMERPENDFUNCTIONCALLFROMISR       (36u)\n#define apiID_XTIMERPENDFUNCTIONCALL              (37u)\n#define apiID_PCTIMERGETTIMERNAME                 (38u)\n#define apiID_XTIMERCREATETIMERTASK               (39u)\n#define apiID_XTIMERGENERICCOMMAND                (40u)\n#define apiID_UXQUEUEMESSAGESWAITING              (41u)\n#define apiID_UXQUEUESPACESAVAILABLE              (42u)\n#define apiID_UXQUEUEMESSAGESWAITINGFROMISR       (43u)\n#define apiID_XQUEUEALTGENERICSEND                (44u)\n#define apiID_XQUEUEALTGENERICRECEIVE             (45u)\n#define apiID_XQUEUECRSENDFROMISR                 (46u)\n#define apiID_XQUEUECRRECEIVEFROMISR              (47u)\n#define apiID_XQUEUECRSEND                        (48u)\n#define apiID_XQUEUECRRECEIVE                     (49u)\n#define apiID_XQUEUECREATEMUTEX                   (50u)\n#define apiID_XQUEUECREATECOUNTINGSEMAPHORE       (51u)\n#define apiID_XQUEUEGETMUTEXHOLDER                (52u)\n#define apiID_XQUEUETAKEMUTEXRECURSIVE            (53u)\n#define apiID_XQUEUEGIVEMUTEXRECURSIVE            (54u)\n#define apiID_VQUEUEUNREGISTERQUEUE               (55u)\n#define apiID_XQUEUECREATESET                     (56u)\n#define apiID_XQUEUEADDTOSET                      (57u)\n#define apiID_XQUEUEREMOVEFROMSET                 (58u)\n#define apiID_XQUEUESELECTFROMSET                 (59u)\n#define apiID_XQUEUESELECTFROMSETFROMISR          (60u)\n#define apiID_XQUEUEGENERICRESET                  (61u)\n#define apiID_VLISTINITIALISE                     (62u)\n#define apiID_VLISTINITIALISEITEM                 (63u)\n#define apiID_VLISTINSERT                         (64u)\n#define apiID_VLISTINSERTEND                      (65u)\n#define apiID_UXLISTREMOVE                        (66u)\n#define apiID_XEVENTGROUPCREATE                   (67u)\n#define apiID_XEVENTGROUPWAITBITS                 (68u)\n#define apiID_XEVENTGROUPCLEARBITS                (69u)\n#define apiID_XEVENTGROUPSETBITS                  (70u)\n#define apiID_XEVENTGROUPSYNC                     (71u)\n#define apiID_VEVENTGROUPDELETE                   (72u)\n#define apiID_UXEVENTGROUPGETNUMBER               (73u)\n#define apiID_XSTREAMBUFFERCREATE                 (74u)\n#define apiID_VSTREAMBUFFERDELETE                 (75u)\n#define apiID_XSTREAMBUFFERRESET                  (76u)\n#define apiID_XSTREAMBUFFERSEND                   (77u)\n#define apiID_XSTREAMBUFFERSENDFROMISR            (78u)\n#define apiID_XSTREAMBUFFERRECEIVE                (79u)\n#define apiID_XSTREAMBUFFERRECEIVEFROMISR         (80u)\n\n#ifdef CONFIG_FREERTOS_SMP\n\n#define traceQUEUE_SEND( pxQueue )                                              SEGGER_SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICSEND, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), 0u, 0u, 0u)\n\n#else // CONFIG_FREERTOS_SMP\n\n#if ( configUSE_QUEUE_SETS != 1 )\n#define traceQUEUE_SEND( pxQueue )                                            SEGGER_SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICSEND, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pvItemToQueue, xTicksToWait, xCopyPosition)\n#else\n#define traceQUEUE_SEND( pxQueue )                                            SEGGER_SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICSEND, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), 0u, 0u, 0u)\n#endif\n\n#endif // CONFIG_FREERTOS_SMP\n\n\n#define traceSTART()                                                            SEGGER_SYSVIEW_Conf()\n\n#define traceTASK_NOTIFY_TAKE(uxIndexToWait)                                    SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_ULTASKNOTIFYTAKE, xClearCountOnExit, xTicksToWait)\n#define traceTASK_DELAY()                                                       SEGGER_SYSVIEW_RecordU32  (apiFastID_OFFSET + apiID_VTASKDELAY, xTicksToDelay)\n#define traceTASK_DELAY_UNTIL(xTimeToWake)                                      SEGGER_SYSVIEW_RecordVoid (apiFastID_OFFSET + apiID_VTASKDELAYUNTIL)\n#define traceTASK_NOTIFY_GIVE_FROM_ISR(uxIndexToNotify)                         SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_VTASKNOTIFYGIVEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), (U32)pxHigherPriorityTaskWoken)\n\n#define traceTASK_PRIORITY_INHERIT( pxTCB, uxPriority )                         SEGGER_SYSVIEW_RecordU32  (apiFastID_OFFSET + apiID_VTASKPRIORITYINHERIT, (U32)pxMutexHolder)\n#define traceTASK_RESUME( pxTCB )                                               SEGGER_SYSVIEW_RecordU32  (apiFastID_OFFSET + apiID_VTASKRESUME, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB))\n#define traceINCREASE_TICK_COUNT( xTicksToJump )                                SEGGER_SYSVIEW_RecordU32  (apiFastID_OFFSET + apiID_VTASKSTEPTICK, xTicksToJump)\n#define traceTASK_SUSPEND( pxTCB )                                              SEGGER_SYSVIEW_RecordU32  (apiFastID_OFFSET + apiID_VTASKSUSPEND, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB))\n#define traceTASK_PRIORITY_DISINHERIT( pxTCB, uxBasePriority )                  SEGGER_SYSVIEW_RecordU32  (apiFastID_OFFSET + apiID_XTASKPRIORITYDISINHERIT, (U32)pxMutexHolder)\n#define traceTASK_RESUME_FROM_ISR( pxTCB )                                      SEGGER_SYSVIEW_RecordU32  (apiFastID_OFFSET + apiID_XTASKRESUMEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB))\n#define traceTASK_NOTIFY(uxIndexToNotify)                                       SEGGER_SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XTASKGENERICNOTIFY, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), ulValue, eAction, (U32)pulPreviousNotificationValue)\n#define traceTASK_NOTIFY_FROM_ISR(uxIndexToWait)                                SEGGER_SYSVIEW_RecordU32x5(apiFastID_OFFSET + apiID_XTASKGENERICNOTIFYFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), ulValue, eAction, (U32)pulPreviousNotificationValue, (U32)pxHigherPriorityTaskWoken)\n#define traceTASK_NOTIFY_WAIT(uxIndexToWait)                                    SEGGER_SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XTASKNOTIFYWAIT, ulBitsToClearOnEntry, ulBitsToClearOnExit, (U32)pulNotificationValue, xTicksToWait)\n\n#define traceQUEUE_CREATE( pxNewQueue )                                         SEGGER_SYSVIEW_RecordU32x3(apiFastID_OFFSET + apiID_XQUEUEGENERICCREATE, uxQueueLength, uxItemSize, ucQueueType)\n#define traceQUEUE_DELETE( pxQueue )                                            SEGGER_SYSVIEW_RecordU32  (apiFastID_OFFSET + apiID_VQUEUEDELETE, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue))\n#define traceQUEUE_PEEK( pxQueue )                                              SEGGER_SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICRECEIVE, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)pvBuffer), xTicksToWait, 1)\n#define traceQUEUE_PEEK_FROM_ISR( pxQueue )                                     SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_XQUEUEPEEKFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)pvBuffer))\n#define traceQUEUE_PEEK_FROM_ISR_FAILED( pxQueue )                              SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_XQUEUEPEEKFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)pvBuffer))\n#define traceQUEUE_RECEIVE( pxQueue )                                           SEGGER_SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICRECEIVE, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)0), xTicksToWait, 1)\n#define traceQUEUE_RECEIVE_FAILED( pxQueue )                                    SEGGER_SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICRECEIVE, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)0), xTicksToWait, 1)\n#define traceQUEUE_SEMAPHORE_RECEIVE( pxQueue )                                 SEGGER_SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICRECEIVE, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)0), xTicksToWait, 0)\n#define traceQUEUE_RECEIVE_FROM_ISR( pxQueue )                                  SEGGER_SYSVIEW_RecordU32x3(apiFastID_OFFSET + apiID_XQUEUERECEIVEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)pvBuffer), (U32)pxHigherPriorityTaskWoken)\n#define traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue )                           SEGGER_SYSVIEW_RecordU32x3(apiFastID_OFFSET + apiID_XQUEUERECEIVEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)pvBuffer), (U32)pxHigherPriorityTaskWoken)\n#define traceQUEUE_REGISTRY_ADD( xQueue, pcQueueName )                          SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_VQUEUEADDTOREGISTRY, SEGGER_SYSVIEW_ShrinkId((U32)xQueue), (U32)pcQueueName)\n#define traceQUEUE_SEND_FAILED( pxQueue )                                       SEGGER_SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICSEND, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pvItemToQueue, xTicksToWait, xCopyPosition)\n#define traceQUEUE_SEND_FROM_ISR( pxQueue )                                     SEGGER_SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICSENDFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pvItemToQueue, (U32)pxHigherPriorityTaskWoken, xCopyPosition)\n#define traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue )                              SEGGER_SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICSENDFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pvItemToQueue, (U32)pxHigherPriorityTaskWoken, xCopyPosition)\n#define traceQUEUE_GIVE_FROM_ISR( pxQueue )                                     SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_XQUEUEGIVEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pxHigherPriorityTaskWoken)\n#define traceQUEUE_GIVE_FROM_ISR_FAILED( pxQueue )                              SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_XQUEUEGIVEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pxHigherPriorityTaskWoken)\n#define traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer )           SEGGER_SYSVIEW_RecordU32x2(apiSlowID_OFFSET + apiID_XSTREAMBUFFERCREATE, (U32)xIsMessageBuffer, (U32)pxStreamBuffer)\n#define traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer )                    SEGGER_SYSVIEW_RecordU32x2(apiSlowID_OFFSET + apiID_XSTREAMBUFFERCREATE, (U32)xIsMessageBuffer, 0u)\n#define traceSTREAM_BUFFER_DELETE( xStreamBuffer )                              SEGGER_SYSVIEW_RecordU32  (apiSlowID_OFFSET + apiID_VSTREAMBUFFERDELETE, (U32)xStreamBuffer)\n#define traceSTREAM_BUFFER_RESET( xStreamBuffer )                               SEGGER_SYSVIEW_RecordU32  (apiSlowID_OFFSET + apiID_XSTREAMBUFFERRESET, (U32)xStreamBuffer)\n#define traceSTREAM_BUFFER_SEND( xStreamBuffer, xBytesSent )                    SEGGER_SYSVIEW_RecordU32x2(apiSlowID_OFFSET + apiID_XSTREAMBUFFERSEND, (U32)xStreamBuffer, (U32)xBytesSent)\n#define traceSTREAM_BUFFER_SEND_FAILED( xStreamBuffer )                         SEGGER_SYSVIEW_RecordU32x2(apiSlowID_OFFSET + apiID_XSTREAMBUFFERSEND, (U32)xStreamBuffer, 0u)\n#define traceSTREAM_BUFFER_SEND_FROM_ISR( xStreamBuffer, xBytesSent )           SEGGER_SYSVIEW_RecordU32x2(apiSlowID_OFFSET + apiID_XSTREAMBUFFERSENDFROMISR, (U32)xStreamBuffer, (U32)xBytesSent)\n#define traceSTREAM_BUFFER_RECEIVE( xStreamBuffer, xReceivedLength )            SEGGER_SYSVIEW_RecordU32x2(apiSlowID_OFFSET + apiID_XSTREAMBUFFERRECEIVE, (U32)xStreamBuffer, (U32)xReceivedLength)\n#define traceSTREAM_BUFFER_RECEIVE_FAILED( xStreamBuffer )                      SEGGER_SYSVIEW_RecordU32x2(apiSlowID_OFFSET + apiID_XSTREAMBUFFERRECEIVE, (U32)xStreamBuffer, 0u)\n#define traceSTREAM_BUFFER_RECEIVE_FROM_ISR( xStreamBuffer, xReceivedLength )   SEGGER_SYSVIEW_RecordU32x2(apiSlowID_OFFSET + apiID_XSTREAMBUFFERRECEIVEFROMISR, (U32)xStreamBuffer, (U32)xReceivedLength)\n\n#define traceTASK_DELETE( pxTCB )                   do {                                                                                                \\\n                                                      SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_VTASKDELETE, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB));  \\\n                                                      SYSVIEW_DeleteTask((U32)pxTCB);                                                                   \\\n                                                    }  while(0)\n\n\n#if( portSTACK_GROWTH < 0 )\n#define traceTASK_CREATE(pxNewTCB)                  if (pxNewTCB != NULL) {                                             \\\n                                                      SEGGER_SYSVIEW_OnTaskCreate((U32)pxNewTCB);                       \\\n                                                      SYSVIEW_AddTask((U32)pxNewTCB,                                    \\\n                                                                      &(pxNewTCB->pcTaskName[0]),                       \\\n                                                                      pxNewTCB->uxPriority,                             \\\n                                                                      (U32)pxNewTCB->pxStack,                           \\\n                                                                      ((U32)pxNewTCB->pxTopOfStack - (U32)pxNewTCB->pxStack) \\\n                                                                      );                                                \\\n                                                    }\n#else\n#define traceTASK_CREATE(pxNewTCB)                  if (pxNewTCB != NULL) {                                             \\\n                                                      SEGGER_SYSVIEW_OnTaskCreate((U32)pxNewTCB);                       \\\n                                                      SYSVIEW_AddTask((U32)pxNewTCB,                                    \\\n                                                                      &(pxNewTCB->pcTaskName[0]),                       \\\n                                                                      pxNewTCB->uxPriority,                             \\\n                                                                      (U32)pxNewTCB->pxStack,                           \\\n                                                                      (U32)(pxNewTCB->pxStack-pxNewTCB->pxTopOfStack)   \\\n                                                                      );                                                \\\n                                                    }\n#endif\n#define traceTASK_PRIORITY_SET(pxTask, uxNewPriority) {                                                                 \\\n                                                        SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET+apiID_VTASKPRIORITYSET, \\\n                                                                                   SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), \\\n                                                                                   uxNewPriority                        \\\n                                                                                  );                                    \\\n                                                        SYSVIEW_UpdateTask((U32)pxTask,                                 \\\n                                                                           &(pxTask->pcTaskName[0]),                    \\\n                                                                           uxNewPriority,                               \\\n                                                                           (U32)pxTask->pxStack,                        \\\n                                                                           0                                            \\\n                                                                          );                                            \\\n                                                      }\n//\n// Define INCLUDE_xTaskGetIdleTaskHandle as 1 in FreeRTOSConfig.h to allow identification of Idle state.\n//\n// SMP FreeRTOS uses unpinned IDLE tasks, so sometimes IDEL0 runs on CPU1, IDLE1 runs on CPU0 and so on.\n// So IDLE state detection based on 'xTaskGetIdleTaskHandle' does not work for SMP kernel.\n// We could compare current task handle with every element of the array returned by 'xTaskGetIdleTaskHandle',\n// but it deos not seem to be efficient enough to be worth of making code more complex and less readabl.\n// So always use task name comparison mechanism for SMP kernel.\n#if ( INCLUDE_xTaskGetIdleTaskHandle == 1  && !defined(CONFIG_FREERTOS_SMP))\n#define traceTASK_SWITCHED_IN()                   if(prvGetTCBFromHandle(NULL) == xTaskGetIdleTaskHandle()) {         \\\n                                                      SEGGER_SYSVIEW_OnIdle();                                          \\\n                                                    } else {                                                            \\\n                                                      SEGGER_SYSVIEW_OnTaskStartExec((U32)prvGetTCBFromHandle(NULL));   \\\n                                                    }\n#else\n#define traceTASK_SWITCHED_IN()                   {                                                                   \\\n                                                      if (memcmp(prvGetTCBFromHandle(NULL)->pcTaskName, \"IDLE\", 4) != 0) { \\\n                                                        SEGGER_SYSVIEW_OnTaskStartExec((U32)prvGetTCBFromHandle(NULL));    \\\n                                                      } else {                                                          \\\n                                                        SEGGER_SYSVIEW_OnIdle();                                        \\\n                                                      }                                                                 \\\n                                                    }\n#endif\n\n#define traceMOVED_TASK_TO_READY_STATE(pxTCB)       SEGGER_SYSVIEW_OnTaskStartReady((U32)pxTCB)\n#define traceREADDED_TASK_TO_READY_STATE(pxTCB)\n\n#define traceMOVED_TASK_TO_DELAYED_LIST()           SEGGER_SYSVIEW_OnTaskStopReady((U32)prvGetTCBFromHandle(NULL),  (1u << 2))\n#define traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST()  SEGGER_SYSVIEW_OnTaskStopReady((U32)prvGetTCBFromHandle(NULL),  (1u << 2))\n#define traceMOVED_TASK_TO_SUSPENDED_LIST(pxTCB)    SEGGER_SYSVIEW_OnTaskStopReady((U32)pxTCB,         ((3u << 3) | 3))\n\n\n#define traceISR_EXIT_TO_SCHEDULER()                SEGGER_SYSVIEW_RecordExitISRToScheduler()\n#define traceISR_EXIT()                             SEGGER_SYSVIEW_RecordExitISR()\n#define traceISR_ENTER(n)                           SEGGER_SYSVIEW_RecordEnterISR(n)\n\n/*********************************************************************\n*\n*       API functions\n*\n**********************************************************************\n*/\n#ifdef __cplusplus\nextern \"C\" {\n#endif\nvoid SYSVIEW_AddTask      (U32 xHandle, const char *pcTaskName, unsigned uxCurrentPriority, U32  pxStack, unsigned uStackHighWaterMark);\nvoid SYSVIEW_UpdateTask   (U32 xHandle, const char *pcTaskName, unsigned uxCurrentPriority, U32 pxStack, unsigned uStackHighWaterMark);\nvoid SYSVIEW_DeleteTask   (U32 xHandle);\nvoid SYSVIEW_SendTaskInfo (U32 TaskID, const char *sName, unsigned Prio, U32 StackBase, unsigned StackSize);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n\n/*************************** End of file ****************************/\n"
  },
  {
    "path": "esp_sysview/src/esp/SEGGER_RTT_esp.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"string.h\"\n#include \"freertos/FreeRTOS.h\"\n#include \"SEGGER_RTT.h\"\n#include \"SEGGER_SYSVIEW.h\"\n#include \"SEGGER_SYSVIEW_Conf.h\"\n\n#include \"esp_log.h\"\n#include \"esp_cpu.h\"\n#include \"esp_trace_port_transport.h\"\n#include \"esp_trace_port_encoder.h\"\n#include \"esp_trace_types.h\"\n#include \"esp_private/startup_internal.h\"\n\nconst static char *TAG = \"segger_rtt\";\n\n#define SYSVIEW_EVENTS_BUF_SZ         255U\n\n// size of down channel data buf\n#define SYSVIEW_DOWN_BUF_SIZE   32\n#if CONFIG_SEGGER_SYSVIEW_BUF_WAIT_TMO == -1\n#define SEGGER_HOST_WAIT_TMO    ESP_TRACE_TMO_INFINITE\n#else\n#define SEGGER_HOST_WAIT_TMO    CONFIG_SEGGER_SYSVIEW_BUF_WAIT_TMO\n#endif\n\nstatic uint8_t s_events_buf[SYSVIEW_EVENTS_BUF_SZ];\nstatic uint16_t s_events_buf_filled;\nstatic uint8_t s_down_buf[SYSVIEW_DOWN_BUF_SIZE];\n\n/*********************************************************************\n*\n*       Public code\n*\n**********************************************************************\n*/\n\n/*********************************************************************\n*\n*       SEGGER_RTT_ESP_FlushNoLock()\n*\n*  Function description\n*    Flushes buffered events.\n*\n*  Parameters\n*    min_sz  Threshold for flushing data. If current filling level is above this value, data will be flushed. JTAG destinations only.\n*    tmo     Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely.\n*\n*  Return value\n*    None.\n*/\nvoid SEGGER_RTT_ESP_FlushNoLock(void)\n{\n    esp_err_t res;\n    esp_trace_encoder_t *encoder = SEGGER_SYSVIEW_ESP_GetEncoder();\n\n    if (!encoder) {\n        ESP_LOGE(TAG, \"Encoder not initialized\");\n        return;\n    }\n\n    esp_trace_transport_t *tp = encoder->tp;\n\n    if (s_events_buf_filled > 0) {\n        res = tp->vt->write(tp, s_events_buf, s_events_buf_filled, SEGGER_HOST_WAIT_TMO);\n        if (res != ESP_OK) {\n            ESP_LOGE(TAG, \"Failed to write buffered events (%d)!\", res);\n        }\n    }\n    // flush even if we failed to write buffered events, because no new events will be sent after STOP\n    res = tp->vt->flush_nolock(tp);\n    if (res != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to flush buffered events (%d)!\", res);\n    }\n\n    s_events_buf_filled = 0;\n}\n\n/*********************************************************************\n*\n*       SEGGER_RTT_ESP_Flush()\n*\n*  Function description\n*    Flushes buffered events.\n*\n*\n*  Return value\n*    None.\n*/\nvoid SEGGER_RTT_ESP_Flush(void)\n{\n    SEGGER_SYSVIEW_LOCK();\n    SEGGER_RTT_ESP_FlushNoLock();\n    SEGGER_SYSVIEW_UNLOCK();\n}\n\n/*********************************************************************\n*\n*       SEGGER_RTT_ReadNoLock()\n*\n*  Function description\n*    Reads characters from SEGGER real-time-terminal control block\n*    which have been previously stored by the host.\n*    Do not lock against interrupts and multiple access.\n*\n*  Parameters\n*    BufferIndex  Index of Down-buffer to be used (e.g. 0 for \"Terminal\").\n*    pBuffer      Pointer to buffer provided by target application, to copy characters from RTT-down-buffer to.\n*    BufferSize   Size of the target application buffer.\n*\n*  Return value\n*    Number of bytes that have been read.\n*/\nunsigned SEGGER_RTT_ReadNoLock(unsigned BufferIndex, void *pData, unsigned BufferSize)\n{\n    esp_trace_encoder_t *encoder = SEGGER_SYSVIEW_ESP_GetEncoder();\n    if (!encoder) {\n        return 0;\n    }\n    size_t size = BufferSize;\n    esp_err_t res = encoder->tp->vt->read(encoder->tp, pData, &size, 0);\n    return res != ESP_OK ? 0 : size;\n}\n\n/*********************************************************************\n*\n*       SEGGER_RTT_WriteSkipNoLock\n*\n*  Function description\n*    Stores a specified number of characters in SEGGER RTT\n*    control block which is then read by the host.\n*    SEGGER_RTT_WriteSkipNoLock does not lock the application and\n*    skips all data, if the data does not fit into the buffer.\n*\n*  Parameters\n*    BufferIndex  Index of \"Up\"-buffer to be used (e.g. 0 for \"Terminal\").\n*    pBuffer      Pointer to character array. Does not need to point to a \\0 terminated string.\n*    NumBytes     Number of bytes to be stored in the SEGGER RTT control block.\n*\n*  Return value\n*    Number of bytes which have been stored in the \"Up\"-buffer.\n*\n*  Notes\n*    (1) If there is not enough space in the \"Up\"-buffer, all data is dropped.\n*    (2) For performance reasons this function does not call Init()\n*        and may only be called after RTT has been initialized.\n*        Either by calling SEGGER_RTT_Init() or calling another RTT API function first.\n*/\nunsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void *pBuffer, unsigned NumBytes)\n{\n    esp_trace_encoder_t *encoder = SEGGER_SYSVIEW_ESP_GetEncoder();\n    if (!encoder) {\n        return 0;  // Encoder is not initialized\n    }\n\n    esp_trace_transport_t *tp = encoder->tp;\n    uint8_t *pbuf = (uint8_t *)pBuffer;\n    uint8_t event_id = *pbuf;\n\n    esp_trace_link_types_t link_type = tp->vt->get_link_type(tp);\n    if (link_type != ESP_TRACE_LINK_DEBUG_PROBE) { // Uart and USB Serial JTAG are handled separately\n        int dest_cpu = SEGGER_SYSVIEW_ESP_GetDestCpu();\n        if (\n            (dest_cpu != esp_cpu_get_core_id()) &&\n            (\n                (event_id == SYSVIEW_EVTID_ISR_ENTER) ||\n                (event_id == SYSVIEW_EVTID_ISR_EXIT) ||\n                (event_id == SYSVIEW_EVTID_TASK_START_EXEC) ||\n                (event_id == SYSVIEW_EVTID_TASK_STOP_EXEC) ||\n                (event_id == SYSVIEW_EVTID_TASK_START_READY) ||\n                (event_id == SYSVIEW_EVTID_TASK_STOP_READY) ||\n                (event_id == SYSVIEW_EVTID_MARK_START) ||\n                (event_id == SYSVIEW_EVTID_MARK_STOP) ||\n                (event_id == SYSVIEW_EVTID_TIMER_ENTER) ||\n                (event_id == SYSVIEW_EVTID_TIMER_EXIT) ||\n                (event_id == SYSVIEW_EVTID_STACK_INFO) ||\n                (event_id == SYSVIEW_EVTID_MODULEDESC)\n            )\n        ) {\n            return NumBytes;\n        }\n\n        // This is workaround for SystemView!\n        // Without this line SystemView will hangs on when heap tracing enabled.\n        if (event_id == SYSVIEW_EVTID_MODULEDESC) {\n            return NumBytes;\n        }\n    }\n\n    if (NumBytes > SYSVIEW_EVENTS_BUF_SZ) {\n        ESP_LOGE(TAG, \"Too large event %u bytes!\", NumBytes);\n        return 0;\n    }\n    if (link_type == ESP_TRACE_LINK_DEBUG_PROBE) {\n        if (esp_cpu_get_core_id()) { // dual core specific code\n            // use the highest - 1 bit of event ID to indicate core ID\n            // the highest bit can not be used due to event ID encoding method\n            // this reduces supported ID range to [0..63] (for 1 byte IDs) plus [128..16383] (for 2 bytes IDs)\n            if (*pbuf & 0x80) { // 2 bytes ID\n                *(pbuf + 1) |= (1 << 6);\n            } else if (NumBytes != 10 || *pbuf != 0) { // ignore sync sequence\n                *pbuf |= (1 << 6);\n            }\n        }\n\n        if (s_events_buf_filled + NumBytes > SYSVIEW_EVENTS_BUF_SZ) {\n\n            esp_err_t res = tp->vt->write(tp, s_events_buf, s_events_buf_filled, SEGGER_HOST_WAIT_TMO);\n            if (res != ESP_OK) {\n                return 0; // skip current data buffer only, accumulated events are kept\n            }\n            s_events_buf_filled = 0;\n        }\n    }\n    memcpy(&s_events_buf[s_events_buf_filled], pBuffer, NumBytes);\n    s_events_buf_filled += NumBytes;\n\n    if (link_type != ESP_TRACE_LINK_DEBUG_PROBE) {\n        esp_err_t res = tp->vt->write(tp, pBuffer, NumBytes, SEGGER_HOST_WAIT_TMO);\n        if (res != ESP_OK) {\n            return 0; // skip current data buffer only, accumulated events are kept\n        }\n        s_events_buf_filled = 0;\n    }\n\n    if (event_id == SYSVIEW_EVTID_TRACE_STOP) {\n        SEGGER_RTT_ESP_FlushNoLock();\n    }\n    return NumBytes;\n}\n\n/*********************************************************************\n*\n*       SEGGER_RTT_ConfigUpBuffer\n*\n*  Function description\n*    Run-time configuration of a specific up-buffer (T->H).\n*    Buffer to be configured is specified by index.\n*    This includes: Buffer address, size, name, flags, ...\n*\n*  Parameters\n*    BufferIndex  Index of the buffer to configure.\n*    sName        Pointer to a constant name string.\n*    pBuffer      Pointer to a buffer to be used.\n*    BufferSize   Size of the buffer.\n*    Flags        Operating modes. Define behavior if buffer is full (not enough space for entire message).\n*\n*  Return value\n*    >= 0 - O.K.\n*     < 0 - Error\n*\n*  Additional information\n*    Buffer 0 is configured on compile-time.\n*    May only be called once per buffer.\n*    Buffer name and flags can be reconfigured using the appropriate functions.\n*/\nint SEGGER_RTT_ConfigUpBuffer(unsigned BufferIndex, const char *sName, void *pBuffer, unsigned BufferSize, unsigned Flags)\n{\n    s_events_buf_filled = 0;\n    return 0;\n}\n\n/*********************************************************************\n*\n*       SEGGER_RTT_ConfigDownBuffer\n*\n*  Function description\n*    Run-time configuration of a specific down-buffer (H->T).\n*    Buffer to be configured is specified by index.\n*    This includes: Buffer address, size, name, flags, ...\n*\n*  Parameters\n*    BufferIndex  Index of the buffer to configure.\n*    sName        Pointer to a constant name string.\n*    pBuffer      Pointer to a buffer to be used.\n*    BufferSize   Size of the buffer.\n*    Flags        Operating modes. Define behavior if buffer is full (not enough space for entire message).\n*\n*  Return value\n*    >= 0  O.K.\n*     < 0  Error\n*\n*  Additional information\n*    Buffer 0 is configured on compile-time.\n*    May only be called once per buffer.\n*    Buffer name and flags can be reconfigured using the appropriate functions.\n*/\nint SEGGER_RTT_ConfigDownBuffer(unsigned BufferIndex, const char *sName, void *pBuffer, unsigned BufferSize, unsigned Flags)\n{\n    esp_trace_encoder_t *encoder = SEGGER_SYSVIEW_ESP_GetEncoder();\n    if (!encoder) {\n        return -1;\n    }\n    return encoder->tp->vt->down_buffer_config(encoder->tp, s_down_buf, sizeof(s_down_buf));\n}\n"
  },
  {
    "path": "esp_sysview/src/esp/SEGGER_SYSVIEW_esp.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include \"esp_log.h\"\n\n#include \"esp_trace_port_encoder.h\"\n#include \"esp_trace_port_transport.h\"\n#include \"adapter_encoder_sysview.h\"\n\nstatic const char *TAG = \"sysview-esp\";\n\n/**\n * @brief Encoder reference used by RTT layer\n * Set by SEGGER_SYSVIEW_ESP_SetEncoder() during encoder init.\n */\nstatic esp_trace_encoder_t *s_encoder = NULL;\n\n/*********************************************************************\n*\n*       Public code\n*\n**********************************************************************\n*/\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_ESP_SetEncoder()\n*\n*  Function description\n*    Inject encoder handle from esp_trace adapter.\n*    This allows SEGGER RTT to access transport through the encoder's\n*    transport reference.\n*\n*  Parameters\n*    encoder  Pointer to encoder instance from esp_trace\n*\n*  Return value\n*    0 if successful, -1 if encoder is not initialized or missing required functions in transport.\n*/\nint SEGGER_SYSVIEW_ESP_SetEncoder(void *encoder)\n{\n    esp_trace_encoder_t *enc = encoder;\n    /* Check if adapter has all required functions */\n    if (!enc || !enc->ctx ||\n            !enc->vt->give_lock ||\n            !enc->vt->take_lock ||\n            !enc->tp->vt->down_buffer_config ||\n            !enc->tp->vt->write ||\n            !enc->tp->vt->flush_nolock ||\n            !enc->tp->vt->read ||\n            !enc->tp->vt->get_link_type) {\n        ESP_LOGE(TAG, \"Encoder not initialized or missing required functions in transport\");\n        return -1;\n    }\n\n    s_encoder = enc;\n\n    return 0;\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_ESP_GetEncoder()\n*\n*  Function description\n*    Returns the encoder handle for accessing transport functions.\n*    This is used by SEGGER_SYSVIEW_Config_FreeRTOS.c to access\n*    transport lock functions.\n*\n*  Parameters\n*    None\n*\n*  Return value\n*    Pointer to encoder instance, or NULL if not initialized.\n*/\nvoid *SEGGER_SYSVIEW_ESP_GetEncoder(void)\n{\n    return s_encoder;\n}\n\n/*********************************************************************\n*\n*       SEGGER_SYSVIEW_ESP_GetDestCpu()\n*\n*  Function description\n*    Gets the destination CPU from the encoder context.\n*\n*  Parameters\n*    None\n*\n*  Return value\n*    CPU ID (0 or 1) to trace\n*/\nint SEGGER_SYSVIEW_ESP_GetDestCpu(void)\n{\n    sysview_encoder_ctx_t *ctx = s_encoder->ctx;\n    return ctx->dest_cpu;\n}\n"
  },
  {
    "path": "esp_sysview/src/esp/adapter_encoder_sysview.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include <stddef.h>\n#include <stdbool.h>\n#include <stdint.h>\n\n#include \"esp_err.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_trace_types.h\"\n#include \"esp_trace_registry.h\"\n#include \"esp_trace_port_encoder.h\"\n#include \"esp_trace_port_transport.h\"\n#include \"adapter_encoder_sysview.h\"\n#include \"esp_trace_util.h\"\n#include \"SEGGER_SYSVIEW.h\"\n#include \"SEGGER_RTT.h\"\n\n/*\n * This adapter is used to create a public system-wide APIs for SystemView.\n * All encoding and transport operations are done by SystemView component. (SEGGER_RTT_esp.c)\n */\n\n#define SYSVIEW_FLUSH_TMO_US (1000 * 1000)  /* 1second */\n#define SYSVIEW_FLUSH_THRESH 0\n\n/**\n * @brief Initializes sysview encoder.\n *        This function is called for each core.\n *        Adapter implementations do NOT need their own multi-core protection. Core does it for them.\n *\n * @param enc Pointer to the encoder structure. Must not be NULL.\n * @param enc_cfg Pointer to the encoder configuration. Can be NULL for defaults.\n *\n * @return ESP_OK on success, otherwise \\see esp_err_t\n */\nstatic esp_err_t init(esp_trace_encoder_t *enc, const void *enc_cfg)\n{\n    static bool initialized = false;\n\n    if (!enc) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    if (initialized) {\n        return ESP_OK;\n    }\n\n    const esp_trace_sysview_config_t *cfg = enc_cfg;\n    int dest_cpu = 0;  // Default to CPU0\n\n    if (cfg) {\n        dest_cpu = cfg->dest_cpu;\n    }\n\n    // Allocate and initialize encoder context\n    sysview_encoder_ctx_t *ctx = heap_caps_calloc(1, sizeof(*ctx), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);\n    if (!ctx) {\n        return ESP_ERR_NO_MEM;\n    }\n\n    /* Segger Sysview needs locking mechanism. */\n    esp_trace_lock_init(&ctx->lock);\n    ctx->dest_cpu = dest_cpu;\n    enc->ctx = ctx;\n\n    if (SEGGER_SYSVIEW_ESP_SetEncoder(enc) != 0) {\n        heap_caps_free(ctx);\n        enc->ctx = NULL;\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n\n    /* Configure transport for SystemView requirements */\n    if (enc->tp->vt->set_config) {\n        uint32_t flush_tmo = SYSVIEW_FLUSH_TMO_US;\n        uint32_t flush_thresh = SYSVIEW_FLUSH_THRESH;\n        uint32_t header_size = 2; /* SystemView uses 2-byte (16-bit) trace headers */\n        enc->tp->vt->set_config(enc->tp, ESP_TRACE_TRANSPORT_CFG_FLUSH_TMO, &flush_tmo);\n        enc->tp->vt->set_config(enc->tp, ESP_TRACE_TRANSPORT_CFG_FLUSH_THRESH, &flush_thresh);\n        enc->tp->vt->set_config(enc->tp, ESP_TRACE_TRANSPORT_CFG_HEADER_SIZE, &header_size);\n    }\n\n    SEGGER_SYSVIEW_Conf();\n\n    initialized = true;\n\n    return ESP_OK;\n}\n\n/**\n * @brief Panic handler\n *\n * Called during system panic to finalize encoder state.\n *\n * @param enc Pointer to the encoder structure. Must not be NULL.\n * @param info Panic information\n */\nstatic void panic_handler(esp_trace_encoder_t *enc, const void *info)\n{\n    (void)enc;\n    (void)info;\n\n    SEGGER_RTT_ESP_Flush();\n}\n\n/**\n * @brief Takes the lock of sysview encoder.\n *\n * @param enc Pointer to the encoder structure. Must not be NULL.\n * @param tmo Timeout for the operation (in us).\n */\nstatic unsigned int take_lock(esp_trace_encoder_t *enc, uint32_t tmo_us)\n{\n    sysview_encoder_ctx_t *ctx = enc->ctx;\n    esp_trace_lock_take(&ctx->lock, tmo_us);\n\n    return ctx->lock.int_state;\n}\n\n/**\n * @brief Gives the lock of sysview encoder.\n *\n * @param enc Pointer to the encoder structure. Must not be NULL.\n * @param int_state The interrupt state.\n */\nstatic void give_lock(esp_trace_encoder_t *enc, unsigned int_state)\n{\n    sysview_encoder_ctx_t *ctx = enc->ctx;\n\n    // Restore interrupt state before releasing lock\n    ctx->lock.int_state = int_state;\n    esp_trace_lock_give(&ctx->lock);\n}\n\n/**\n * @brief Sysview encoder vtable.\n */\nstatic const esp_trace_encoder_vtable_t s_sysview_vt = {\n    .init                  = init,\n    .panic_handler         = panic_handler,\n    .take_lock             = take_lock,\n    .give_lock             = give_lock,\n};\n\nESP_TRACE_REGISTER_ENCODER(\"sysview\", &s_sysview_vt);\n"
  },
  {
    "path": "esp_sysview/src/esp/adapter_encoder_sysview.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include \"esp_trace_util.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief SystemView encoder configuration\n */\ntypedef struct {\n    /**\n     * @brief CPU to trace (0 or 1)\n     *\n     * Determines which CPU's events are captured by SystemView.\n     * Only relevant when using UART apptrace transport.\n     *\n     * - 0: Capture events from CPU0 (Pro CPU)\n     * - 1: Capture events from CPU1 (App CPU)\n     *\n     * @note This parameter is ignored for single-core systems\n     * @note This parameter is ignored when using JTAG transport\n     */\n    int dest_cpu;\n} esp_trace_sysview_config_t;\n\n/**\n * @brief SystemView encoder context structure\n *\n * This structure is shared between the sysview adapter and the SEGGER RTT layer\n * to allow proper access to encoder-specific configuration.\n */\ntypedef struct {\n    int dest_cpu;                        ///< CPU to trace (0 or 1)\n    esp_trace_lock_t lock;               ///< Encoder lock\n} sysview_encoder_ctx_t;\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_sysview/src/ext/heap_trace_module.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include <stdint.h>\n#include <sdkconfig.h>\n#include \"SEGGER_SYSVIEW.h\"\n#include \"SEGGER_RTT.h\"\n#include \"esp_app_trace.h\"\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"esp_log.h\"\n\nconst static char *TAG = \"sysview_heap_trace\";\n\n#ifdef CONFIG_HEAP_TRACING_STACK_DEPTH\n#define CALLSTACK_SIZE  CONFIG_HEAP_TRACING_STACK_DEPTH\n#else\n#define CALLSTACK_SIZE  0\n#endif\n\nstatic SEGGER_SYSVIEW_MODULE s_esp_sysview_heap_module = {\n    .sModule = \"M=ESP32 SystemView Heap Tracing Module\",\n    .NumEvents = 2,\n};\n\nstatic bool s_mod_registered;\n\nesp_err_t esp_sysview_heap_trace_start(uint32_t tmo)\n{\n    uint32_t tmo_ticks = tmo / (1000 * portTICK_PERIOD_MS);\n\n    ESP_EARLY_LOGV(TAG, \"%s\", __func__);\n    do {\n        if (tmo != (uint32_t) -1) {\n            // Currently timeout implementation is simple and has granularity of 1 OS tick,\n            // so just count down the number of times to call vTaskDelay\n            if (tmo_ticks-- == 0) {\n                return ESP_ERR_TIMEOUT;\n            }\n        }\n        vTaskDelay(1);\n    } while (!SEGGER_SYSVIEW_Started());\n\n    SEGGER_SYSVIEW_RegisterModule(&s_esp_sysview_heap_module);\n    s_mod_registered = true;\n    return ESP_OK;\n}\n\nesp_err_t esp_sysview_heap_trace_stop(void)\n{\n    ESP_EARLY_LOGV(TAG, \"%s\", __func__);\n    SEGGER_RTT_ESP_Flush();\n    return ESP_OK;\n}\n\nvoid esp_sysview_heap_trace_alloc(const void *addr, uint32_t size, const void *callers)\n{\n    U8  aPacket[SEGGER_SYSVIEW_INFO_SIZE + (2 + CALLSTACK_SIZE)*SEGGER_SYSVIEW_QUANTA_U32];\n    U8 *pPayload = SEGGER_SYSVIEW_PREPARE_PACKET(aPacket);\n    U32 *calls = (U32 *)callers;\n\n    if (!s_mod_registered) {\n        return;\n    }\n    ESP_EARLY_LOGV(TAG, \"%s %p %lu\", __func__, addr, size);\n    pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, (U32)addr);\n    pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, size);\n    for (int i = 0; i < CALLSTACK_SIZE; i++) {\n        pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, calls[i]);\n    }\n    SEGGER_SYSVIEW_SendPacket(&aPacket[0], pPayload, s_esp_sysview_heap_module.EventOffset + 0);\n}\n\nvoid esp_sysview_heap_trace_free(const void *addr, const void *callers)\n{\n    U8  aPacket[SEGGER_SYSVIEW_INFO_SIZE + (1 + CALLSTACK_SIZE)*SEGGER_SYSVIEW_QUANTA_U32];\n    U8 *pPayload = SEGGER_SYSVIEW_PREPARE_PACKET(aPacket);\n    U32 *calls = (U32 *)callers;\n\n    if (!s_mod_registered) {\n        return;\n    }\n    ESP_EARLY_LOGV(TAG, \"%s %p\", __func__, addr);\n    pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, (U32)addr);\n    for (int i = 0; i < CALLSTACK_SIZE; i++) {\n        pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, calls[i]);\n    }\n    SEGGER_SYSVIEW_SendPacket(&aPacket[0], pPayload, s_esp_sysview_heap_module.EventOffset + 1);\n}\n\nesp_err_t esp_sysview_flush(void)\n{\n    SEGGER_RTT_ESP_Flush();\n    return ESP_OK;\n}\n"
  },
  {
    "path": "esp_sysview/src/ext/heap_trace_tohost.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include \"sdkconfig.h\"\n#include \"freertos/FreeRTOS.h\"\n#include \"esp_heap_trace.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_sysview_heap_trace_module.h\"\n\n#define STACK_DEPTH CONFIG_HEAP_TRACING_STACK_DEPTH\n\nstatic bool s_tracing;\n\nesp_err_t heap_trace_init_tohost(void)\n{\n    if (s_tracing) {\n        return ESP_ERR_INVALID_STATE;\n    }\n    return ESP_OK;\n}\n\nesp_err_t heap_trace_start(heap_trace_mode_t mode_param)\n{\n    esp_err_t ret = esp_sysview_heap_trace_start((uint32_t) -1);\n    if (ret != ESP_OK) {\n        return ret;\n    }\n    s_tracing = true;\n    return ESP_OK;\n}\n\nesp_err_t heap_trace_stop(void)\n{\n    esp_err_t ret = esp_sysview_heap_trace_stop();\n    s_tracing = false;\n    return ret;\n}\n\nesp_err_t heap_trace_resume(void)\n{\n    return heap_trace_start(HEAP_TRACE_ALL);\n}\n\nsize_t heap_trace_get_count(void)\n{\n    return 0;\n}\n\nesp_err_t heap_trace_get(size_t index, heap_trace_record_t *record)\n{\n    return ESP_ERR_NOT_SUPPORTED;\n}\n\nesp_err_t heap_trace_summary(heap_trace_summary_t *summary)\n{\n    return ESP_ERR_NOT_SUPPORTED;\n}\n\nvoid heap_trace_dump(void)\n{\n    return;\n}\n\nvoid heap_trace_dump_caps(__attribute__((unused)) const uint32_t caps)\n{\n    return;\n}\n\n/* Add a new allocation to the heap trace records */\nstatic HEAP_IRAM_ATTR void record_allocation(const heap_trace_record_t *record)\n{\n    if (!s_tracing) {\n        return;\n    }\n    esp_sysview_heap_trace_alloc(record->address, record->size, record->alloced_by);\n}\n\n/* record a free event in the heap trace log\n\n   For HEAP_TRACE_ALL, this means filling in the freed_by pointer.\n   For HEAP_TRACE_LEAKS, this means removing the record from the log.\n*/\nstatic HEAP_IRAM_ATTR void record_free(void *p, void **callers)\n{\n    if (!s_tracing) {\n        return;\n    }\n    esp_sysview_heap_trace_free(p, callers);\n}\n\n#include \"heap_trace.inc\"\n"
  },
  {
    "path": "esp_sysview/src/ext/logging.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2018-2021 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include <stdio.h>\n#include <stdarg.h>\n#include <sdkconfig.h>\n#include \"SEGGER_SYSVIEW_Int.h\"\n#include \"freertos/FreeRTOS.h\"\n\nstatic portMUX_TYPE s_log_mutex = portMUX_INITIALIZER_UNLOCKED;\n\nint esp_sysview_vprintf(const char *format, va_list args)\n{\n    static char log_buffer[SEGGER_SYSVIEW_MAX_STRING_LEN];\n\n    portENTER_CRITICAL(&s_log_mutex);\n    size_t len = vsnprintf(log_buffer, sizeof(log_buffer), format, args);\n    if (len > sizeof(log_buffer) - 1) {\n        log_buffer[sizeof(log_buffer) - 1] = 0;\n    }\n    SEGGER_SYSVIEW_Print(log_buffer);\n    portEXIT_CRITICAL(&s_log_mutex);\n    return len;\n}\n"
  },
  {
    "path": "esp_sysview/src/include/esp_sysview_heap_trace_module.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdarg.h>\n#include \"esp_err.h\"\n\n/**\n * @brief Flushes remaining data in SystemView trace buffer to host.\n *\n * @return ESP_OK.\n */\nesp_err_t esp_sysview_flush(void);\n\n/**\n * @brief vprintf-like function to sent log messages to the host.\n *\n * @param format  Address of format string.\n * @param args    List of arguments.\n *\n * @return Number of bytes written.\n */\nint esp_sysview_vprintf(const char *format, va_list args);\n\n/**\n * @brief  Starts SystemView heap tracing.\n *\n * @param tmo Timeout (in us) to wait for the host to be connected. Use -1 to wait forever.\n *\n * @return ESP_OK on success, ESP_ERR_TIMEOUT if operation has been timed out.\n */\nesp_err_t esp_sysview_heap_trace_start(uint32_t tmo);\n\n/**\n * @brief  Stops SystemView heap tracing.\n *\n * @return ESP_OK.\n */\nesp_err_t esp_sysview_heap_trace_stop(void);\n\n/**\n * @brief Sends heap allocation event to the host.\n *\n * @param addr      Address of allocated block.\n * @param size      Size of allocated block.\n * @param callers   Pointer to array with callstack addresses.\n *                  Array size must be CONFIG_HEAP_TRACING_STACK_DEPTH.\n */\nvoid esp_sysview_heap_trace_alloc(void *addr, uint32_t size, const void *callers);\n\n/**\n * @brief Sends heap de-allocation event to the host.\n *\n * @param addr      Address of de-allocated block.\n * @param callers   Pointer to array with callstack addresses.\n *                  Array size must be CONFIG_HEAP_TRACING_STACK_DEPTH.\n */\nvoid esp_sysview_heap_trace_free(void *addr, const void *callers);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "esp_sysview/src/include/esp_trace_freertos_impl.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include \"SEGGER_SYSVIEW_FreeRTOS.h\"\n#undef INLINE /* to avoid redefinition */\n"
  },
  {
    "path": "expat/.build-test-rules.yml",
    "content": "expat/test_apps:\n  enable:\n    - if: IDF_TARGET in [\"esp32\", \"esp32c3\"]\n      reason: \"Sufficient to test on one Xtensa and one RISC-V target\"\n"
  },
  {
    "path": "expat/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"expat/expat/lib/xmlparse.c\"\n                            \"expat/expat/lib/xmlrole.c\"\n                            \"expat/expat/lib/xmltok.c\"\n                            \"expat/expat/lib/xmltok_impl.c\"\n                            \"expat/expat/lib/xmltok_ns.c\"\n                            \"expat/expat/lib/random_getrandom.c\"\n                    INCLUDE_DIRS expat/expat/lib port/include)\n\ntarget_compile_definitions(${COMPONENT_LIB} PRIVATE HAVE_EXPAT_CONFIG_H)\ntarget_compile_definitions(${COMPONENT_LIB} PRIVATE HAVE_GETRANDOM)\n\n# Temporary suppress \"fallthrough\" warnings until they are fixed in expat repo\ntarget_compile_options(${COMPONENT_LIB} PRIVATE -Wno-implicit-fallthrough)\n"
  },
  {
    "path": "expat/idf_component.yml",
    "content": "version: \"2.8.0\"\ndescription: \"Expat - XML Parsing C Library\"\nurl: https://github.com/espressif/idf-extra-components/tree/master/expat\ndependencies:\n  idf: \">=4.3\"\nsbom:\n  manifests:\n    - path: sbom_libexpat.yml\n      dest: expat\n"
  },
  {
    "path": "expat/port/include/expat_config.h",
    "content": "/* expat_config.h.  Generated from expat_config.h.in by configure.  */\n/* expat_config.h.in.  Generated from configure.ac by autoheader.  */\n\n#ifndef EXPAT_CONFIG_H\n#define EXPAT_CONFIG_H 1\n\n/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */\n#define BYTEORDER 1234\n/* Define to 1 if you have the `bcopy' function. */\n#define HAVE_BCOPY 1\n\n/* Define to 1 if you have the <dlfcn.h> header file. */\n#define HAVE_DLFCN_H 1\n\n/* Define to 1 if you have the <fcntl.h> header file. */\n#define HAVE_FCNTL_H 1\n\n/* Define to 1 if you have the `getpagesize' function. */\n#define HAVE_GETPAGESIZE 1\n\n/* Define to 1 if you have the `getrandom' function. */\n#define HAVE_GETRANDOM 1\n\n/* Define to 1 if you have the <inttypes.h> header file. */\n#define HAVE_INTTYPES_H 1\n\n/* Define to 1 if you have the `memmove' function. */\n#define HAVE_MEMMOVE 1\n\n/* Define to 1 if you have the <memory.h> header file. */\n#define HAVE_MEMORY_H 1\n\n/* Define to 1 if you have a working `mmap' system call. */\n#define HAVE_MMAP 1\n\n/* Define to 1 if you have the <stdint.h> header file. */\n#define HAVE_STDINT_H 1\n\n/* Define to 1 if you have the <stdlib.h> header file. */\n#define HAVE_STDLIB_H 1\n\n/* Define to 1 if you have the <strings.h> header file. */\n#define HAVE_STRINGS_H 1\n\n/* Define to 1 if you have the <string.h> header file. */\n#define HAVE_STRING_H 1\n\n/* Define to 1 if you have the <sys/param.h> header file. */\n#define HAVE_SYS_PARAM_H 1\n\n/* Define to 1 if you have the <sys/stat.h> header file. */\n#define HAVE_SYS_STAT_H 1\n\n/* Define to 1 if you have the <sys/types.h> header file. */\n#define HAVE_SYS_TYPES_H 1\n\n/* Define to 1 if you have the <unistd.h> header file. */\n#define HAVE_UNISTD_H 1\n\n/* Define to the sub-directory where libtool stores uninstalled libraries. */\n#define LT_OBJDIR \".libs/\"\n\n/* Name of package */\n#define PACKAGE \"expat\"\n\n/* Define to the address where bug reports for this package should be sent. */\n#define PACKAGE_BUGREPORT \"https://github.com/libexpat/libexpat/issues\"\n\n/* Define to the full name of this package. */\n#define PACKAGE_NAME \"expat\"\n\n/* Define to the full name and version of this package. */\n#define PACKAGE_STRING \"expat 2.8.0\"\n\n/* Define to the one symbol short name of this package. */\n#define PACKAGE_TARNAME \"expat\"\n\n/* Define to the home page for this package. */\n#define PACKAGE_URL \"\"\n\n/* Define to the version of this package. */\n#define PACKAGE_VERSION \"2.8.0\"\n\n/* Define to 1 if you have the ANSI C header files. */\n#define STDC_HEADERS 1\n\n/* Version number of package */\n#define VERSION \"2.8.0\"\n\n/* whether byteorder is bigendian */\n/* #undef WORDS_BIGENDIAN */\n\n/* Define to specify how much context to retain around the current parse\n   point. */\n#define XML_CONTEXT_BYTES 1024\n\n/* Define to make parameter entity parsing functionality available. */\n#define XML_DTD 1\n\n/* Define as 1/0 to enable/disable support for general entities. */\n#define XML_GE 1\n\n/* Define to make XML Namespaces functionality available. */\n#define XML_NS 1\n\n/* Define to empty if `const' does not conform to ANSI C. */\n/* #undef const */\n\n/* Define to `long int' if <sys/types.h> does not define. */\n/* #undef off_t */\n\n/* Define to `unsigned int' if <sys/types.h> does not define. */\n/* #undef size_t */\n\n#endif // ndef EXPAT_CONFIG_H\n"
  },
  {
    "path": "expat/sbom_libexpat.yml",
    "content": "name: libexpat\nversion: 2.8.0\ncpe: cpe:2.3:a:libexpat_project:libexpat:{}:*:*:*:*:*:*:*\nsupplier: 'Organization: libexpat_project'\ndescription: Fast streaming XML parser written in C99\nurl: https://github.com/libexpat/libexpat/\nhash: 6345e05baa634fbd60ace0134228cb6af4cfdaef\ncve-exclude-list:\n  - cve: CVE-2024-8176\n    reason: Resolved in version 2.7.0, please see https://github.com/libexpat/libexpat/pull/973\n"
  },
  {
    "path": "expat/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(expat_test)\n"
  },
  {
    "path": "expat/test_apps/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"test_expat.c\" \"test_main.c\"\n                    PRIV_INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES unity\n                    WHOLE_ARCHIVE)\n"
  },
  {
    "path": "expat/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/expat:\n    version: \"*\"\n    override_path: \"../..\"\n"
  },
  {
    "path": "expat/test_apps/main/test_expat.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <expat.h>\n#include <string.h>\n#include \"unity.h\"\n\ntypedef struct {\n    int depth;\n    char output[512];\n    int output_off;\n} user_data_t;\n\nstatic void insert_space(user_data_t *user_data)\n{\n    const char align_str[] = \"    \";\n\n    TEST_ASSERT(sizeof(user_data->output) >= user_data->output_off);\n    user_data->output[user_data->output_off++] = '\\n';\n\n    for (int i = 0; i < user_data->depth; i++) {\n        for (int j = 0; j < strlen(align_str); ++j) {\n            TEST_ASSERT(sizeof(user_data->output) >= user_data->output_off);\n            user_data->output[user_data->output_off++] = align_str[j];\n        }\n    }\n}\n\nstatic void XMLCALL start_element(void *userData, const XML_Char *name, const XML_Char **atts)\n{\n    user_data_t *user_data = (user_data_t *) userData;\n\n    insert_space(user_data);\n\n    const int ret = snprintf(user_data->output + user_data->output_off,\n                             sizeof(user_data->output) - user_data->output_off,\n                             \"<%s>\", name);\n    TEST_ASSERT_EQUAL(strlen(name) + 2, ret); // 2 are the tag characters: \"<>\"\n    user_data->output_off += ret;\n    ++user_data->depth;\n}\n\nstatic void XMLCALL end_element(void *userData, const XML_Char *name)\n{\n    user_data_t *user_data = (user_data_t *) userData;\n\n    --user_data->depth;\n    insert_space(user_data);\n\n    int ret = snprintf(user_data->output + user_data->output_off, sizeof(user_data->output) - user_data->output_off,\n                       \"</%s>\", name);\n    TEST_ASSERT_EQUAL(strlen(name) + 3, ret); // 3 are the tag characters: \"</>\"\n    user_data->output_off += ret;\n}\n\nstatic void data_handler(void *userData, const XML_Char *s, int len)\n{\n    user_data_t *user_data = (user_data_t *) userData;\n\n    insert_space(user_data);\n\n    // s is not zero-terminated\n    char tmp_str[len + 1];\n    strlcpy(tmp_str, s, len + 1);\n\n    int ret = snprintf(user_data->output + user_data->output_off, sizeof(user_data->output) - user_data->output_off,\n                       \"%s\", tmp_str);\n    TEST_ASSERT_EQUAL(strlen(tmp_str), ret);\n    user_data->output_off += ret;\n}\n\nTEST_CASE(\"Expat parses XML\", \"[expat]\")\n{\n    const char test_in[] = \"<html><title>Page title</title><body><h>header</h><ol><li>A</li>\"\\\n                           \"<li>B</li><li>C</li></ol></body></html>\";\n    const char test_expected[] =    \"\\n\"\\\n                                    \"<html>\\n\"\\\n                                    \"    <title>\\n\"\\\n                                    \"        Page title\\n\"\\\n                                    \"    </title>\\n\"\\\n                                    \"    <body>\\n\"\\\n                                    \"        <h>\\n\"\\\n                                    \"            header\\n\"\\\n                                    \"        </h>\\n\"\\\n                                    \"        <ol>\\n\"\\\n                                    \"            <li>\\n\"\\\n                                    \"                A\\n\"\\\n                                    \"            </li>\\n\"\\\n                                    \"            <li>\\n\"\\\n                                    \"                B\\n\"\\\n                                    \"            </li>\\n\"\\\n                                    \"            <li>\\n\"\\\n                                    \"                C\\n\"\\\n                                    \"            </li>\\n\"\\\n                                    \"        </ol>\\n\"\\\n                                    \"    </body>\\n\"\\\n                                    \"</html>\";\n    user_data_t user_data = {\n        .depth = 0,\n        .output = { '\\0' },\n        .output_off = 0\n    };\n\n    XML_Parser parser = XML_ParserCreate(NULL);\n    XML_SetUserData(parser, &user_data);\n    XML_SetElementHandler(parser, start_element, end_element);\n    XML_SetCharacterDataHandler(parser, data_handler);\n\n    TEST_ASSERT_NOT_EQUAL(XML_STATUS_ERROR, XML_Parse(parser, test_in, strlen(test_in), 1));\n    XML_ParserFree(parser);\n\n    TEST_ASSERT_EQUAL(0, user_data.depth); // all closing tags have been found\n\n    TEST_ASSERT_EQUAL(strlen(test_expected), strlen(user_data.output));\n    TEST_ASSERT_EQUAL_STRING(test_expected, user_data.output);\n}\n"
  },
  {
    "path": "expat/test_apps/main/test_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"unity.h\"\n#include \"unity_test_runner.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_newlib.h\"\n#include \"unity_test_utils_memory.h\"\n\nvoid setUp(void)\n{\n    unity_utils_record_free_mem();\n}\n\nvoid tearDown(void)\n{\n    esp_reent_cleanup();    //clean up some of the newlib's lazy allocations\n    unity_utils_evaluate_leaks_direct(0);\n}\n\nvoid app_main(void)\n{\n    printf(\"Running expat component tests\\n\");\n    unity_run_menu();\n}\n"
  },
  {
    "path": "expat/test_apps/pytest_expat.py",
    "content": "import pytest\n\n\n@pytest.mark.generic\ndef test_expat(dut) -> None:\n    dut.run_all_single_board_cases()\n"
  },
  {
    "path": "expat/test_apps/sdkconfig.defaults",
    "content": "# This file was generated using idf.py save-defconfig. It can be edited manually.\n# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration\n#\nCONFIG_ESP_TASK_WDT_INIT=n\n"
  },
  {
    "path": "fmt/CMakeLists.txt",
    "content": "idf_component_register( )\n\nset(FMT_INSTALL OFF)\nadd_subdirectory(fmt)\n\ntarget_link_libraries(${COMPONENT_LIB} INTERFACE fmt::fmt)\n\n"
  },
  {
    "path": "fmt/README.md",
    "content": " # FMT\n \n [![Component Registry](https://components.espressif.com/components/espressif/fmt/badge.svg)](https://components.espressif.com/components/espressif/fmt)\n \n**fmt** is an open-source formatting library providing a fast and safe\nalternative to C stdio and C++ iostreams.\n\nSee the project [README](https://github.com/fmtlib/fmt/blob/master/README.md) for details.\n\n\n"
  },
  {
    "path": "fmt/examples/hello_fmt/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(hello_fmt)\n"
  },
  {
    "path": "fmt/examples/hello_fmt/README.md",
    "content": "# `fmt` basic example\n\nThis is a basic example of using `fmt` library in an ESP-IDF project. It includes `fmt` and prints `Hello, fmt!` on the console.\n\nThe example runs on any ESP development board. To build and run the example, follow the same steps as for any other ESP-IDF project. For example, for ESP32-C3:\n\n```bash\nidf.py set-target esp32c3\nidf.py flash monitor\n```\n\nThe example should print the following:\n\n```\nI (6074) main_task: Calling app_main()\nHello, fmt!\nI (6084) main_task: Returned from app_main()\n```\n"
  },
  {
    "path": "fmt/examples/hello_fmt/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"hello_fmt.cpp\"\n                    INCLUDE_DIRS \".\")\n"
  },
  {
    "path": "fmt/examples/hello_fmt/main/hello_fmt.cpp",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n\n#include <fmt/core.h>\n\nextern \"C\" void app_main()\n{\n    fmt::print(\"Hello, fmt!\\n\");\n}\n"
  },
  {
    "path": "fmt/examples/hello_fmt/main/idf_component.yml",
    "content": "dependencies:\n  fmt:\n    version: \"*\"\n    override_path: \"../../../\"\n"
  },
  {
    "path": "fmt/examples/hello_fmt/pytest_fmt.py",
    "content": "# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\n\nimport pytest\nfrom pytest_embedded import Dut\n\n\n@pytest.mark.generic\ndef test_fmt_example(dut: Dut) -> None:\n    dut.expect_exact('Hello, fmt!')\n"
  },
  {
    "path": "fmt/idf_component.yml",
    "content": "version: \"11.0.1\"\ndescription: Formatting library providing a fast and safe alternative to C stdio and C++ iostreams.\nurl: https://github.com/espressif/idf-extra-components/tree/master/fmt\ndependencies:\n  idf: \">=4.1\"\nsbom:\n  manifests:\n    - path: sbom_fmt.yml\n      dest: fmt\n"
  },
  {
    "path": "fmt/sbom_fmt.yml",
    "content": "name: fmt\nversion: 11.0.1\ncpe: cpe:2.3:a:fmt:fmt:{}:*:*:*:*:*:*:*\nsupplier: 'Organization: fmt <https://fmt.dev/latest/index.html>'\ndescription: A modern formatting library\nurl: https://github.com/fmtlib/fmt/\nhash: b50e685db996c167e6c831dcef582aba6e14276a\n"
  },
  {
    "path": "freetype/CMakeLists.txt",
    "content": "idf_component_register()\n\n# Override options defined in freetype/CMakeLists.txt.\n# We could have used normal set(...) here if freetype enabled CMake policy CMP0077.\noption(FT_DISABLE_HARFBUZZ \"\" ON)\noption(FT_DISABLE_BZIP2 \"\" ON)\noption(FT_DISABLE_BROTLI \"\" ON)\noption(FT_DISABLE_PNG \"\" ON)\noption(FT_DISABLE_ZLIB \"\" ON)\n\n# These are regular CMake variables, so we can set them directly.\nset(SKIP_INSTALL_ALL TRUE)\nset(BUILD_SHARED_LIBS OFF)\n\nadd_subdirectory(freetype output)\n\n# https://gitlab.freedesktop.org/freetype/freetype/-/issues/1299\ntarget_compile_options(freetype PRIVATE \"-Wno-dangling-pointer\")\n\ntarget_link_libraries(${COMPONENT_LIB} INTERFACE freetype)\n"
  },
  {
    "path": "freetype/LICENSE",
    "content": "FREETYPE LICENSES\n-----------------\n\nThe FreeType  2 font  engine is  copyrighted work  and cannot  be used\nlegally without  a software  license.  In order  to make  this project\nusable to  a vast majority of  developers, we distribute it  under two\nmutually exclusive open-source licenses.\n\nThis means that *you* must choose  *one* of the two licenses described\nbelow, then obey all its terms and conditions when using FreeType 2 in\nany of your projects or products.\n\n  - The FreeType License,  found in the file  `docs/FTL.TXT`, which is\n    similar to the  original BSD license *with*  an advertising clause\n    that forces  you to explicitly  cite the FreeType project  in your\n    product's  documentation.  All  details are  in the  license file.\n    This license is suited to products which don't use the GNU General\n    Public License.\n\n    Note that  this license  is compatible to  the GNU  General Public\n    License version 3, but not version 2.\n\n  - The   GNU   General   Public   License   version   2,   found   in\n    `docs/GPLv2.TXT`  (any  later  version  can  be  used  also),  for\n    programs  which  already  use  the  GPL.  Note  that  the  FTL  is\n    incompatible with GPLv2 due to its advertisement clause.\n\nThe contributed  BDF and PCF  drivers come  with a license  similar to\nthat  of the  X Window  System.   It is  compatible to  the above  two\nlicenses (see files `src/bdf/README`  and `src/pcf/README`).  The same\nholds   for   the   source    code   files   `src/base/fthash.c`   and\n`include/freetype/internal/fthash.h`; they were part of the BDF driver\nin earlier FreeType versions.\n\nThe gzip  module uses the  zlib license (see  `src/gzip/zlib.h`) which\ntoo is compatible to the above two licenses.\n\nThe files `src/autofit/ft-hb.c` and `src/autofit/ft-hb.h` contain code\ntaken almost  verbatim from the  HarfBuzz file `hb-ft.cc`,  which uses\nthe 'Old MIT' license, compatible to the above two licenses.\n\nThe  MD5 checksum  support  (only used  for  debugging in  development\nbuilds) is in the public domain.\n\n\n--- end of LICENSE.TXT ---"
  },
  {
    "path": "freetype/README.md",
    "content": "# freetype compression and decompression Library\n\n[![Component Registry](https://components.espressif.com/components/espressif/freetype/badge.svg)](https://components.espressif.com/components/espressif/freetype)\n\nThis is an IDF component for freetype library.\n\nFor usage instructions, please refer to the official documentation: https://freetype.org/freetype2/docs/documentation.html\n"
  },
  {
    "path": "freetype/examples/freetype-example/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.17)\n\nset(COMPONENTS main)\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nproject(freetype-example)\n"
  },
  {
    "path": "freetype/examples/freetype-example/README.md",
    "content": "# FreeType Example\n\nThis is a simple example of initializing FreeType library, loading a font from a filesystem, and rendering a line of text.\n\nThe font file (DejaVu Sans) is downloaded at compile time and is added into a SPIFFS filesystem image. The filesystem is flashed to the board together with the application. The example loads the font file and renders \"FreeType\" text into the console as ASCII art.\n\nThis example doesn't require any special hardware and can run on any development board.\n\n## Building and running\n\nRun the application as usual for an ESP-IDF project. For example, for ESP32:\n```\nidf.py set-target esp32\nidf.py -p PORT flash monitor\n```\n\n## Example output\n\nThe example should output the following:\n\n```\nI (468) main_task: Calling app_main()\nI (538) example: FreeType library initialized\nI (1258) example: Font loaded\nI (1268) example: Rendering char: 'F'\nI (1388) example: Rendering char: 'r'\nI (1528) example: Rendering char: 'e'\nI (1658) example: Rendering char: 'e'\nI (1798) example: Rendering char: 'T'\nI (1938) example: Rendering char: 'y'\nI (2078) example: Rendering char: 'p'\nI (2208) example: Rendering char: 'e'\n\n\n######.                          #########\n##                                  +#\n##      #####   +###+    +###+      +#   +#    ########     +###+\n##      ##+    +#. .#+  +#. .#+     +#    #+   #+##+ .#+   +#. .#+\n######  ##     #+   +#  #+   +#     +#    ##  +# ##   +#   #+   +#\n##      ##    .####### .#######     +#    .#  ## ##   .#  .#######\n##      ##    .#.      .#.          +#     #+.#. ##   .#  .#.\n##      ##     #+       #+          +#     +###  ##   +#   #+\n##      ##     ##+  ++  ##+  ++     +#      ##+  ##+ .#+   ##+  ++\n##      ##      +####    +####      +#      ##   ######     +####\n                                            ##   ##\n                                           +#.   ##\n                                          ##+    ##\n\n\n\n```\n"
  },
  {
    "path": "freetype/examples/freetype-example/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"freetype-example.c\"\n                    INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES spiffs)\n\n# Download the example font into a directory \"spiffs\" in the build directory\nset(URL \"https://github.com/espressif/esp-docs/raw/f036a337d8bee5d1a93b2264ecd29255baec4260/src/esp_docs/fonts/DejaVuSans.ttf\")\nset(FILE \"DejaVuSans.ttf\")\nset(SPIFFS_DIR \"${CMAKE_BINARY_DIR}/spiffs\")\nfile(MAKE_DIRECTORY ${SPIFFS_DIR})\nfile(DOWNLOAD ${URL} ${SPIFFS_DIR}/${FILE} SHOW_PROGRESS)\n\n# Create a partition named \"fonts\" with the example font\nspiffs_create_partition_image(fonts ${SPIFFS_DIR} FLASH_IN_PROJECT)\n"
  },
  {
    "path": "freetype/examples/freetype-example/main/freetype-example.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n\n\n#include <stdlib.h>\n#include \"esp_log.h\"\n#include \"esp_err.h\"\n#include \"esp_spiffs.h\"\n#include \"ft2build.h\"\n#include FT_FREETYPE_H\n\nstatic const char *TAG = \"example\";\n\nstatic void init_filesystem(void);\nstatic void init_freetype(void);\nstatic void load_font(void);\nstatic void render_text(void);\n\n#define BITMAP_WIDTH  80\n#define BITMAP_HEIGHT 18\n\nstatic FT_Library  s_library;\nstatic FT_Face s_face;\nstatic uint8_t s_bitmap[BITMAP_HEIGHT][BITMAP_WIDTH];\n\n\nvoid app_main(void)\n{\n    init_filesystem();\n    init_freetype();\n    load_font();\n    render_text();\n}\n\nstatic void init_filesystem(void)\n{\n    esp_vfs_spiffs_conf_t conf = {\n        .base_path = \"/fonts\",\n        .partition_label = \"fonts\",\n        .max_files = 1,\n    };\n\n    ESP_ERROR_CHECK(esp_vfs_spiffs_register(&conf));\n}\n\nstatic void init_freetype(void)\n{\n    FT_Error error = FT_Init_FreeType( &s_library );\n    if (error) {\n        ESP_LOGE(TAG, \"Error initializing FreeType library: %d\", error);\n        abort();\n    }\n\n    ESP_LOGI(TAG, \"FreeType library initialized\");\n}\n\nstatic void load_font(void)\n{\n    FT_Error error = FT_New_Face( s_library,\n                                  \"/fonts/DejaVuSans.ttf\",\n                                  0,\n                                  &s_face );\n    if (error) {\n        ESP_LOGE(TAG, \"Error loading font: %d\", error);\n        abort();\n    }\n\n    ESP_LOGI(TAG, \"Font loaded\");\n\n}\n\nstatic void render_text(void)\n{\n    /* Configure character size. */\n    const int font_size = 14;\n    const int freetype_scale = 64;\n    FT_Error error = FT_Set_Char_Size(s_face, 0, font_size * freetype_scale, 0, 0 );\n    if (error) {\n        ESP_LOGE(TAG, \"Error setting font size: %d\", error);\n        abort();\n    }\n\n    const char *text = \"FreeType\";\n    int num_chars = strlen(text);\n\n    /* current drawing position */\n    int x = 0;\n    int y = 12;\n\n    for (int n = 0; n < num_chars; n++) {\n        ESP_LOGI(TAG, \"Rendering char: '%c'\", text[n]);\n\n        /* retrieve glyph index from character code */\n        FT_UInt  glyph_index = FT_Get_Char_Index( s_face, text[n] );\n\n        /* load glyph image into the slot (erase previous one) */\n        error = FT_Load_Glyph( s_face, glyph_index, FT_LOAD_DEFAULT );\n        if (error) {\n            ESP_LOGE(TAG, \"Error loading glyph: %d\", error);\n            abort();\n        }\n\n        /* convert to a bitmap */\n        error = FT_Render_Glyph( s_face->glyph, FT_RENDER_MODE_NORMAL );\n        if (error) {\n            ESP_LOGE(TAG, \"Error rendering glyph: %d\", error);\n            abort();\n        }\n\n        /* copy the glyph bitmap into the overall bitmap */\n        FT_GlyphSlot slot = s_face->glyph;\n        for (int iy = 0; iy < slot->bitmap.rows; iy++) {\n            for (int ix = 0; ix < slot->bitmap.width; ix++) {\n                /* bounds check */\n                int res_x = ix + x;\n                int res_y = y + iy - slot->bitmap_top;\n                if (res_x >= BITMAP_WIDTH || res_y >= BITMAP_HEIGHT) {\n                    continue;\n                }\n                s_bitmap[res_y][res_x] = slot->bitmap.buffer[ix + iy * slot->bitmap.width];\n            }\n        }\n\n        /* increment horizontal position */\n        x += slot->advance.x / 64;\n        if (x >= BITMAP_WIDTH) {\n            break;\n        }\n    }\n\n    /* output the resulting bitmap to console */\n    for (int iy = 0; iy < BITMAP_HEIGHT; iy++) {\n        for (int ix = 0; ix < x; ix++) {\n            int val = s_bitmap[iy][ix];\n            if (val > 127) {\n                putchar('#');\n            } else if (val > 64) {\n                putchar('+');\n            } else if (val > 32) {\n                putchar('.');\n            } else {\n                putchar(' ');\n            }\n        }\n        putchar('\\n');\n    }\n}\n"
  },
  {
    "path": "freetype/examples/freetype-example/main/idf_component.yml",
    "content": "dependencies:\n  espressif/freetype:\n    version: \"*\"\n    override_path: \"../../..\"\n"
  },
  {
    "path": "freetype/examples/freetype-example/partitions.csv",
    "content": "nvs,      data, nvs,     0x9000,  0x6000,\nphy_init, data, phy,     0xf000,  0x1000,\nfactory,  app,  factory, 0x10000, 1M,\nfonts,    data, spiffs,  ,        0xF0000,\n"
  },
  {
    "path": "freetype/examples/freetype-example/pytest_freetype.py",
    "content": "# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nfrom __future__ import unicode_literals\n\nimport textwrap\n\nimport pytest\nfrom pytest_embedded import Dut\n\n\n@pytest.mark.generic\ndef test_freetype_example(dut: Dut) -> None:\n    dut.expect_exact('FreeType library initialized')\n    dut.expect_exact('Font loaded')\n    for c in 'FreeType':\n        dut.expect_exact(f'Rendering char: \\'{c}\\'')\n"
  },
  {
    "path": "freetype/examples/freetype-example/sdkconfig.defaults",
    "content": "CONFIG_PARTITION_TABLE_CUSTOM=y\nCONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions.csv\"\n\nCONFIG_ESP_MAIN_TASK_STACK_SIZE=20000\nCONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y\n"
  },
  {
    "path": "freetype/idf_component.yml",
    "content": "version: \"2.14.2\"\ndescription: freetype C library\nurl: https://github.com/espressif/idf-extra-components/tree/master/freetype\nrepository: \"https://github.com/espressif/idf-extra-components.git\"\ndocumentation: \"https://freetype.org/freetype2/docs/documentation.html\"\nissues: \"https://github.com/espressif/idf-extra-components/issues\" # URL of the issue tracker\ndependencies:\n  idf: \">=4.4\"\nsbom:\n  manifests:\n    - path: sbom_freetype.yml\n      dest: freetype\n"
  },
  {
    "path": "freetype/sbom_freetype.yml",
    "content": "name: freetype\nversion: 2.14.2\ncpe: cpe:2.3:a:freetype:freetype:{}:*:*:*:*:*:*:*\nsupplier: 'Organization: freetype <https://www.freetype.org>'\ndescription: FreeType is a software font engine\nurl: https://github.com/freetype/freetype\nhash: f4205da14867c5387cd6a329b90ee10a6df6eeff\ncve-exclude-list:\n  - cve: CVE-2026-23865\n    reason: Fixed in version 2.14.2 with commit https://github.com/freetype/freetype/commit/fc85a255849229c024c8e65f536fe1875d84841c\n"
  },
  {
    "path": "iqmath/.build-test-rules.yml",
    "content": ""
  },
  {
    "path": "iqmath/CHANGELOG.md",
    "content": "## 1.11.0\n\n- Initial port of the IQMath Library, obtained from TI MSPM0 SDK\n"
  },
  {
    "path": "iqmath/CMakeLists.txt",
    "content": "set(srcs\n    \"_IQNfunctions/_atoIQN.c\"\n    \"_IQNfunctions/_IQNasin_acos.c\"\n    \"_IQNfunctions/_IQNatan2.c\"\n    \"_IQNfunctions/_IQNdiv.c\"\n    \"_IQNfunctions/_IQNexp.c\"\n    \"_IQNfunctions/_IQNfrac.c\"\n    \"_IQNfunctions/_IQNlog.c\"\n    \"_IQNfunctions/_IQNmpy.c\"\n    \"_IQNfunctions/_IQNmpyIQX.c\"\n    \"_IQNfunctions/_IQNrepeat.c\"\n    \"_IQNfunctions/_IQNrmpy.c\"\n    \"_IQNfunctions/_IQNrsmpy.c\"\n    \"_IQNfunctions/_IQNsin_cos.c\"\n    \"_IQNfunctions/_IQNsqrt.c\"\n    \"_IQNfunctions/_IQNtables.c\"\n    \"_IQNfunctions/_IQNtoa.c\"\n    \"_IQNfunctions/_IQNtoF.c\"\n    \"_IQNfunctions/_IQNversion.c\")\n\nidf_component_register(SRCS ${srcs}\n                       INCLUDE_DIRS \"include\")\n"
  },
  {
    "path": "iqmath/LICENSE",
    "content": "Copyright (c) 2023, Texas Instruments Incorporated\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n\n* Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright\nnotice, this list of conditions and the following disclaimer in the\ndocumentation and/or other materials provided with the distribution.\n\n* Neither the name of Texas Instruments Incorporated nor the names of\nits contributors may be used to endorse or promote products derived\nfrom this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\nCONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\nEXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\nPROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;\nOR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\nWHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\nOTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\nEVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
  },
  {
    "path": "iqmath/README.md",
    "content": "# IQMath Library\n\n[![Component Registry](https://components.espressif.com/components/espressif/iqmath/badge.svg)](https://components.espressif.com/components/espressif/iqmath)\n\nThe IQmath Library is a collection of highly optimized and high-precision mathematical functions for C programmers to seamlessly port a floating-point algorithm into fixed-point code on ESP chips. These routines are typically used in computationally intensive real-time applications where optimal execution speed, high accuracy and ultra-low energy are critical. By using the IQmath library, it is possible to achieve execution speeds considerably faster and energy consumption considerably lower than equivalent code written using floating-point math.\n\nThe IQmath library provides functions for use with 32-bit data types and high accuracy.\n\n## IQmath Data Types\n\nThe IQmath library uses a 32-bit fixed-point signed number (i.e. `int32_t`) as its basic data type. The IQ format of this fixed-point number can range from `IQ1` to `IQ30`, where the IQ format number indicates the number of fractional bits. The IQ format value is stored as an integer with an implied scale based on the IQ format and the number of fractional bits. The equation below shows how a IQ format decimal number $x_{iq}$ is stored using an integer value $x_i$ with an implied scale, where $n$ represents the number of fractional bits.\n\n$$\nIQ_n(x_{iq}) = x_i * 2^{-n}\n$$\n\nFor example the IQ24 value of 3.625 is stored as an integer value of 60817408, shown in the equation below.\n\n$$\nIQ_{24}(3.625) = 60817408 * 2^{-24}\n$$\n\nC typedefs are provided for the various IQ formats, and these IQmath data types should be used in preference to the underlying “int32_t” data type to make it clear which variables are in IQ format.\n\nThe following table provides the characteristics of the various IQ formats:\n\n| Type  | Integer Bits | Fractional Bits | Min Range      | Max Range                 | Resolution    |\n|-------|--------------|-----------------|----------------|---------------------------|---------------|\n| _iq30 | 2            | 30              | -2             | 1.999 999 999             | 0.000 000 001 |\n| _iq29 | 3            | 29              | -4             | 3.999 999 998             | 0.000 000 002 |\n| _iq28 | 4            | 28              | -8             | 7.999 999 996             | 0.000 000 004 |\n| _iq27 | 5            | 27              | -16            | 15.999 999 993            | 0.000 000 007 |\n| _iq26 | 6            | 26              | -32            | 31.999 999 985            | 0.000 000 015 |\n| _iq25 | 7            | 25              | -64            | 63.999 999 970            | 0.000 000 030 |\n| _iq24 | 8            | 24              | -128           | 127.999 999 940           | 0.000 000 060 |\n| _iq23 | 9            | 23              | -256           | 255.999 999 881           | 0.000 000 119 |\n| _iq22 | 10           | 22              | -512           | 511.999 999 762           | 0.000 000 238 |\n| _iq21 | 11           | 21              | -1,024         | 1,023.999 999 523         | 0.000 000 477 |\n| _iq20 | 12           | 20              | -2,048         | 2,047.999 999 046         | 0.000 000 954 |\n| _iq19 | 13           | 19              | -4,096         | 4,095.999 998 093         | 0.000 001 907 |\n| _iq18 | 14           | 18              | -8,192         | 8,191.999 996 185         | 0.000 003 815 |\n| _iq17 | 15           | 17              | -16,384        | 16,383.999 992 371        | 0.000 007 629 |\n| _iq16 | 16           | 16              | -32,768        | 32,767.999 984 741        | 0.000 015 259 |\n| _iq15 | 17           | 15              | -65,536        | 65,535.999 969 483        | 0.000 030 518 |\n| _iq14 | 18           | 14              | -131,072       | 131,071.999 938 965       | 0.000 061 035 |\n| _iq13 | 19           | 13              | -262,144       | 262,143.999 877 930       | 0.000 122 070 |\n| _iq12 | 20           | 12              | -524,288       | 524,287.999 755 859       | 0.000 244 141 |\n| _iq11 | 21           | 11              | -1,048,576     | 1,048,575.999 511 720     | 0.000 488 281 |\n| _iq10 | 22           | 10              | -2,097,152     | 2,097,151.999 023 440     | 0.000 976 563 |\n| _iq9  | 23           | 9               | -4,194,304     | 4,194,303.998 046 880     | 0.001 953 125 |\n| _iq8  | 24           | 8               | -8,388,608     | 8,388,607.996 093 750     | 0.003 906 250 |\n| _iq7  | 25           | 7               | -16,777,216    | 16,777,215.992 187 500    | 0.007 812 500 |\n| _iq6  | 26           | 6               | -33,554,432    | 33,554,431.984 375 000    | 0.015 625 000 |\n| _iq5  | 27           | 5               | -67,108,864    | 67,108,863.968 750 000    | 0.031 250 000 |\n| _iq4  | 28           | 4               | -134,217,728   | 134,217,727.937 500 000   | 0.062 500 000 |\n| _iq3  | 29           | 3               | -268,435,456   | 268,435,455.875 000 000   | 0.125 000 000 |\n| _iq2  | 30           | 2               | -536,870,912   | 536,870,911.750 000 000   | 0.250 000 000 |\n| _iq1  | 31           | 1               | -1,073,741,824 | 1,073,741,823.500 000 000 | 0.500 000 000 |\n\n## API Guide\n\nIQmath includes five types of routines:\n\n* **Format conversion functions**: methods to convert numbers to and from the various formats.\n* **Arithmetic functions**: methods to perform basic arithmetic (addition, subtraction, multiplication, division).\n* **Trigonometric functions**: methods to perform trigonometric functions (sin, cos, atan, and so on).\n* **Mathematical functions**: methods to perform advanced arithmetic (square root, ex , and so on).\n* **Miscellaneous**: miscellaneous methods (saturation and absolute value).\n"
  },
  {
    "path": "iqmath/_IQNfunctions/_IQNasin_acos.c",
    "content": "/*!****************************************************************************\n *  @file       _IQNasin_acos.c\n *  @brief      Functions to compute the inverse sine of the input\n *              and return the result, in radians.\n *\n *  <hr>\n ******************************************************************************/\n\n#include <stdint.h>\n\n#include \"../support/support.h\"\n#include \"_IQNtables.h\"\n\n/* Hidden Q31 sqrt function. */\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\n/**\n * @brief Computes the square root of the IQ31 input.\n *\n * @param iq31Input       IQ31 type input.\n *\n * @return                IQ31 type result of square root.\n */\nextern int_fast32_t _IQ31sqrt(int_fast32_t iq31Input);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Computes the inverse sine of the IQN input.\n *\n * @param iqNInput        IQN type input.\n * @param q_value         IQ format.\n *\n * @return                IQN type result of inverse sine.\n */\n/*\n * Calculate asin using a 4th order Taylor series for inputs in the range of\n * zero to 0.5. The coefficients are stored in a lookup table with 17 ranges\n * to give an accuracy of 26 bits.\n *\n * For inputs greater than 0.5 we apply the following transformation:\n *\n *     asin(x) = PI/2 - 2*asin(sqrt((1 - x)/2))\n *\n * This transformation is derived from the following trig identities:\n *\n *     (1) asin(x) = PI/2 - acos(x)\n *     (2) sin(t/2)^2 = (1 - cos(t))/2\n *     (3) cos(t) = x\n *     (4) t = acos(x)\n *\n * Identity (2) can be simplified to give equation (5):\n *\n *     (5) t = 2*asin(sqrt((1 - cos(t))/2))\n *\n * Substituting identities (3) and (4) into equation (5) gives equation (6):\n *\n *     (6) acos(x) = 2*asin(sqrt((1 - x)/2))\n *\n * The final step is substituting equation (6) into identity (1):\n *\n *     asin(x) = PI/2 - 2*asin(sqrt((1 - x)/2))\n *\n * Acos is implemented using asin and identity (1).\n */\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNasin)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n__STATIC_INLINE int_fast32_t __IQNasin(int_fast32_t iqNInput, const int8_t q_value)\n{\n    uint8_t ui8Status = 0;\n    uint_fast16_t index;\n    uint_fast16_t ui16IntState;\n    uint_fast16_t ui16MPYState;\n    int_fast32_t iq29Result;\n    const int_fast32_t *piq29Coeffs;\n    uint_fast32_t uiq31Input;\n    uint_fast32_t uiq31InputTemp;\n\n    /*\n     * Extract the sign from the input and set the following status bits:\n     *\n     *      ui8Status = xxxxxxTS\n     *      x = unused\n     *      T = transform was applied\n     *      S = sign bit needs to be set (-y)\n     */\n    if (iqNInput < 0) {\n        ui8Status |= 1;\n        iqNInput = -iqNInput;\n    }\n\n    /*\n     * Check if input is within the valid input range:\n     *\n     *     0 <= iqNInput <= 1\n     */\n    if (iqNInput > ((uint_fast32_t)1 << q_value)) {\n        return 0;\n    }\n\n    /* Convert input to unsigned iq31. */\n    uiq31Input = (uint_fast32_t)iqNInput << (31 - q_value);\n\n    /*\n     * Apply the transformation from asin to acos if input is greater than 0.5.\n     * The first step is to calculate the following:\n     *\n     *     (sqrt((1 - uiq31Input)/2))\n     */\n    uiq31InputTemp = 0x80000000 - uiq31Input;\n    if (uiq31InputTemp < 0x40000000) {\n        /* Halve the result. */\n        uiq31Input = uiq31InputTemp >> 1;\n\n        /* Calculate sqrt((1 - uiq31Input)/2) */\n        uiq31Input = _IQ31sqrt(uiq31Input);\n\n        /* Flag that the transformation was used. */\n        ui8Status |= 2;\n    }\n\n    /* Calculate the index using the left 6 most bits of the input. */\n    index = (int_fast16_t)(uiq31Input >> 26) & 0x003f;\n\n    /* Set the coefficient pointer. */\n    piq29Coeffs = _IQ29Asin_coeffs[index];\n\n    /*\n     * Mark the start of any multiplies. This will disable interrupts and set\n     * the multiplier to fractional mode. This is designed to reduce overhead\n     * of constantly switching states when using repeated multiplies (MSP430\n     * only).\n     */\n    __mpyf_start(&ui16IntState, &ui16MPYState);\n\n    /*\n     * Calculate asin(x) using the following Taylor series:\n     *\n     *     asin(x) = (((c4*x + c3)*x + c2)*x + c1)*x + c0\n     */\n\n    /* c4*x */\n    iq29Result = __mpyf_l(uiq31Input, *piq29Coeffs++);\n\n    /* c4*x + c3 */\n    iq29Result = iq29Result + *piq29Coeffs++;\n\n    /* (c4*x + c3)*x */\n    iq29Result = __mpyf_l(uiq31Input, iq29Result);\n\n    /* (c4*x + c3)*x + c2 */\n    iq29Result = iq29Result + *piq29Coeffs++;\n\n    /* ((c4*x + c3)*x + c2)*x */\n    iq29Result = __mpyf_l(uiq31Input, iq29Result);\n\n    /* ((c4*x + c3)*x + c2)*x + c1 */\n    iq29Result = iq29Result + *piq29Coeffs++;\n\n    /* (((c4*x + c3)*x + c2)*x + c1)*x */\n    iq29Result = __mpyf_l(uiq31Input, iq29Result);\n\n    /* (((c4*x + c3)*x + c2)*x + c1)*x + c0 */\n    iq29Result = iq29Result + *piq29Coeffs++;\n\n    /*\n     * Mark the end of all multiplies. This restores MPY and interrupt states\n     * (MSP430 only).\n     */\n    __mpy_stop(&ui16IntState, &ui16MPYState);\n\n    /* check if we switched to acos */\n    if (ui8Status & 2) {\n        /* asin(x) = pi/2 - 2*iq29Result */\n        iq29Result = iq29Result << 1;\n        iq29Result -= iq29_halfPi;      // this is equivalent to the above\n        iq29Result = -iq29Result;       // but avoids using temporary registers\n    }\n\n    /* Shift iq29 result to specified q_value. */\n    iq29Result >>= 29 - q_value;\n\n    /* Add sign to the result. */\n    if (ui8Status & 1) {\n        iq29Result = -iq29Result;\n    }\n\n    return iq29Result;\n}\n\n/* ASIN */\n/**\n * @brief Computes the inverse sine of the IQ29 input.\n *\n * @param a               IQ29 type input.\n *\n * @return                IQ29 type result of inverse sine.\n */\nint32_t _IQ29asin(int32_t a)\n{\n    return __IQNasin(a, 29);\n}\n/**\n * @brief Computes the inverse sine of the IQ28 input.\n *\n * @param a               IQ28 type input.\n *\n * @return                IQ28 type result of inverse sine.\n */\nint32_t _IQ28asin(int32_t a)\n{\n    return __IQNasin(a, 28);\n}\n/**\n * @brief Computes the inverse sine of the IQ27 input.\n *\n * @param a               IQ27 type input.\n *\n * @return                IQ27 type result of inverse sine.\n */\nint32_t _IQ27asin(int32_t a)\n{\n    return __IQNasin(a, 27);\n}\n/**\n * @brief Computes the inverse sine of the IQ26 input.\n *\n * @param a               IQ26 type input.\n *\n * @return                IQ26 type result of inverse sine.\n */\nint32_t _IQ26asin(int32_t a)\n{\n    return __IQNasin(a, 26);\n}\n/**\n * @brief Computes the inverse sine of the IQ25 input.\n *\n * @param a               IQ25 type input.\n *\n * @return                IQ25 type result of inverse sine.\n */\nint32_t _IQ25asin(int32_t a)\n{\n    return __IQNasin(a, 25);\n}\n/**\n * @brief Computes the inverse sine of the IQ24 input.\n *\n * @param a               IQ24 type input.\n *\n * @return                IQ24 type result of inverse sine.\n */\nint32_t _IQ24asin(int32_t a)\n{\n    return __IQNasin(a, 24);\n}\n/**\n * @brief Computes the inverse sine of the IQ23 input.\n *\n * @param a               IQ23 type input.\n *\n * @return                IQ23 type result of inverse sine.\n */\nint32_t _IQ23asin(int32_t a)\n{\n    return __IQNasin(a, 23);\n}\n/**\n * @brief Computes the inverse sine of the IQ22 input.\n *\n * @param a               IQ22 type input.\n *\n * @return                IQ22 type result of inverse sine.\n */\nint32_t _IQ22asin(int32_t a)\n{\n    return __IQNasin(a, 22);\n}\n/**\n * @brief Computes the inverse sine of the IQ21 input.\n *\n * @param a               IQ21 type input.\n *\n * @return                IQ21 type result of inverse sine.\n */\nint32_t _IQ21asin(int32_t a)\n{\n    return __IQNasin(a, 21);\n}\n/**\n * @brief Computes the inverse sine of the IQ20 input.\n *\n * @param a               IQ20 type input.\n *\n * @return                IQ20 type result of inverse sine.\n */\nint32_t _IQ20asin(int32_t a)\n{\n    return __IQNasin(a, 20);\n}\n/**\n * @brief Computes the inverse sine of the IQ19 input.\n *\n * @param a               IQ19 type input.\n *\n * @return                IQ19 type result of inverse sine.\n */\nint32_t _IQ19asin(int32_t a)\n{\n    return __IQNasin(a, 19);\n}\n/**\n * @brief Computes the inverse sine of the IQ18 input.\n *\n * @param a               IQ18 type input.\n *\n * @return                IQ18 type result of inverse sine.\n */\nint32_t _IQ18asin(int32_t a)\n{\n    return __IQNasin(a, 18);\n}\n/**\n * @brief Computes the inverse sine of the IQ17 input.\n *\n * @param a               IQ17 type input.\n *\n * @return                IQ17 type result of inverse sine.\n */\nint32_t _IQ17asin(int32_t a)\n{\n    return __IQNasin(a, 17);\n}\n/**\n * @brief Computes the inverse sine of the IQ16 input.\n *\n * @param a               IQ16 type input.\n *\n * @return                IQ16 type result of inverse sine.\n */\nint32_t _IQ16asin(int32_t a)\n{\n    return __IQNasin(a, 16);\n}\n/**\n * @brief Computes the inverse sine of the IQ15 input.\n *\n * @param a               IQ15 type input.\n *\n * @return                IQ15 type result of inverse sine.\n */\nint32_t _IQ15asin(int32_t a)\n{\n    return __IQNasin(a, 15);\n}\n/**\n * @brief Computes the inverse sine of the IQ14 input.\n *\n * @param a               IQ14 type input.\n *\n * @return                IQ14 type result of inverse sine.\n */\nint32_t _IQ14asin(int32_t a)\n{\n    return __IQNasin(a, 14);\n}\n/**\n * @brief Computes the inverse sine of the IQ13 input.\n *\n * @param a               IQ13 type input.\n *\n * @return                IQ13 type result of inverse sine.\n */\nint32_t _IQ13asin(int32_t a)\n{\n    return __IQNasin(a, 13);\n}\n/**\n * @brief Computes the inverse sine of the IQ12 input.\n *\n * @param a               IQ12 type input.\n *\n * @return                IQ12 type result of inverse sine.\n */\nint32_t _IQ12asin(int32_t a)\n{\n    return __IQNasin(a, 12);\n}\n/**\n * @brief Computes the inverse sine of the IQ11 input.\n *\n * @param a               IQ11 type input.\n *\n * @return                IQ11 type result of inverse sine.\n */\nint32_t _IQ11asin(int32_t a)\n{\n    return __IQNasin(a, 11);\n}\n/**\n * @brief Computes the inverse sine of the IQ10 input.\n *\n * @param a               IQ10 type input.\n *\n * @return                IQ10 type result of inverse sine.\n */\nint32_t _IQ10asin(int32_t a)\n{\n    return __IQNasin(a, 10);\n}\n/**\n * @brief Computes the inverse sine of the IQ9 input.\n *\n * @param a               IQ9 type input.\n *\n * @return                IQ9 type result of inverse sine.\n */\nint32_t _IQ9asin(int32_t a)\n{\n    return __IQNasin(a, 9);\n}\n/**\n * @brief Computes the inverse sine of the IQ8 input.\n *\n * @param a               IQ8 type input.\n *\n * @return                IQ8 type result of inverse sine.\n */\nint32_t _IQ8asin(int32_t a)\n{\n    return __IQNasin(a, 8);\n}\n/**\n * @brief Computes the inverse sine of the IQ7 input.\n *\n * @param a               IQ7 type input.\n *\n * @return                IQ7 type result of inverse sine.\n */\nint32_t _IQ7asin(int32_t a)\n{\n    return __IQNasin(a, 7);\n}\n/**\n * @brief Computes the inverse sine of the IQ6 input.\n *\n * @param a               IQ6 type input.\n *\n * @return                IQ6 type result of inverse sine.\n */\nint32_t _IQ6asin(int32_t a)\n{\n    return __IQNasin(a, 6);\n}\n/**\n * @brief Computes the inverse sine of the IQ5 input.\n *\n * @param a               IQ5 type input.\n *\n * @return                IQ5 type result of inverse sine.\n */\nint32_t _IQ5asin(int32_t a)\n{\n    return __IQNasin(a, 5);\n}\n/**\n * @brief Computes the inverse sine of the IQ4 input.\n *\n * @param a               IQ4 type input.\n *\n * @return                IQ4 type result of inverse sine.\n */\nint32_t _IQ4asin(int32_t a)\n{\n    return __IQNasin(a, 4);\n}\n/**\n * @brief Computes the inverse sine of the IQ3 input.\n *\n * @param a               IQ3 type input.\n *\n * @return                IQ3 type result of inverse sine.\n */\nint32_t _IQ3asin(int32_t a)\n{\n    return __IQNasin(a, 3);\n}\n/**\n * @brief Computes the inverse sine of the IQ2 input.\n *\n * @param a               IQ2 type input.\n *\n * @return                IQ2 type result of inverse sine.\n */\nint32_t _IQ2asin(int32_t a)\n{\n    return __IQNasin(a, 2);\n}\n/**\n * @brief Computes the inverse sine of the IQ1 input.\n *\n * @param a               IQ1 type input.\n *\n * @return                IQ1 type result of inverse sine.\n */\nint32_t _IQ1asin(int32_t a)\n{\n    return __IQNasin(a, 1);\n}\n"
  },
  {
    "path": "iqmath/_IQNfunctions/_IQNatan2.c",
    "content": "/*!****************************************************************************\n *  @file       _IQNatan2.c\n *  @brief      Functions to compute the 4-quadrant arctangent of the input\n *              and return the result.\n *\n *  <hr>\n ******************************************************************************/\n\n#include <stdint.h>\n\n#include \"../support/support.h\"\n#include \"_IQNtables.h\"\n#include \"../include/IQmathLib.h\"\n#include \"_IQNmpy.h\"\n#include \"_IQNdiv.h\"\n\n/*!\n * @brief The value of PI\n */\n#define PI (3.1415926536)\n\n/*!\n * @brief Used to specify per-unit result\n */\n#define TYPE_PU         (0)\n/*!\n * @brief Used to specify result in radians\n */\n#define TYPE_RAD        (1)\n\n#if ((!defined (__IQMATH_USE_MATHACL__)) || (!defined (__MSPM0_HAS_MATHACL__)))\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\n/* Hidden _UIQ31div function. */\n/**\n * @brief Computes the division of the IQ31 inputs.\n *\n * @param uiq31Input1     IQ31 type value numerator to be divided.\n * @param uiq31Input2     IQ31 type value denominator to divide by.\n *\n * @return                IQ31 type result of division.\n */\nextern uint_fast32_t _UIQ31div(uint_fast32_t uiq31Input1, uint_fast32_t uiq31Input2);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Compute the 4-quadrant arctangent of the IQN input\n *        and return the result.\n *\n * @param iqNInputY       IQN type input y.\n * @param iqNInputX       IQN type input x.\n * @param type            Specifies radians or per-unit operation.\n * @param q_value         IQ format.\n *\n * @return                IQN type result of 4-quadrant arctangent.\n */\n/*\n * Calculate atan2 using a 3rd order Taylor series. The coefficients are stored\n * in a lookup table with 17 ranges to give an accuracy of XX bits.\n *\n * The input to the Taylor series is the ratio of the two inputs and must be\n * in the range of 0 <= input <= 1. If the y argument is larger than the x\n * argument we must apply the following transformation:\n *\n *     atan(y/x) = pi/2 - atan(x/y)\n */\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNatan2)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n__STATIC_INLINE int_fast32_t __IQNatan2(int_fast32_t iqNInputY, int_fast32_t iqNInputX, const uint8_t type, const int8_t q_value)\n{\n    uint8_t ui8Status = 0;\n    uint8_t ui8Index;\n    uint_fast16_t ui16IntState;\n    uint_fast16_t ui16MPYState;\n    uint_fast32_t uiqNInputX;\n    uint_fast32_t uiqNInputY;\n    uint_fast32_t uiq32ResultPU;\n    int_fast32_t iqNResult;\n    int_fast32_t iq29Result;\n    const int_fast32_t *piq32Coeffs;\n    uint_fast32_t uiq31Input;\n\n    /*\n     * Extract the sign from the inputs and set the following status bits:\n     *\n     *      ui8Status = xxxxxTQS\n     *      x = unused\n     *      T = transform was applied\n     *      Q = 2nd or 3rd quadrant (-x)\n     *      S = sign bit needs to be set (-y)\n     */\n    if (iqNInputY < 0) {\n        ui8Status |= 1;\n        iqNInputY = -iqNInputY;\n    }\n    if (iqNInputX < 0) {\n        ui8Status |= 2;\n        iqNInputX = -iqNInputX;\n    }\n\n    /* Save inputs to unsigned iqN formats. */\n    uiqNInputX = (uint_fast32_t)iqNInputX;\n    uiqNInputY = (uint_fast32_t)iqNInputY;\n\n    /*\n     * Calculate the ratio of the inputs in iq31. When using the iq31 div\n     * functions with inputs of matching type the result will be iq31:\n     *\n     *     iq31 = _IQ31div(iqN, iqN);\n     */\n    if (uiqNInputX < uiqNInputY) {\n        ui8Status |= 4;\n        uiq31Input = _UIQ31div(uiqNInputX, uiqNInputY);\n    } else {\n        uiq31Input = _UIQ31div(uiqNInputY, uiqNInputX);\n    }\n\n    /* Calculate the index using the left 8 most bits of the input. */\n    ui8Index = (uint_fast16_t)(uiq31Input >> 24);\n    ui8Index = ui8Index & 0x00fc;\n\n    /* Set the coefficient pointer. */\n    piq32Coeffs = &_IQ32atan_coeffs[ui8Index];\n\n    /*\n     * Mark the start of any multiplies. This will disable interrupts and set\n     * the multiplier to fractional mode. This is designed to reduce overhead\n     * of constantly switching states when using repeated multiplies (MSP430\n     * only).\n     */\n    __mpyf_start(&ui16IntState, &ui16MPYState);\n\n    /*\n     * Calculate atan(x) using the following Taylor series:\n     *\n     *     atan(x) = ((c3*x + c2)*x + c1)*x + c0\n     */\n\n    /* c3*x */\n    uiq32ResultPU = __mpyf_l(uiq31Input, *piq32Coeffs++);\n\n    /* c3*x + c2 */\n    uiq32ResultPU = uiq32ResultPU + *piq32Coeffs++;\n\n    /* (c3*x + c2)*x */\n    uiq32ResultPU = __mpyf_l(uiq31Input, uiq32ResultPU);\n\n    /* (c3*x + c2)*x + c1 */\n    uiq32ResultPU = uiq32ResultPU + *piq32Coeffs++;\n\n    /* ((c3*x + c2)*x + c1)*x */\n    uiq32ResultPU = __mpyf_l(uiq31Input, uiq32ResultPU);\n\n    /* ((c3*x + c2)*x + c1)*x + c0 */\n    uiq32ResultPU = uiq32ResultPU + *piq32Coeffs++;\n\n    /* Check if we applied the transformation. */\n    if (ui8Status & 4) {\n        /* atan(y/x) = pi/2 - uiq32ResultPU */\n        uiq32ResultPU = (uint32_t)(0x40000000 - uiq32ResultPU);\n    }\n\n    /* Check if the result needs to be mirrored to the 2nd/3rd quadrants. */\n    if (ui8Status & 2) {\n        /* atan(y/x) = pi - uiq32ResultPU */\n        uiq32ResultPU = (uint32_t)(0x80000000 - uiq32ResultPU);\n    }\n\n    /* Round and convert result to correct format (radians/PU and iqN type). */\n    if (type == TYPE_PU) {\n        uiq32ResultPU += (uint_fast32_t)1 << (31 - q_value);\n        iqNResult = uiq32ResultPU >> (32 - q_value);\n    } else {\n        /*\n         * Multiply the per-unit result by 2*pi:\n         *\n         *     iq31mpy(iq32, iq28) = iq29\n         */\n        iq29Result = __mpyf_l(uiq32ResultPU, iq28_twoPi);\n\n        /* Only round IQ formats < 29 */\n        if (q_value < 29) {\n            iq29Result += (uint_fast32_t)1 << (28 - q_value);\n        }\n        iqNResult = iq29Result >> (29 - q_value);\n    }\n\n    /*\n     * Mark the end of all multiplies. This restores MPY and interrupt states\n     * (MSP430 only).\n     */\n    __mpy_stop(&ui16IntState, &ui16MPYState);\n\n    /* Set the sign bit and result to correct quadrant. */\n    if (ui8Status & 1) {\n        return -iqNResult;\n    } else {\n        return iqNResult;\n    }\n}\n#else\n/**\n * @brief Compute the 4-quadrant arctangent of the IQN input\n *        and return the result, using MathACL.\n *\n * @param iqNInputY       IQN type input y.\n * @param iqNInputX       IQN type input x.\n * @param type            Specifies radians or per-unit operation.\n * @param q_value         IQ format.\n *\n * @return                IQN type result of 4-quadrant arctangent.\n */\n/* Calculate atan2 using MATHACL */\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNatan2)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n\n__STATIC_INLINE int_fast32_t __IQNatan2(int_fast32_t iqNInputY, int_fast32_t iqNInputX, const uint8_t type, const int8_t q_value)\n{\n    int_fast32_t res, res1, abs_max, temp;\n    int_fast32_t iqNnormX, iqNnormY, iq31normX, iq31normY;\n    /* ATAN2 Operation with MatchACL requires X,Y input values to be IQ31.\n     * Therefore, we need to normalize the input values.\n     */\n\n    /* Normalize input values by using the largest abs max input value */\n    /* Code for _IQXabs is the same for all Q values */\n    if (_IQabs(iqNInputY) > _IQabs(iqNInputX)) {\n        abs_max = _IQabs(iqNInputY);\n    } else {\n        abs_max = _IQabs(iqNInputX);\n    }\n\n    /* Both inputs are 0 */\n    if (abs_max == 0) {\n        return 0;\n    }\n\n    /* IQ31 doesn't support 1.0. Therefore, we need to ensure the normalized\n     * values are not equal to 1 but rather slightly below 1.0.\n     */\n\n    /* Check to see if abs_max is equal to the max value\n     * represented by the specified Q value (0x7FFFFFFFF) being represented.\n     * This will determine which approach is taken to ensure abs_max is > than\n     * the abs value of either inputs when normalization is performed.\n     */\n    if (abs_max == 0x7FFFFFFF) {\n        /* We want to represent as close as .999999 that we can for a given\n         * q value. Therefore we want to go to the number slightly lower than\n         * 1 for the given q value.\n         */\n        temp = (1 << q_value) - 1;\n\n        /* Scale down the inputs slightly so we ensure that abs_max is slightly\n         * larger than the abs value of the inputs.\n         */\n        iqNInputX = __IQNmpy(iqNInputX, temp, q_value);\n        iqNInputY = __IQNmpy(iqNInputY, temp, q_value);\n    } else {\n        /* The decimal value 1 is the smallest positive value for a given IQ.\n         * So by adding this to our variable we are using to normalize we\n         * ensure the resulting normalized values are < 1.0.\n         */\n        abs_max += 1;\n    }\n\n    /* Normalize Inputs */\n    iqNnormX = __IQNdiv_MathACL(iqNInputX, abs_max, q_value);\n    iqNnormY = __IQNdiv_MathACL(iqNInputY, abs_max, q_value);\n\n    /* Shift from IQX to IQ31 which is required for MathACL ATAN2 operation */\n    iq31normX = (uint_fast32_t)iqNnormX << (31 - q_value);\n    iq31normY = (uint_fast32_t)iqNnormY << (31 - q_value);\n\n    /* MathACL ATAN2 Operation */\n    MATHACL->CTL = 2 | (31 << 24);\n    /* write operands to HWA */\n    MATHACL->OP2 = iq31normY;\n    /* write to OP1 is the trigger */\n    MATHACL->OP1 = iq31normX;\n\n    /* read atan2 */\n    res1 = MATHACL->RES1;\n    /* Shift from IQ31 to IQ28 for result scaling */\n    res = res1 >> (3);\n    /* Round and convert result to correct format (radians/PU and iqN type). */\n    if (type == TYPE_PU) {\n        /* IQ28(2.0) = 0x20000000 in int32 */\n        res = _IQ28div(res, 0x20000000);\n    } else {\n        /* IQ28(PI) = 0x3243F6A8 in int32 */\n        res = _IQ28mpy(0x3243F6A8, res);\n    }\n    /* Shift to q_value type */\n    if (q_value < 28) {\n        res = res >> (28 - q_value);\n    } else {\n        res = res << (q_value - 28);\n    }\n\n    return res;\n}\n#endif\n\n/* ATAN2 */\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ29 input\n *        and return the result, in radians.\n *\n * @param y               IQ29 type input y.\n * @param x               IQ29 type input x.\n *\n * @return                IQ29 type result of 4-quadrant arctangent.\n */\nint32_t _IQ29atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 29);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ28 input\n *        and return the result, in radians.\n *\n * @param y               IQ28 type input y.\n * @param x               IQ28 type input x.\n *\n * @return                IQ28 type result of 4-quadrant arctangent.\n */\nint32_t _IQ28atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 28);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ27 input\n *        and return the result, in radians.\n *\n * @param y               IQ27 type input y.\n * @param x               IQ27 type input x.\n *\n * @return                IQ27 type result of 4-quadrant arctangent.\n */\nint32_t _IQ27atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 27);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ26 input\n *        and return the result, in radians.\n *\n * @param y               IQ26 type input y.\n * @param x               IQ26 type input x.\n *\n * @return                IQ26 type result of 4-quadrant arctangent.\n */\nint32_t _IQ26atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 26);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ25 input\n *        and return the result, in radians.\n *\n * @param y               IQ25 type input y.\n * @param x               IQ25 type input x.\n *\n * @return                IQ25 type result of 4-quadrant arctangent.\n */\nint32_t _IQ25atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 25);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ24 input\n *        and return the result, in radians.\n *\n * @param y               IQ24 type input y.\n * @param x               IQ24 type input x.\n *\n * @return                IQ24 type result of 4-quadrant arctangent.\n */\nint32_t _IQ24atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 24);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ23 input\n *        and return the result, in radians.\n *\n * @param y               IQ23 type input y.\n * @param x               IQ23 type input x.\n *\n * @return                IQ23 type result of 4-quadrant arctangent.\n */\nint32_t _IQ23atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 23);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ22 input\n *        and return the result, in radians.\n *\n * @param y               IQ22 type input y.\n * @param x               IQ22 type input x.\n *\n * @return                IQ22 type result of 4-quadrant arctangent.\n */\nint32_t _IQ22atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 22);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ21 input\n *        and return the result, in radians.\n *\n * @param y               IQ21 type input y.\n * @param x               IQ21 type input x.\n *\n * @return                IQ21 type result of 4-quadrant arctangent.\n */\nint32_t _IQ21atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 21);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ20 input\n *        and return the result, in radians.\n *\n * @param y               IQ20 type input y.\n * @param x               IQ20 type input x.\n *\n * @return                IQ20 type result of 4-quadrant arctangent.\n */\nint32_t _IQ20atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 20);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ19 input\n *        and return the result, in radians.\n *\n * @param y               IQ19 type input y.\n * @param x               IQ19 type input x.\n *\n * @return                IQ19 type result of 4-quadrant arctangent.\n */\nint32_t _IQ19atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 19);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ18 input\n *        and return the result, in radians.\n *\n * @param y               IQ18 type input y.\n * @param x               IQ18 type input x.\n *\n * @return                IQ18 type result of 4-quadrant arctangent.\n */\nint32_t _IQ18atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 18);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ17 input\n *        and return the result, in radians.\n *\n * @param y               IQ17 type input y.\n * @param x               IQ17 type input x.\n *\n * @return                IQ17 type result of 4-quadrant arctangent.\n */\nint32_t _IQ17atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 17);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ16 input\n *        and return the result, in radians.\n *\n * @param y               IQ16 type input y.\n * @param x               IQ16 type input x.\n *\n * @return                IQ16 type result of 4-quadrant arctangent.\n */\nint32_t _IQ16atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 16);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ15 input\n *        and return the result, in radians.\n *\n * @param y               IQ15 type input y.\n * @param x               IQ15 type input x.\n *\n * @return                IQ15 type result of 4-quadrant arctangent.\n */\nint32_t _IQ15atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 15);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ14 input\n *        and return the result, in radians.\n *\n * @param y               IQ14 type input y.\n * @param x               IQ14 type input x.\n *\n * @return                IQ14 type result of 4-quadrant arctangent.\n */\nint32_t _IQ14atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 14);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ13 input\n *        and return the result, in radians.\n *\n * @param y               IQ13 type input y.\n * @param x               IQ13 type input x.\n *\n * @return                IQ13 type result of 4-quadrant arctangent.\n */\nint32_t _IQ13atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 13);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ12 input\n *        and return the result, in radians.\n *\n * @param y               IQ12 type input y.\n * @param x               IQ12 type input x.\n *\n * @return                IQ12 type result of 4-quadrant arctangent.\n */\nint32_t _IQ12atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 12);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ11 input\n *        and return the result, in radians.\n *\n * @param y               IQ11 type input y.\n * @param x               IQ11 type input x.\n *\n * @return                IQ11 type result of 4-quadrant arctangent.\n */\nint32_t _IQ11atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 11);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ10 input\n *        and return the result, in radians.\n *\n * @param y               IQ10 type input y.\n * @param x               IQ10 type input x.\n *\n * @return                IQ10 type result of 4-quadrant arctangent.\n */\nint32_t _IQ10atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 10);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ9 input\n *        and return the result, in radians.\n *\n * @param y               IQ9 type input y.\n * @param x               IQ9 type input x.\n *\n * @return                IQ9 type result of 4-quadrant arctangent.\n */\nint32_t _IQ9atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 9);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ8 input\n *        and return the result, in radians.\n *\n * @param y               IQ8 type input y.\n * @param x               IQ8 type input x.\n *\n * @return                IQ8 type result of 4-quadrant arctangent.\n */\nint32_t _IQ8atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 8);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ7 input\n *        and return the result, in radians.\n *\n * @param y               IQ7 type input y.\n * @param x               IQ7 type input x.\n *\n * @return                IQ7 type result of 4-quadrant arctangent.\n */\nint32_t _IQ7atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 7);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ6 input\n *        and return the result, in radians.\n *\n * @param y               IQ6 type input y.\n * @param x               IQ6 type input x.\n *\n * @return                IQ6 type result of 4-quadrant arctangent.\n */\nint32_t _IQ6atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 6);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ5 input\n *        and return the result, in radians.\n *\n * @param y               IQ5 type input y.\n * @param x               IQ5 type input x.\n *\n * @return                IQ5 type result of 4-quadrant arctangent.\n */\nint32_t _IQ5atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 5);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ4 input\n *        and return the result, in radians.\n *\n * @param y               IQ4 type input y.\n * @param x               IQ4 type input x.\n *\n * @return                IQ4 type result of 4-quadrant arctangent.\n */\nint32_t _IQ4atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 4);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ3 input\n *        and return the result, in radians.\n *\n * @param y               IQ3 type input y.\n * @param x               IQ3 type input x.\n *\n * @return                IQ3 type result of 4-quadrant arctangent.\n */\nint32_t _IQ3atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 3);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ2 input\n *        and return the result, in radians.\n *\n * @param y               IQ2 type input y.\n * @param x               IQ2 type input x.\n *\n * @return                IQ2 type result of 4-quadrant arctangent.\n */\nint32_t _IQ2atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 2);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ1 input\n *        and return the result, in radians.\n *\n * @param y               IQ1 type input y.\n * @param x               IQ1 type input x.\n *\n * @return                IQ1 type result of 4-quadrant arctangent.\n */\nint32_t _IQ1atan2(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_RAD, 1);\n}\n\n/* ATAN2PU */\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ31 input\n *        and return the result.\n *\n * @param y               IQ31 type input y.\n * @param x               IQ31 type input x.\n *\n * @return                IQ31 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ31atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 31);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ30 input\n *        and return the result.\n *\n * @param y               IQ30 type input y.\n * @param x               IQ30 type input x.\n *\n * @return                IQ30 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ30atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 30);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ29 input\n *        and return the result.\n *\n * @param y               IQ29 type input y.\n * @param x               IQ29 type input x.\n *\n * @return                IQ29 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ29atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 29);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ28 input\n *        and return the result.\n *\n * @param y               IQ28 type input y.\n * @param x               IQ28 type input x.\n *\n * @return                IQ28 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ28atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 28);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ27 input\n *        and return the result.\n *\n * @param y               IQ27 type input y.\n * @param x               IQ27 type input x.\n *\n * @return                IQ27 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ27atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 27);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ26 input\n *        and return the result.\n *\n * @param y               IQ26 type input y.\n * @param x               IQ26 type input x.\n *\n * @return                IQ26 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ26atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 26);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ25 input\n *        and return the result.\n *\n * @param y               IQ25 type input y.\n * @param x               IQ25 type input x.\n *\n * @return                IQ25 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ25atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 25);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ24 input\n *        and return the result.\n *\n * @param y               IQ24 type input y.\n * @param x               IQ24 type input x.\n *\n * @return                IQ24 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ24atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 24);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ23 input\n *        and return the result.\n *\n * @param y               IQ23 type input y.\n * @param x               IQ23 type input x.\n *\n * @return                IQ23 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ23atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 23);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ22 input\n *        and return the result.\n *\n * @param y               IQ22 type input y.\n * @param x               IQ22 type input x.\n *\n * @return                IQ22 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ22atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 22);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ21 input\n *        and return the result.\n *\n * @param y               IQ21 type input y.\n * @param x               IQ21 type input x.\n *\n * @return                IQ21 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ21atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 21);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ20 input\n *        and return the result.\n *\n * @param y               IQ20 type input y.\n * @param x               IQ20 type input x.\n *\n * @return                IQ20 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ20atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 20);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ19 input\n *        and return the result.\n *\n * @param y               IQ19 type input y.\n * @param x               IQ19 type input x.\n *\n * @return                IQ19 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ19atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 19);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ18 input\n *        and return the result.\n *\n * @param y               IQ18 type input y.\n * @param x               IQ18 type input x.\n *\n * @return                IQ18 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ18atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 18);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ17 input\n *        and return the result.\n *\n * @param y               IQ17 type input y.\n * @param x               IQ17 type input x.\n *\n * @return                IQ17 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ17atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 17);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ16 input\n *        and return the result.\n *\n * @param y               IQ16 type input y.\n * @param x               IQ16 type input x.\n *\n * @return                IQ16 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ16atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 16);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ15 input\n *        and return the result.\n *\n * @param y               IQ15 type input y.\n * @param x               IQ15 type input x.\n *\n * @return                IQ15 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ15atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 15);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ14 input\n *        and return the result.\n *\n * @param y               IQ14 type input y.\n * @param x               IQ14 type input x.\n *\n * @return                IQ14 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ14atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 14);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ13 input\n *        and return the result.\n *\n * @param y               IQ13 type input y.\n * @param x               IQ13 type input x.\n *\n * @return                IQ13 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ13atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 13);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ12 input\n *        and return the result.\n *\n * @param y               IQ12 type input y.\n * @param x               IQ12 type input x.\n *\n * @return                IQ12 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ12atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 12);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ11 input\n *        and return the result.\n *\n * @param y               IQ11 type input y.\n * @param x               IQ11 type input x.\n *\n * @return                IQ11 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ11atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 11);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ10 input\n *        and return the result.\n *\n * @param y               IQ10 type input y.\n * @param x               IQ10 type input x.\n *\n * @return                IQ10 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ10atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 10);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ9 input\n *        and return the result.\n *\n * @param y               IQ9 type input y.\n * @param x               IQ9 type input x.\n *\n * @return                IQ9 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ9atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 9);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ8 input\n *        and return the result.\n *\n * @param y               IQ8 type input y.\n * @param x               IQ8 type input x.\n *\n * @return                IQ8 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ8atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 8);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ7 input\n *        and return the result.\n *\n * @param y               IQ7 type input y.\n * @param x               IQ7 type input x.\n *\n * @return                IQ7 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ7atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 7);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ6 input\n *        and return the result.\n *\n * @param y               IQ6 type input y.\n * @param x               IQ6 type input x.\n *\n * @return                IQ6 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ6atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 6);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ5 input\n *        and return the result.\n *\n * @param y               IQ5 type input y.\n * @param x               IQ5 type input x.\n *\n * @return                IQ5 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ5atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 5);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ4 input\n *        and return the result.\n *\n * @param y               IQ4 type input y.\n * @param x               IQ4 type input x.\n *\n * @return                IQ4 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ4atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 4);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ3 input\n *        and return the result.\n *\n * @param y               IQ3 type input y.\n * @param x               IQ3 type input x.\n *\n * @return                IQ3 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ3atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 3);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ2 input\n *        and return the result.\n *\n * @param y               IQ2 type input y.\n * @param x               IQ2 type input x.\n *\n * @return                IQ2 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ2atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 2);\n}\n/**\n * @brief Compute the 4-quadrant arctangent of the IQ1 input\n *        and return the result.\n *\n * @param y               IQ1 type input y.\n * @param x               IQ1 type input x.\n *\n * @return                IQ1 type per-unit result of 4-quadrant arctangent.\n */\nint32_t _IQ1atan2PU(int32_t y, int32_t x)\n{\n    return __IQNatan2(y, x, TYPE_PU, 1);\n}\n"
  },
  {
    "path": "iqmath/_IQNfunctions/_IQNdiv.c",
    "content": "#include \"_IQNdiv.h\"\n\n/* RTS Functions */\n#if ((!defined (__IQMATH_USE_MATHACL__)) || (!defined (__MSPM0_HAS_MATHACL__)))\n/**\n * @brief Divides two values of IQ31 format.\n *\n * @param a             IQ31 type value numerator to be divided.\n * @param b             IQ31 type value denominator to divide by.\n *\n * @return              IQ31 type result of the multiplication.\n */\nint32_t _IQ31div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 31);\n}\n/**\n * @brief Divides two values of IQ30 format.\n *\n * @param a             IQ30 type value numerator to be divided.\n * @param b             IQ30 type value denominator to divide by.\n *\n * @return              IQ30 type result of the multiplication.\n */\nint32_t _IQ30div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 30);\n}\n/**\n * @brief Divides two values of IQ29 format.\n *\n * @param a             IQ29 type value numerator to be divided.\n * @param b             IQ29 type value denominator to divide by.\n *\n * @return              IQ29 type result of the multiplication.\n */\nint32_t _IQ29div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 29);\n}\n/**\n * @brief Divides two values of IQ28 format.\n *\n * @param a             IQ28 type value numerator to be divided.\n * @param b             IQ28 type value denominator to divide by.\n *\n * @return              IQ28 type result of the multiplication.\n */\nint32_t _IQ28div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 28);\n}\n/**\n * @brief Divides two values of IQ27 format.\n *\n * @param a             IQ27 type value numerator to be divided.\n * @param b             IQ27 type value denominator to divide by.\n *\n * @return              IQ27 type result of the multiplication.\n */\nint32_t _IQ27div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 27);\n}\n/**\n * @brief Divides two values of IQ26 format.\n *\n * @param a             IQ26 type value numerator to be divided.\n * @param b             IQ26 type value denominator to divide by.\n *\n * @return              IQ26 type result of the multiplication.\n */\nint32_t _IQ26div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 26);\n}\n/**\n * @brief Divides two values of IQ25 format.\n *\n * @param a             IQ25 type value numerator to be divided.\n * @param b             IQ25 type value denominator to divide by.\n *\n * @return              IQ25 type result of the multiplication.\n */\nint32_t _IQ25div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 25);\n}\n/**\n * @brief Divides two values of IQ24 format.\n *\n * @param a             IQ24 type value numerator to be divided.\n * @param b             IQ24 type value denominator to divide by.\n *\n * @return              IQ24 type result of the multiplication.\n */\nint32_t _IQ24div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 24);\n}\n/**\n * @brief Divides two values of IQ23 format.\n *\n * @param a             IQ23 type value numerator to be divided.\n * @param b             IQ23 type value denominator to divide by.\n *\n * @return              IQ23 type result of the multiplication.\n */\nint32_t _IQ23div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 23);\n}\n/**\n * @brief Divides two values of IQ22 format.\n *\n * @param a             IQ22 type value numerator to be divided.\n * @param b             IQ22 type value denominator to divide by.\n *\n * @return              IQ22 type result of the multiplication.\n */\nint32_t _IQ22div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 22);\n}\n/**\n * @brief Divides two values of IQ21 format.\n *\n * @param a             IQ21 type value numerator to be divided.\n * @param b             IQ21 type value denominator to divide by.\n *\n * @return              IQ21 type result of the multiplication.\n */\nint32_t _IQ21div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 21);\n}\n/**\n * @brief Divides two values of IQ20 format.\n *\n * @param a             IQ20 type value numerator to be divided.\n * @param b             IQ20 type value denominator to divide by.\n *\n * @return              IQ20 type result of the multiplication.\n */\nint32_t _IQ20div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 20);\n}\n/**\n * @brief Divides two values of IQ19 format.\n *\n * @param a             IQ19 type value numerator to be divided.\n * @param b             IQ19 type value denominator to divide by.\n *\n * @return              IQ19 type result of the multiplication.\n */\nint32_t _IQ19div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 19);\n}\n/**\n * @brief Divides two values of IQ18 format.\n *\n * @param a             IQ18 type value numerator to be divided.\n * @param b             IQ18 type value denominator to divide by.\n *\n * @return              IQ18 type result of the multiplication.\n */\nint32_t _IQ18div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 18);\n}\n/**\n * @brief Divides two values of IQ17 format.\n *\n * @param a             IQ17 type value numerator to be divided.\n * @param b             IQ17 type value denominator to divide by.\n *\n * @return              IQ17 type result of the multiplication.\n */\nint32_t _IQ17div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 17);\n}\n/**\n * @brief Divides two values of IQ16 format.\n *\n * @param a             IQ16 type value numerator to be divided.\n * @param b             IQ16 type value denominator to divide by.\n *\n * @return              IQ16 type result of the multiplication.\n */\nint32_t _IQ16div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 16);\n}\n/**\n * @brief Divides two values of IQ15 format.\n *\n * @param a             IQ15 type value numerator to be divided.\n * @param b             IQ15 type value denominator to divide by.\n *\n * @return              IQ15 type result of the multiplication.\n */\nint32_t _IQ15div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 15);\n}\n/**\n * @brief Divides two values of IQ14 format.\n *\n * @param a             IQ14 type value numerator to be divided.\n * @param b             IQ14 type value denominator to divide by.\n *\n * @return              IQ14 type result of the multiplication.\n */\nint32_t _IQ14div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 14);\n}\n/**\n * @brief Divides two values of IQ13 format.\n *\n * @param a             IQ13 type value numerator to be divided.\n * @param b             IQ13 type value denominator to divide by.\n *\n * @return              IQ13 type result of the multiplication.\n */\nint32_t _IQ13div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 13);\n}\n/**\n * @brief Divides two values of IQ12 format.\n *\n * @param a             IQ12 type value numerator to be divided.\n * @param b             IQ12 type value denominator to divide by.\n *\n * @return              IQ12 type result of the multiplication.\n */\nint32_t _IQ12div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 12);\n}\n/**\n * @brief Divides two values of IQ11 format.\n *\n * @param a             IQ11 type value numerator to be divided.\n * @param b             IQ11 type value denominator to divide by.\n *\n * @return              IQ11 type result of the multiplication.\n */\nint32_t _IQ11div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 11);\n}\n/**\n * @brief Divides two values of IQ10 format.\n *\n * @param a             IQ10 type value numerator to be divided.\n * @param b             IQ10 type value denominator to divide by.\n *\n * @return              IQ10 type result of the multiplication.\n */\nint32_t _IQ10div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 10);\n}\n/**\n * @brief Divides two values of IQ9 format.\n *\n * @param a             IQ9 type value numerator to be divided.\n * @param b             IQ9 type value denominator to divide by.\n *\n * @return              IQ9 type result of the multiplication.\n */\nint32_t _IQ9div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 9);\n}\n/**\n * @brief Divides two values of IQ8 format.\n *\n * @param a             IQ8 type value numerator to be divided.\n * @param b             IQ8 type value denominator to divide by.\n *\n * @return              IQ8 type result of the multiplication.\n */\nint32_t _IQ8div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 8);\n}\n/**\n * @brief Divides two values of IQ7 format.\n *\n * @param a             IQ7 type value numerator to be divided.\n * @param b             IQ7 type value denominator to divide by.\n *\n * @return              IQ7 type result of the multiplication.\n */\nint32_t _IQ7div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 7);\n}\n/**\n * @brief Divides two values of IQ6 format.\n *\n * @param a             IQ6 type value numerator to be divided.\n * @param b             IQ6 type value denominator to divide by.\n *\n * @return              IQ6 type result of the multiplication.\n */\nint32_t _IQ6div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 6);\n}\n/**\n * @brief Divides two values of IQ5 format.\n *\n * @param a             IQ5 type value numerator to be divided.\n * @param b             IQ5 type value denominator to divide by.\n *\n * @return              IQ5 type result of the multiplication.\n */\nint32_t _IQ5div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 5);\n}\n/**\n * @brief Divides two values of IQ4 format.\n *\n * @param a             IQ4 type value numerator to be divided.\n * @param b             IQ4 type value denominator to divide by.\n *\n * @return              IQ4 type result of the multiplication.\n */\nint32_t _IQ4div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 4);\n}\n/**\n * @brief Divides two values of IQ3 format.\n *\n * @param a             IQ3 type value numerator to be divided.\n * @param b             IQ3 type value denominator to divide by.\n *\n * @return              IQ3 type result of the multiplication.\n */\nint32_t _IQ3div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 3);\n}\n/**\n * @brief Divides two values of IQ2 format.\n *\n * @param a             IQ2 type value numerator to be divided.\n * @param b             IQ2 type value denominator to divide by.\n *\n * @return              IQ2 type result of the multiplication.\n */\nint32_t _IQ2div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 2);\n}\n/**\n * @brief Divides two values of IQ1 format.\n *\n * @param a             IQ1 type value numerator to be divided.\n * @param b             IQ1 type value denominator to divide by.\n *\n * @return              IQ1 type result of the multiplication.\n */\nint32_t _IQ1div(int32_t a, int32_t b)\n{\n    return __IQNdiv(a, b, TYPE_DEFAULT, 1);\n}\n/* MathACL Functions */\n#else\n/**\n * @brief Divides two values of IQ31 format, using MathACL\n *\n * @param a             IQ31 type value numerator to be divided.\n * @param b             IQ31 type value denominator to divide by.\n *\n * @return              IQ31 type result of the multiplication.\n */\nint32_t _IQ31div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 31);\n}\n/**\n * @brief Divides two values of IQ30 format, using MathACL\n *\n * @param a             IQ30 type value numerator to be divided.\n * @param b             IQ30 type value denominator to divide by.\n *\n * @return              IQ30 type result of the multiplication.\n */\nint32_t _IQ30div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 30);\n}\n/**\n * @brief Divides two values of IQ29 format, using MathACL\n *\n * @param a             IQ29 type value numerator to be divided.\n * @param b             IQ29 type value denominator to divide by.\n *\n * @return              IQ29 type result of the multiplication.\n */\nint32_t _IQ29div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 29);\n}\n/**\n * @brief Divides two values of IQ28 format, using MathACL\n *\n * @param a             IQ28 type value numerator to be divided.\n * @param b             IQ28 type value denominator to divide by.\n *\n * @return              IQ28 type result of the multiplication.\n */\nint32_t _IQ28div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 28);\n}\n/**\n * @brief Divides two values of IQ27 format, using MathACL\n *\n * @param a             IQ27 type value numerator to be divided.\n * @param b             IQ27 type value denominator to divide by.\n *\n * @return              IQ27 type result of the multiplication.\n */\nint32_t _IQ27div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 27);\n}\n/**\n * @brief Divides two values of IQ26 format, using MathACL\n *\n * @param a             IQ26 type value numerator to be divided.\n * @param b             IQ26 type value denominator to divide by.\n *\n * @return              IQ26 type result of the multiplication.\n */\nint32_t _IQ26div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 26);\n}\n/**\n * @brief Divides two values of IQ25 format, using MathACL\n *\n * @param a             IQ25 type value numerator to be divided.\n * @param b             IQ25 type value denominator to divide by.\n *\n * @return              IQ25 type result of the multiplication.\n */\nint32_t _IQ25div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 25);\n}\n/**\n * @brief Divides two values of IQ24 format, using MathACL\n *\n * @param a             IQ24 type value numerator to be divided.\n * @param b             IQ24 type value denominator to divide by.\n *\n * @return              IQ24 type result of the multiplication.\n */\nint32_t _IQ24div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 24);\n}\n/**\n * @brief Divides two values of IQ23 format, using MathACL\n *\n * @param a             IQ23 type value numerator to be divided.\n * @param b             IQ23 type value denominator to divide by.\n *\n * @return              IQ23 type result of the multiplication.\n */\nint32_t _IQ23div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 23);\n}\n/**\n * @brief Divides two values of IQ22 format, using MathACL\n *\n * @param a             IQ22 type value numerator to be divided.\n * @param b             IQ22 type value denominator to divide by.\n *\n * @return              IQ22 type result of the multiplication.\n */\nint32_t _IQ22div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 22);\n}\n/**\n * @brief Divides two values of IQ21 format, using MathACL\n *\n * @param a             IQ21 type value numerator to be divided.\n * @param b             IQ21 type value denominator to divide by.\n *\n * @return              IQ21 type result of the multiplication.\n */\nint32_t _IQ21div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 21);\n}\n/**\n * @brief Divides two values of IQ20 format, using MathACL\n *\n * @param a             IQ20 type value numerator to be divided.\n * @param b             IQ20 type value denominator to divide by.\n *\n * @return              IQ20 type result of the multiplication.\n */\nint32_t _IQ20div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 20);\n}\n/**\n * @brief Divides two values of IQ19 format, using MathACL\n *\n * @param a             IQ19 type value numerator to be divided.\n * @param b             IQ19 type value denominator to divide by.\n *\n * @return              IQ19 type result of the multiplication.\n */\nint32_t _IQ19div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 19);\n}\n/**\n * @brief Divides two values of IQ18 format, using MathACL\n *\n * @param a             IQ18 type value numerator to be divided.\n * @param b             IQ18 type value denominator to divide by.\n *\n * @return              IQ18 type result of the multiplication.\n */\nint32_t _IQ18div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 18);\n}\n/**\n * @brief Divides two values of IQ17 format, using MathACL\n *\n * @param a             IQ17 type value numerator to be divided.\n * @param b             IQ17 type value denominator to divide by.\n *\n * @return              IQ17 type result of the multiplication.\n */\nint32_t _IQ17div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 17);\n}\n/**\n * @brief Divides two values of IQ16 format, using MathACL\n *\n * @param a             IQ16 type value numerator to be divided.\n * @param b             IQ16 type value denominator to divide by.\n *\n * @return              IQ16 type result of the multiplication.\n */\nint32_t _IQ16div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 16);\n}\n/**\n * @brief Divides two values of IQ15 format, using MathACL\n *\n * @param a             IQ15 type value numerator to be divided.\n * @param b             IQ15 type value denominator to divide by.\n *\n * @return              IQ15 type result of the multiplication.\n */\nint32_t _IQ15div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 15);\n}\n/**\n * @brief Divides two values of IQ14 format, using MathACL\n *\n * @param a             IQ14 type value numerator to be divided.\n * @param b             IQ14 type value denominator to divide by.\n *\n * @return              IQ14 type result of the multiplication.\n */\nint32_t _IQ14div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 14);\n}\n/**\n * @brief Divides two values of IQ13 format, using MathACL\n *\n * @param a             IQ13 type value numerator to be divided.\n * @param b             IQ13 type value denominator to divide by.\n *\n * @return              IQ13 type result of the multiplication.\n */\nint32_t _IQ13div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 13);\n}\n/**\n * @brief Divides two values of IQ12 format, using MathACL\n *\n * @param a             IQ12 type value numerator to be divided.\n * @param b             IQ12 type value denominator to divide by.\n *\n * @return              IQ12 type result of the multiplication.\n */\nint32_t _IQ12div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 12);\n}\n/**\n * @brief Divides two values of IQ11 format, using MathACL\n *\n * @param a             IQ11 type value numerator to be divided.\n * @param b             IQ11 type value denominator to divide by.\n *\n * @return              IQ11 type result of the multiplication.\n */\nint32_t _IQ11div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 11);\n}\n/**\n * @brief Divides two values of IQ10 format, using MathACL\n *\n * @param a             IQ10 type value numerator to be divided.\n * @param b             IQ10 type value denominator to divide by.\n *\n * @return              IQ10 type result of the multiplication.\n */\nint32_t _IQ10div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 10);\n}\n/**\n * @brief Divides two values of IQ9 format, using MathACL\n *\n * @param a             IQ9 type value numerator to be divided.\n * @param b             IQ9 type value denominator to divide by.\n *\n * @return              IQ9 type result of the multiplication.\n */\nint32_t _IQ9div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 9);\n}\n/**\n * @brief Divides two values of IQ8 format, using MathACL\n *\n * @param a             IQ8 type value numerator to be divided.\n * @param b             IQ8 type value denominator to divide by.\n *\n * @return              IQ8 type result of the multiplication.\n */\nint32_t _IQ8div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 8);\n}\n/**\n * @brief Divides two values of IQ7 format, using MathACL\n *\n * @param a             IQ7 type value numerator to be divided.\n * @param b             IQ7 type value denominator to divide by.\n *\n * @return              IQ7 type result of the multiplication.\n */\nint32_t _IQ7div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 7);\n}\n/**\n * @brief Divides two values of IQ6 format, using MathACL\n *\n * @param a             IQ6 type value numerator to be divided.\n * @param b             IQ6 type value denominator to divide by.\n *\n * @return              IQ6 type result of the multiplication.\n */\nint32_t _IQ6div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 6);\n}\n/**\n * @brief Divides two values of IQ5 format, using MathACL\n *\n * @param a             IQ5 type value numerator to be divided.\n * @param b             IQ5 type value denominator to divide by.\n *\n * @return              IQ5 type result of the multiplication.\n */\nint32_t _IQ5div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 5);\n}\n/**\n * @brief Divides two values of IQ4 format, using MathACL\n *\n * @param a             IQ4 type value numerator to be divided.\n * @param b             IQ4 type value denominator to divide by.\n *\n * @return              IQ4 type result of the multiplication.\n */\nint32_t _IQ4div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 4);\n}\n/**\n * @brief Divides two values of IQ3 format, using MathACL\n *\n * @param a             IQ3 type value numerator to be divided.\n * @param b             IQ3 type value denominator to divide by.\n *\n * @return              IQ3 type result of the multiplication.\n */\nint32_t _IQ3div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 3);\n}\n/**\n * @brief Divides two values of IQ2 format, using MathACL\n *\n * @param a             IQ2 type value numerator to be divided.\n * @param b             IQ2 type value denominator to divide by.\n *\n * @return              IQ2 type result of the multiplication.\n */\nint32_t _IQ2div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 2);\n}\n/**\n * @brief Divides two values of IQ1 format, using MathACL\n *\n * @param a             IQ1 type value numerator to be divided.\n * @param b             IQ1 type value denominator to divide by.\n *\n * @return              IQ1 type result of the multiplication.\n */\nint32_t _IQ1div(int32_t a, int32_t b)\n{\n    return __IQNdiv_MathACL(a, b, 1);\n}\n#endif\n\n/* Hidden unsigned uiq31 divide without sign checks, used for atan2. */\n/**\n * @brief Divides two values of IQ31 format, without sign checks.\n *\n * @param a             IQ31 type value numerator to be divided.\n * @param b             IQ31 type value denominator to divide by.\n *\n * @return              IQ31 type result of the multiplication.\n */\nuint32_t _UIQ31div(uint32_t a, uint32_t b)\n{\n    return __IQNdiv(a, b, TYPE_UNSIGNED, 31);\n}\n"
  },
  {
    "path": "iqmath/_IQNfunctions/_IQNdiv.h",
    "content": "/*!****************************************************************************\n *  @file       _IQNdiv.c\n *  @brief      Functions to divide two values of IQN type.\n *\n *  <hr>\n ******************************************************************************/\n\n#ifndef ti_iq_iqndiv__include\n#define ti_iq_iqndiv__include\n#include <stdint.h>\n\n#include \"../support/support.h\"\n#include \"_IQNtables.h\"\n\n/*!\n * @brief Used to specify signed division on IQNdiv\n */\n#define TYPE_DEFAULT    (0)\n/*!\n * @brief Used to specify unsigned division on IQNdiv\n */\n#define TYPE_UNSIGNED   (1)\n\n/**\n * @brief Divide two values of IQN type\n *\n * @param iqNInput1       IQN type value numerator to be divided.\n * @param iqNInput2       IQN type value denominator to divide by.\n * @param type            Specify operation is signed or unsigned.\n * @param q_value         IQ format.\n *\n * @return                IQN type result of the multiplication.\n */\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNdiv)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n__STATIC_INLINE int_fast32_t __IQNdiv(int_fast32_t iqNInput1, int_fast32_t iqNInput2, const uint8_t type, const int8_t q_value)\n{\n    uint8_t ui8Index, ui8Sign = 0;\n    uint_fast32_t ui32Temp;\n    uint_fast32_t uiq30Guess;\n    uint_fast32_t uiqNInput1;\n    uint_fast32_t uiqNInput2;\n    uint_fast32_t uiqNResult;\n    uint_fast64_t uiiqNInput1;\n    uint_fast16_t ui16IntState;\n    uint_fast16_t ui16MPYState;\n\n    if (type == TYPE_DEFAULT) {\n        /* save sign of denominator */\n        if (iqNInput2 <= 0) {\n            /* check for divide by zero */\n            if (iqNInput2 == 0) {\n                return INT32_MAX;\n            } else {\n                ui8Sign = 1;\n                iqNInput2 = -iqNInput2;\n            }\n        }\n\n        /* save sign of numerator */\n        if (iqNInput1 < 0) {\n            ui8Sign ^= 1;\n            iqNInput1 = -iqNInput1;\n        }\n    } else {\n        /* Check for divide by zero */\n        if (iqNInput2 == 0) {\n            return INT32_MAX;\n        }\n    }\n\n    /* Save input1 and input2 to unsigned IQN and IIQN (64-bit). */\n    uiiqNInput1 = (uint_fast64_t)iqNInput1;\n    uiqNInput2 = (uint_fast32_t)iqNInput2;\n\n    /* Scale inputs so that 0.5 <= uiqNInput2 < 1.0. */\n    while (uiqNInput2 < 0x40000000) {\n        uiqNInput2 <<= 1;\n        uiiqNInput1 <<= 1;\n    }\n\n    /*\n     * Shift input1 back from iq31 to iqN but scale by 2 since we multiply\n     * by result in iq30 format.\n     */\n    if (q_value < 31) {\n        uiiqNInput1 >>= (31 - q_value - 1);\n    } else {\n        uiiqNInput1 <<= 1;\n    }\n\n    /* Check for saturation. */\n    if (uiiqNInput1 >> 32) {\n        if (ui8Sign) {\n            return INT32_MIN;\n        } else {\n            return INT32_MAX;\n        }\n    } else {\n        uiqNInput1 = (uint_fast32_t)uiiqNInput1;\n    }\n\n    /* use left most 7 bits as ui8Index into lookup table (range: 32-64) */\n    ui8Index = uiqNInput2 >> 24;\n    ui8Index -= 64;\n    uiq30Guess = (uint_fast32_t)_IQ6div_lookup[ui8Index] << 24;\n\n    /*\n     * Mark the start of any multiplies. This will disable interrupts and set\n     * the multiplier to fractional mode. This is designed to reduce overhead\n     * of constantly switching states when using repeated multiplies (MSP430\n     * only).\n     */\n    __mpyf_start(&ui16IntState, &ui16MPYState);\n\n    /* 1st iteration */\n    ui32Temp = __mpyf_ul(uiq30Guess, uiqNInput2);\n    ui32Temp = -((uint_fast32_t)ui32Temp - 0x80000000);\n    ui32Temp = ui32Temp << 1;\n    uiq30Guess = __mpyf_ul_reuse_arg1(uiq30Guess, ui32Temp);\n\n    /* 2nd iteration */\n    ui32Temp = __mpyf_ul(uiq30Guess, uiqNInput2);\n    ui32Temp = -((uint_fast32_t)ui32Temp - 0x80000000);\n    ui32Temp = ui32Temp << 1;\n    uiq30Guess = __mpyf_ul_reuse_arg1(uiq30Guess, ui32Temp);\n\n    /* 3rd iteration */\n    ui32Temp = __mpyf_ul(uiq30Guess, uiqNInput2);\n    ui32Temp = -((uint_fast32_t)ui32Temp - 0x80000000);\n    ui32Temp = ui32Temp << 1;\n    uiq30Guess = __mpyf_ul_reuse_arg1(uiq30Guess, ui32Temp);\n\n    /* Multiply 1/uiqNInput2 and uiqNInput1. */\n    uiqNResult = __mpyf_ul(uiq30Guess, uiqNInput1);\n\n    /*\n     * Mark the end of all multiplies. This restores MPY and interrupt states\n     * (MSP430 only).\n     */\n    __mpy_stop(&ui16IntState, &ui16MPYState);\n\n    /* Saturate, add the sign and return. */\n    if (type == TYPE_DEFAULT) {\n        if (uiqNResult > INT32_MAX) {\n            if (ui8Sign) {\n                return INT32_MIN;\n            } else {\n                return INT32_MAX;\n            }\n        } else {\n            if (ui8Sign) {\n                return -(int_fast32_t)uiqNResult;\n            } else {\n                return (int_fast32_t)uiqNResult;\n            }\n        }\n    } else {\n        return uiqNResult;\n    }\n}\n// TODO: unless we find a different use for it, or we are intending to keep same params as RTS function, I see no use for TYPE here.\n#if ((defined (__IQMATH_USE_MATHACL__)) && (defined (__MSPM0_HAS_MATHACL__)))\n/**\n * @brief Divide two values of IQN type, using MathACL\n *\n * @param iqNInput1       IQN type value numerator to be divided.\n * @param iqNInput2       IQN type value denominator to divide by.\n * @param q_value         IQ format.\n *\n * @return                IQN type result of the multiplication.\n */\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNdiv_MathACL)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n__STATIC_INLINE int_fast32_t __IQNdiv_MathACL(int_fast32_t iqNInput1, int_fast32_t iqNInput2, const int8_t q_value)\n{\n    /* write control */\n    MATHACL->CTL = 4 | (q_value << 8) | (1 << 5);\n    /* write operands to HWA. OP2 = divisor, OP1 = dividend */\n    MATHACL->OP2 = iqNInput2;\n    /* trigger is write to OP1 */\n    MATHACL->OP1 = iqNInput1;\n    /* read quotient and remainder */\n    return MATHACL->RES1;\n}\n#endif\n#endif"
  },
  {
    "path": "iqmath/_IQNfunctions/_IQNexp.c",
    "content": "/*!****************************************************************************\n *  @file       _IQNexp.c\n *  @brief      Functions to compute the exponential of the input\n *              and return the result.\n *\n *  <hr>\n ******************************************************************************/\n\n#include <stdint.h>\n\n#include \"../support/support.h\"\n#include \"_IQNtables.h\"\n\n/**\n * @brief Computes the exponential of an IQN input.\n *\n * @param iqNInput          IQN type input.\n * @param iqNLookupTable    Integer result lookup table.\n * @param ui8IntegerOffset  Integer portion offset\n * @param iqN_MIN           Minimum parameter value.\n * @param iqN_MAX           Maximum parameter value.\n * @param q_value           IQ format.\n *\n *\n * @return                  IQN type result of exponential.\n */\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNexp)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n__STATIC_INLINE int_fast32_t __IQNexp(int_fast32_t iqNInput, const uint_fast32_t *iqNLookupTable, uint8_t ui8IntegerOffset, const int_fast32_t iqN_MIN, const int_fast32_t iqN_MAX, const int8_t q_value)\n{\n    uint8_t ui8Count;\n    int_fast16_t i16Integer;\n    uint_fast16_t ui16IntState;\n    uint_fast16_t ui16MPYState;\n    int_fast32_t iq31Fractional;\n    uint_fast32_t uiqNResult;\n    uint_fast32_t uiqNIntegerResult;\n    uint_fast32_t uiq30FractionalResult;\n    uint_fast32_t uiq31FractionalResult;\n    const uint_fast32_t *piq30Coeffs;\n\n    /* Input is negative. */\n    if (iqNInput < 0) {\n        /* Check for the minimum value. */\n        if (iqNInput < iqN_MIN) {\n            return 0;\n        }\n\n        /* Extract the fractional portion in iq31 and set sign bit. */\n        iq31Fractional = iqNInput;\n        iq31Fractional <<= (31 - q_value);\n        iq31Fractional |= 0x80000000;\n\n        /* Extract the integer portion. */\n        i16Integer = (int_fast16_t)(iqNInput >> q_value) + 1;\n\n        /* Offset the integer portion and lookup the integer result. */\n        i16Integer += ui8IntegerOffset;\n        uiqNIntegerResult = iqNLookupTable[i16Integer];\n\n        /* Reduce the fractional portion to -ln(2) < iq31Fractional < 0 */\n        if (iq31Fractional <= -iq31_ln2) {\n            iq31Fractional += iq31_ln2;\n            uiqNIntegerResult >>= 1;\n        }\n    }\n    /* Input is positive. */\n    else {\n        /* Check for the maximum value. */\n        if (iqNInput > iqN_MAX) {\n            return INT32_MAX;\n        }\n\n        /* Extract the fractional portion in iq31 and clear sign bit. */\n        iq31Fractional = iqNInput;\n        iq31Fractional <<= (31 - q_value);\n        iq31Fractional &= 0x7fffffff;\n\n        /* Extract the integer portion. */\n        i16Integer = (int_fast16_t)(iqNInput >> q_value);\n\n        /* Offset the integer portion and lookup the integer result. */\n        i16Integer += ui8IntegerOffset;\n        uiqNIntegerResult = iqNLookupTable[i16Integer];\n\n        /* Reduce the fractional portion to 0 < iq31Fractional < ln(2) */\n        if (iq31Fractional >= iq31_ln2) {\n            iq31Fractional -= iq31_ln2;\n            uiqNIntegerResult <<= 1;\n        }\n    }\n\n    /*\n     * Mark the start of any multiplies. This will disable interrupts and set\n     * the multiplier to fractional mode. This is designed to reduce overhead\n     * of constantly switching states when using repeated multiplies (MSP430\n     * only).\n     */\n    __mpyf_start(&ui16IntState, &ui16MPYState);\n\n    /*\n     * Initialize the coefficient pointer to the Taylor Series iq30 coefficients\n     * for the exponential functions. Set the iq30 result to the first\n     * coefficient in the table.\n     */\n    piq30Coeffs = _IQ30exp_coeffs;\n    uiq30FractionalResult = *piq30Coeffs++;\n\n    /* Compute exp^(iq31Fractional). */\n    for (ui8Count = _IQ30exp_order; ui8Count > 0; ui8Count--) {\n        uiq30FractionalResult = __mpyf_l(iq31Fractional, uiq30FractionalResult);\n        uiq30FractionalResult += *piq30Coeffs++;\n    }\n\n    /* Scale the iq30 fractional result by to iq31. */\n    uiq31FractionalResult = uiq30FractionalResult << 1;\n\n    /*\n     * Multiply the integer result in iqN format and the fractional result in\n     * iq31 format to obtain the result in iqN format.\n     */\n    uiqNResult = __mpyf_ul(uiqNIntegerResult, uiq31FractionalResult);\n\n    /*\n     * Mark the end of all multiplies. This restores MPY and interrupt states\n     * (MSP430 only).\n     */\n    __mpy_stop(&ui16IntState, &ui16MPYState);\n\n    /* The result is scaled by 2, round the result and scale to iqN format. */\n    uiqNResult++;\n    uiqNResult >>= 1;\n\n    return uiqNResult;\n}\n\n/**\n * @brief Computes the exponential of an IQ30 input.\n *\n * @param a               IQ30 type input.\n *\n * @return                IQ30 type result of exponential.\n */\nint32_t _IQ30exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup30, _IQNexp_offset[30 - 1], _IQNexp_min[30 - 1], _IQNexp_max[30 - 1], 30);\n}\n/**\n * @brief Computes the exponential of an IQ29 input.\n *\n * @param a               IQ29 type input.\n *\n * @return                IQ29 type result of exponential.\n */\nint32_t _IQ29exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup29, _IQNexp_offset[29 - 1], _IQNexp_min[29 - 1], _IQNexp_max[29 - 1], 29);\n}\n/**\n * @brief Computes the exponential of an IQ28 input.\n *\n * @param a               IQ28 type input.\n *\n * @return                IQ28 type result of exponential.\n */\nint32_t _IQ28exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup28, _IQNexp_offset[28 - 1], _IQNexp_min[28 - 1], _IQNexp_max[28 - 1], 28);\n}\n/**\n * @brief Computes the exponential of an IQ27 input.\n *\n * @param a               IQ27 type input.\n *\n * @return                IQ27 type result of exponential.\n */\nint32_t _IQ27exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup27, _IQNexp_offset[27 - 1], _IQNexp_min[27 - 1], _IQNexp_max[27 - 1], 27);\n}\n/**\n * @brief Computes the exponential of an IQ26 input.\n *\n * @param a               IQ26 type input.\n *\n * @return                IQ26 type result of exponential.\n */\nint32_t _IQ26exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup26, _IQNexp_offset[26 - 1], _IQNexp_min[26 - 1], _IQNexp_max[26 - 1], 26);\n}\n/**\n * @brief Computes the exponential of an IQ25 input.\n *\n * @param a               IQ25 type input.\n *\n * @return                IQ25 type result of exponential.\n */\nint32_t _IQ25exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup25, _IQNexp_offset[25 - 1], _IQNexp_min[25 - 1], _IQNexp_max[25 - 1], 25);\n}\n/**\n * @brief Computes the exponential of an IQ24 input.\n *\n * @param a               IQ24 type input.\n *\n * @return                IQ24 type result of exponential.\n */\nint32_t _IQ24exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup24, _IQNexp_offset[24 - 1], _IQNexp_min[24 - 1], _IQNexp_max[24 - 1], 24);\n}\n/**\n * @brief Computes the exponential of an IQ23 input.\n *\n * @param a               IQ23 type input.\n *\n * @return                IQ23 type result of exponential.\n */\nint32_t _IQ23exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup23, _IQNexp_offset[23 - 1], _IQNexp_min[23 - 1], _IQNexp_max[23 - 1], 23);\n}\n/**\n * @brief Computes the exponential of an IQ22 input.\n *\n * @param a               IQ22 type input.\n *\n * @return                IQ22 type result of exponential.\n */\nint32_t _IQ22exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup22, _IQNexp_offset[22 - 1], _IQNexp_min[22 - 1], _IQNexp_max[22 - 1], 22);\n}\n/**\n * @brief Computes the exponential of an IQ21 input.\n *\n * @param a               IQ21 type input.\n *\n * @return                IQ21 type result of exponential.\n */\nint32_t _IQ21exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup21, _IQNexp_offset[21 - 1], _IQNexp_min[21 - 1], _IQNexp_max[21 - 1], 21);\n}\n/**\n * @brief Computes the exponential of an IQ20 input.\n *\n * @param a               IQ20 type input.\n *\n * @return                IQ20 type result of exponential.\n */\nint32_t _IQ20exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup20, _IQNexp_offset[20 - 1], _IQNexp_min[20 - 1], _IQNexp_max[20 - 1], 20);\n}\n/**\n * @brief Computes the exponential of an IQ19 input.\n *\n * @param a               IQ19 type input.\n *\n * @return                IQ19 type result of exponential.\n */\nint32_t _IQ19exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup19, _IQNexp_offset[19 - 1], _IQNexp_min[19 - 1], _IQNexp_max[19 - 1], 19);\n}\n/**\n * @brief Computes the exponential of an IQ18 input.\n *\n * @param a               IQ18 type input.\n *\n * @return                IQ18 type result of exponential.\n */\nint32_t _IQ18exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup18, _IQNexp_offset[18 - 1], _IQNexp_min[18 - 1], _IQNexp_max[18 - 1], 18);\n}\n/**\n * @brief Computes the exponential of an IQ17 input.\n *\n * @param a               IQ17 type input.\n *\n * @return                IQ17 type result of exponential.\n */\nint32_t _IQ17exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup17, _IQNexp_offset[17 - 1], _IQNexp_min[17 - 1], _IQNexp_max[17 - 1], 17);\n}\n/**\n * @brief Computes the exponential of an IQ16 input.\n *\n * @param a               IQ16 type input.\n *\n * @return                IQ16 type result of exponential.\n */\nint32_t _IQ16exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup16, _IQNexp_offset[16 - 1], _IQNexp_min[16 - 1], _IQNexp_max[16 - 1], 16);\n}\n/**\n * @brief Computes the exponential of an IQ15 input.\n *\n * @param a               IQ15 type input.\n *\n * @return                IQ15 type result of exponential.\n */\nint32_t _IQ15exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup15, _IQNexp_offset[15 - 1], _IQNexp_min[15 - 1], _IQNexp_max[15 - 1], 15);\n}\n/**\n * @brief Computes the exponential of an IQ14 input.\n *\n * @param a               IQ14 type input.\n *\n * @return                IQ14 type result of exponential.\n */\nint32_t _IQ14exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup14, _IQNexp_offset[14 - 1], _IQNexp_min[14 - 1], _IQNexp_max[14 - 1], 14);\n}\n/**\n * @brief Computes the exponential of an IQ13 input.\n *\n * @param a               IQ13 type input.\n *\n * @return                IQ13 type result of exponential.\n */\nint32_t _IQ13exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup13, _IQNexp_offset[13 - 1], _IQNexp_min[13 - 1], _IQNexp_max[13 - 1], 13);\n}\n/**\n * @brief Computes the exponential of an IQ12 input.\n *\n * @param a               IQ12 type input.\n *\n * @return                IQ12 type result of exponential.\n */\nint32_t _IQ12exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup12, _IQNexp_offset[12 - 1], _IQNexp_min[12 - 1], _IQNexp_max[12 - 1], 12);\n}\n/**\n * @brief Computes the exponential of an IQ11 input.\n *\n * @param a               IQ11 type input.\n *\n * @return                IQ11 type result of exponential.\n */\nint32_t _IQ11exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup11, _IQNexp_offset[11 - 1], _IQNexp_min[11 - 1], _IQNexp_max[11 - 1], 11);\n}\n/**\n * @brief Computes the exponential of an IQ10 input.\n *\n * @param a               IQ10 type input.\n *\n * @return                IQ10 type result of exponential.\n */\nint32_t _IQ10exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup10, _IQNexp_offset[10 - 1], _IQNexp_min[10 - 1], _IQNexp_max[10 - 1], 10);\n}\n/**\n * @brief Computes the exponential of an IQ9 input.\n *\n * @param a               IQ9 type input.\n *\n * @return                IQ9 type result of exponential.\n */\nint32_t _IQ9exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup9, _IQNexp_offset[9 - 1], _IQNexp_min[9 - 1], _IQNexp_max[9 - 1], 9);\n}\n/**\n * @brief Computes the exponential of an IQ8 input.\n *\n * @param a               IQ8 type input.\n *\n * @return                IQ8 type result of exponential.\n */\nint32_t _IQ8exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup8, _IQNexp_offset[8 - 1], _IQNexp_min[8 - 1], _IQNexp_max[8 - 1], 8);\n}\n/**\n * @brief Computes the exponential of an IQ7 input.\n *\n * @param a               IQ7 type input.\n *\n * @return                IQ7 type result of exponential.\n */\nint32_t _IQ7exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup7, _IQNexp_offset[7 - 1], _IQNexp_min[7 - 1], _IQNexp_max[7 - 1], 7);\n}\n/**\n * @brief Computes the exponential of an IQ6 input.\n *\n * @param a               IQ6 type input.\n *\n * @return                IQ6 type result of exponential.\n */\nint32_t _IQ6exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup6, _IQNexp_offset[6 - 1], _IQNexp_min[6 - 1], _IQNexp_max[6 - 1], 6);\n}\n/**\n * @brief Computes the exponential of an IQ5 input.\n *\n * @param a               IQ5 type input.\n *\n * @return                IQ5 type result of exponential.\n */\nint32_t _IQ5exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup5, _IQNexp_offset[5 - 1], _IQNexp_min[5 - 1], _IQNexp_max[5 - 1], 5);\n}\n/**\n * @brief Computes the exponential of an IQ4 input.\n *\n * @param a               IQ4 type input.\n *\n * @return                IQ4 type result of exponential.\n */\nint32_t _IQ4exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup4, _IQNexp_offset[4 - 1], _IQNexp_min[4 - 1], _IQNexp_max[4 - 1], 4);\n}\n/**\n * @brief Computes the exponential of an IQ3 input.\n *\n * @param a               IQ3 type input.\n *\n * @return                IQ3 type result of exponential.\n */\nint32_t _IQ3exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup3, _IQNexp_offset[3 - 1], _IQNexp_min[3 - 1], _IQNexp_max[3 - 1], 3);\n}\n/**\n * @brief Computes the exponential of an IQ2 input.\n *\n * @param a               IQ2 type input.\n *\n * @return                IQ2 type result of exponential.\n */\nint32_t _IQ2exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup2, _IQNexp_offset[2 - 1], _IQNexp_min[2 - 1], _IQNexp_max[2 - 1], 2);\n}\n/**\n * @brief Computes the exponential of an IQ1 input.\n *\n * @param a               IQ1 type input.\n *\n * @return                IQ1 type result of exponential.\n */\nint32_t _IQ1exp(int32_t a)\n{\n    return __IQNexp(a, _IQNexp_lookup1, _IQNexp_offset[1 - 1], _IQNexp_min[1 - 1], _IQNexp_max[1 - 1], 1);\n}\n"
  },
  {
    "path": "iqmath/_IQNfunctions/_IQNfrac.c",
    "content": "/*!****************************************************************************\n *  @file       _IQNfrac.c\n *  @brief      Functions to return the fractional portion of the input.\n *\n *  <hr>\n ******************************************************************************/\n\n#include <stdint.h>\n\n#include \"../support/support.h\"\n\n/**\n * @brief Return the fractional portion of an IQN input.\n *\n * @param iqNInput        IQN type input.\n * @param q_value         IQ format.\n *\n * @return                IQN type fractional portion of input.\n */\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNfrac)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n__STATIC_INLINE int_fast32_t __IQNfrac(int_fast32_t iqNInput, int8_t q_value)\n{\n    int_fast32_t iqNInteger;\n\n    iqNInteger = (uint_fast32_t)iqNInput & ((uint_fast32_t)0xffffffff << q_value);\n\n    return (iqNInput - iqNInteger);\n}\n\n/**\n * @brief Return the fractional portion of an IQ30 input.\n *\n * @param a               IQ30 type input.\n *\n * @return                IQ30 type fractional portion of input.\n */\nint32_t _IQ30frac(int32_t a)\n{\n    return __IQNfrac(a, 30);\n}\n/**\n * @brief Return the fractional portion of an IQ29 input.\n *\n * @param a               IQ29 type input.\n *\n * @return                IQ29 type fractional portion of input.\n */\nint32_t _IQ29frac(int32_t a)\n{\n    return __IQNfrac(a, 29);\n}\n/**\n * @brief Return the fractional portion of an IQ28 input.\n *\n * @param a               IQ28 type input.\n *\n * @return                IQ28 type fractional portion of input.\n */\nint32_t _IQ28frac(int32_t a)\n{\n    return __IQNfrac(a, 28);\n}\n/**\n * @brief Return the fractional portion of an IQ27 input.\n *\n * @param a               IQ27 type input.\n *\n * @return                IQ27 type fractional portion of input.\n */\nint32_t _IQ27frac(int32_t a)\n{\n    return __IQNfrac(a, 27);\n}\n/**\n * @brief Return the fractional portion of an IQ26 input.\n *\n * @param a               IQ26 type input.\n *\n * @return                IQ26 type fractional portion of input.\n */\nint32_t _IQ26frac(int32_t a)\n{\n    return __IQNfrac(a, 26);\n}\n/**\n * @brief Return the fractional portion of an IQ25 input.\n *\n * @param a               IQ25 type input.\n *\n * @return                IQ25 type fractional portion of input.\n */\nint32_t _IQ25frac(int32_t a)\n{\n    return __IQNfrac(a, 25);\n}\n/**\n * @brief Return the fractional portion of an IQ24 input.\n *\n * @param a               IQ24 type input.\n *\n * @return                IQ24 type fractional portion of input.\n */\nint32_t _IQ24frac(int32_t a)\n{\n    return __IQNfrac(a, 24);\n}\n/**\n * @brief Return the fractional portion of an IQ23 input.\n *\n * @param a               IQ23 type input.\n *\n * @return                IQ23 type fractional portion of input.\n */\nint32_t _IQ23frac(int32_t a)\n{\n    return __IQNfrac(a, 23);\n}\n/**\n * @brief Return the fractional portion of an IQ22 input.\n *\n * @param a               IQ22 type input.\n *\n * @return                IQ22 type fractional portion of input.\n */\nint32_t _IQ22frac(int32_t a)\n{\n    return __IQNfrac(a, 22);\n}\n/**\n * @brief Return the fractional portion of an IQ21 input.\n *\n * @param a               IQ21 type input.\n *\n * @return                IQ21 type fractional portion of input.\n */\nint32_t _IQ21frac(int32_t a)\n{\n    return __IQNfrac(a, 21);\n}\n/**\n * @brief Return the fractional portion of an IQ20 input.\n *\n * @param a               IQ20 type input.\n *\n * @return                IQ20 type fractional portion of input.\n */\nint32_t _IQ20frac(int32_t a)\n{\n    return __IQNfrac(a, 20);\n}\n/**\n * @brief Return the fractional portion of an IQ19 input.\n *\n * @param a               IQ19 type input.\n *\n * @return                IQ19 type fractional portion of input.\n */\nint32_t _IQ19frac(int32_t a)\n{\n    return __IQNfrac(a, 19);\n}\n/**\n * @brief Return the fractional portion of an IQ18 input.\n *\n * @param a               IQ18 type input.\n *\n * @return                IQ18 type fractional portion of input.\n */\nint32_t _IQ18frac(int32_t a)\n{\n    return __IQNfrac(a, 18);\n}\n/**\n * @brief Return the fractional portion of an IQ17 input.\n *\n * @param a               IQ17 type input.\n *\n * @return                IQ17 type fractional portion of input.\n */\nint32_t _IQ17frac(int32_t a)\n{\n    return __IQNfrac(a, 17);\n}\n/**\n * @brief Return the fractional portion of an IQ16 input.\n *\n * @param a               IQ16 type input.\n *\n * @return                IQ16 type fractional portion of input.\n */\nint32_t _IQ16frac(int32_t a)\n{\n    return __IQNfrac(a, 16);\n}\n/**\n * @brief Return the fractional portion of an IQ15 input.\n *\n * @param a               IQ15 type input.\n *\n * @return                IQ15 type fractional portion of input.\n */\nint32_t _IQ15frac(int32_t a)\n{\n    return __IQNfrac(a, 15);\n}\n/**\n * @brief Return the fractional portion of an IQ14 input.\n *\n * @param a               IQ14 type input.\n *\n * @return                IQ14 type fractional portion of input.\n */\nint32_t _IQ14frac(int32_t a)\n{\n    return __IQNfrac(a, 14);\n}\n/**\n * @brief Return the fractional portion of an IQ13 input.\n *\n * @param a               IQ13 type input.\n *\n * @return                IQ13 type fractional portion of input.\n */\nint32_t _IQ13frac(int32_t a)\n{\n    return __IQNfrac(a, 13);\n}\n/**\n * @brief Return the fractional portion of an IQ12 input.\n *\n * @param a               IQ12 type input.\n *\n * @return                IQ12 type fractional portion of input.\n */\nint32_t _IQ12frac(int32_t a)\n{\n    return __IQNfrac(a, 12);\n}\n/**\n * @brief Return the fractional portion of an IQ11 input.\n *\n * @param a               IQ11 type input.\n *\n * @return                IQ11 type fractional portion of input.\n */\nint32_t _IQ11frac(int32_t a)\n{\n    return __IQNfrac(a, 11);\n}\n/**\n * @brief Return the fractional portion of an IQ10 input.\n *\n * @param a               IQ10 type input.\n *\n * @return                IQ10 type fractional portion of input.\n */\nint32_t _IQ10frac(int32_t a)\n{\n    return __IQNfrac(a, 10);\n}\n/**\n * @brief Return the fractional portion of an IQ9 input.\n *\n * @param a               IQ9 type input.\n *\n * @return                IQ9 type fractional portion of input.\n */\nint32_t _IQ9frac(int32_t a)\n{\n    return __IQNfrac(a, 9);\n}\n/**\n * @brief Return the fractional portion of an IQ8 input.\n *\n * @param a               IQ8 type input.\n *\n * @return                IQ8 type fractional portion of input.\n */\nint32_t _IQ8frac(int32_t a)\n{\n    return __IQNfrac(a, 8);\n}\n/**\n * @brief Return the fractional portion of an IQ7 input.\n *\n * @param a               IQ7 type input.\n *\n * @return                IQ7 type fractional portion of input.\n */\nint32_t _IQ7frac(int32_t a)\n{\n    return __IQNfrac(a, 7);\n}\n/**\n * @brief Return the fractional portion of an IQ6 input.\n *\n * @param a               IQ6 type input.\n *\n * @return                IQ6 type fractional portion of input.\n */\nint32_t _IQ6frac(int32_t a)\n{\n    return __IQNfrac(a, 6);\n}\n/**\n * @brief Return the fractional portion of an IQ5 input.\n *\n * @param a               IQ5 type input.\n *\n * @return                IQ5 type fractional portion of input.\n */\nint32_t _IQ5frac(int32_t a)\n{\n    return __IQNfrac(a, 5);\n}\n/**\n * @brief Return the fractional portion of an IQ4 input.\n *\n * @param a               IQ4 type input.\n *\n * @return                IQ4 type fractional portion of input.\n */\nint32_t _IQ4frac(int32_t a)\n{\n    return __IQNfrac(a, 4);\n}\n/**\n * @brief Return the fractional portion of an IQ3 input.\n *\n * @param a               IQ3 type input.\n *\n * @return                IQ3 type fractional portion of input.\n */\nint32_t _IQ3frac(int32_t a)\n{\n    return __IQNfrac(a, 3);\n}\n/**\n * @brief Return the fractional portion of an IQ2 input.\n *\n * @param a               IQ2 type input.\n *\n * @return                IQ2 type fractional portion of input.\n */\nint32_t _IQ2frac(int32_t a)\n{\n    return __IQNfrac(a, 2);\n}\n/**\n * @brief Return the fractional portion of an IQ1 input.\n *\n * @param a               IQ1 type input.\n *\n * @return                IQ1 type fractional portion of input.\n */\nint32_t _IQ1frac(int32_t a)\n{\n    return __IQNfrac(a, 1);\n}\n"
  },
  {
    "path": "iqmath/_IQNfunctions/_IQNlog.c",
    "content": "/*!****************************************************************************\n *  @file       _IQNlog.c\n *  @brief      Functions to compute the base-e logarithm of an IQN number.\n *\n *  <hr>\n ******************************************************************************/\n\n\n#include <stdint.h>\n\n#include \"../support/support.h\"\n#include \"_IQNtables.h\"\n\n/**\n * @brief Computes the base-e logarithm of an IQN input.\n *\n * @param iqNInput          IQN type input.\n * @param iqNMin            Minimum parameter value.\n * @param q_value           IQ format.\n *\n * @return                  IQN type result of exponential.\n */\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNlog)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n__STATIC_INLINE int_fast32_t __IQNlog(int_fast32_t iqNInput, const int_fast32_t iqNMin, const int8_t q_value)\n{\n    uint8_t ui8Counter;\n    int_fast16_t i16Exp;\n    uint_fast16_t ui16IntState;\n    uint_fast16_t ui16MPYState;\n    int_fast32_t iqNResult;\n    int_fast32_t iq30Result;\n    uint_fast32_t uiq31Input;\n    const uint_fast32_t *piq30Coeffs;\n\n    /*\n     * Check the sign of the input and for negative saturation for q_values\n     * larger than iq26.\n     */\n    if (q_value > 26) {\n        if (iqNInput <= 0) {\n            return 0;\n        } else if (iqNInput <= iqNMin) {\n            return INT32_MIN;\n        }\n    }\n    /*\n     * Only check the sign of the input and that it is not equal to zero for\n     * q_values less than or equal to iq26.\n     */\n    else {\n        if (iqNInput <= 0) {\n            return 0;\n        }\n    }\n\n    /* Initialize the exponent value. */\n    i16Exp = (31 - q_value);\n\n    /*\n     * Scale the input so it is within the following range in iq31:\n     *\n     *     0.666666 < uiq31Input < 1.333333.\n     */\n    uiq31Input = (uint_fast32_t)iqNInput;\n    while (uiq31Input < iq31_twoThird) {\n        uiq31Input <<= 1;\n        i16Exp--;\n    }\n\n    /*\n     * Mark the start of any multiplies. This will disable interrupts and set\n     * the multiplier to fractional mode. This is designed to reduce overhead\n     * of constantly switching states when using repeated multiplies (MSP430\n     * only).\n     */\n    __mpyf_start(&ui16IntState, &ui16MPYState);\n\n    /*\n     * Initialize the coefficient pointer to the Taylor Series iq30 coefficients\n     * for the logarithm functions. Set the iq30 result to the first\n     * coefficient in the table. Subtract one from the iq31 input.\n     */\n    piq30Coeffs = _IQ30log_coeffs;\n    iq30Result = *piq30Coeffs++;\n    uiq31Input -= iq31_one;\n\n    /* Calculate log(uiq31Input) using the iq30 Taylor Series coefficients. */\n    for (ui8Counter = _IQ30log_order; ui8Counter > 0; ui8Counter--) {\n        iq30Result = __mpyf_l(uiq31Input, iq30Result);\n        iq30Result += *piq30Coeffs++;\n    }\n\n    /* Scale the iq30 result to match the function iq type. */\n    iqNResult = iq30Result >> (30 - q_value);\n\n    /*\n     * Add i16Exp * ln(2) to the iqN result. This will never saturate since we\n     * check for the minimum value at the start of the function. Negative\n     * exponents require separate handling to allow for an extra bit with the\n     * unsigned data type.\n     */\n    if (i16Exp > 0) {\n        iqNResult += __mpyf_ul(iq31_ln2, ((int_fast32_t)i16Exp << q_value));\n    } else {\n        iqNResult -= __mpyf_ul(iq31_ln2, (((uint_fast32_t) - i16Exp) << q_value));\n    }\n\n    /*\n     * Mark the end of all multiplies. This restores MPY and interrupt states\n     * (MSP430 only).\n     */\n    __mpy_stop(&ui16IntState, &ui16MPYState);\n\n    return iqNResult;\n}\n\n/**\n * @brief Computes the base-e logarithm of an IQ30 input.\n *\n * @param a                 IQ30 type input.\n *\n * @return                  IQ30 type result of exponential.\n */\nint32_t _IQ30log(int32_t a)\n{\n    return __IQNlog(a, _IQNlog_min[30 - 27], 30);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ29 input.\n *\n * @param a                 IQ29 type input.\n *\n * @return                  IQ29 type result of exponential.\n */\nint32_t _IQ29log(int32_t a)\n{\n    return __IQNlog(a, _IQNlog_min[29 - 27], 29);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ28 input.\n *\n * @param a                 IQ28 type input.\n *\n * @return                  IQ28 type result of exponential.\n */\nint32_t _IQ28log(int32_t a)\n{\n    return __IQNlog(a, _IQNlog_min[28 - 27], 28);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ27 input.\n *\n * @param a                 IQ27 type input.\n *\n * @return                  IQ27 type result of exponential.\n */\nint32_t _IQ27log(int32_t a)\n{\n    return __IQNlog(a, _IQNlog_min[27 - 27], 27);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ26 input.\n *\n * @param a                 IQ26 type input.\n *\n * @return                  IQ26 type result of exponential.\n */\nint32_t _IQ26log(int32_t a)\n{\n    return __IQNlog(a, 1, 26);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ25 input.\n *\n * @param a                 IQ25 type input.\n *\n * @return                  IQ25 type result of exponential.\n */\nint32_t _IQ25log(int32_t a)\n{\n    return __IQNlog(a, 1, 25);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ24 input.\n *\n * @param a                 IQ24 type input.\n *\n * @return                  IQ24 type result of exponential.\n */\nint32_t _IQ24log(int32_t a)\n{\n    return __IQNlog(a, 1, 24);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ23 input.\n *\n * @param a                 IQ23 type input.\n *\n * @return                  IQ23 type result of exponential.\n */\nint32_t _IQ23log(int32_t a)\n{\n    return __IQNlog(a, 1, 23);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ22 input.\n *\n * @param a                 IQ22 type input.\n *\n * @return                  IQ22 type result of exponential.\n */\nint32_t _IQ22log(int32_t a)\n{\n    return __IQNlog(a, 1, 22);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ21 input.\n *\n * @param a                 IQ21 type input.\n *\n * @return                  IQ21 type result of exponential.\n */\nint32_t _IQ21log(int32_t a)\n{\n    return __IQNlog(a, 1, 21);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ20 input.\n *\n * @param a                 IQ20 type input.\n *\n * @return                  IQ20 type result of exponential.\n */\nint32_t _IQ20log(int32_t a)\n{\n    return __IQNlog(a, 1, 20);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ19 input.\n *\n * @param a                 IQ19 type input.\n *\n * @return                  IQ19 type result of exponential.\n */\nint32_t _IQ19log(int32_t a)\n{\n    return __IQNlog(a, 1, 19);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ18 input.\n *\n * @param a                 IQ18 type input.\n *\n * @return                  IQ18 type result of exponential.\n */\nint32_t _IQ18log(int32_t a)\n{\n    return __IQNlog(a, 1, 18);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ17 input.\n *\n * @param a                 IQ17 type input.\n *\n * @return                  IQ17 type result of exponential.\n */\nint32_t _IQ17log(int32_t a)\n{\n    return __IQNlog(a, 1, 17);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ16 input.\n *\n * @param a                 IQ16 type input.\n *\n * @return                  IQ16 type result of exponential.\n */\nint32_t _IQ16log(int32_t a)\n{\n    return __IQNlog(a, 1, 16);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ15 input.\n *\n * @param a                 IQ15 type input.\n *\n * @return                  IQ15 type result of exponential.\n */\nint32_t _IQ15log(int32_t a)\n{\n    return __IQNlog(a, 1, 15);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ14 input.\n *\n * @param a                 IQ14 type input.\n *\n * @return                  IQ14 type result of exponential.\n */\nint32_t _IQ14log(int32_t a)\n{\n    return __IQNlog(a, 1, 14);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ13 input.\n *\n * @param a                 IQ13 type input.\n *\n * @return                  IQ13 type result of exponential.\n */\nint32_t _IQ13log(int32_t a)\n{\n    return __IQNlog(a, 1, 13);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ12 input.\n *\n * @param a                 IQ12 type input.\n *\n * @return                  IQ12 type result of exponential.\n */\nint32_t _IQ12log(int32_t a)\n{\n    return __IQNlog(a, 1, 12);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ11 input.\n *\n * @param a                 IQ11 type input.\n *\n * @return                  IQ11 type result of exponential.\n */\nint32_t _IQ11log(int32_t a)\n{\n    return __IQNlog(a, 1, 11);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ10 input.\n *\n * @param a                 IQ10 type input.\n *\n * @return                  IQ10 type result of exponential.\n */\nint32_t _IQ10log(int32_t a)\n{\n    return __IQNlog(a, 1, 10);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ9 input.\n *\n * @param a                 IQ9 type input.\n *\n * @return                  IQ9 type result of exponential.\n */\nint32_t _IQ9log(int32_t a)\n{\n    return __IQNlog(a, 1, 9);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ8 input.\n *\n * @param a                 IQ8 type input.\n *\n * @return                  IQ8 type result of exponential.\n */\nint32_t _IQ8log(int32_t a)\n{\n    return __IQNlog(a, 1, 8);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ7 input.\n *\n * @param a                 IQ7 type input.\n *\n * @return                  IQ7 type result of exponential.\n */\nint32_t _IQ7log(int32_t a)\n{\n    return __IQNlog(a, 1, 7);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ6 input.\n *\n * @param a                 IQ6 type input.\n *\n * @return                  IQ6 type result of exponential.\n */\nint32_t _IQ6log(int32_t a)\n{\n    return __IQNlog(a, 1, 6);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ5 input.\n *\n * @param a                 IQ5 type input.\n *\n * @return                  IQ5 type result of exponential.\n */\nint32_t _IQ5log(int32_t a)\n{\n    return __IQNlog(a, 1, 5);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ4 input.\n *\n * @param a                 IQ4 type input.\n *\n * @return                  IQ4 type result of exponential.\n */\nint32_t _IQ4log(int32_t a)\n{\n    return __IQNlog(a, 1, 4);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ3 input.\n *\n * @param a                 IQ3 type input.\n *\n * @return                  IQ3 type result of exponential.\n */\nint32_t _IQ3log(int32_t a)\n{\n    return __IQNlog(a, 1, 3);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ2 input.\n *\n * @param a                 IQ2 type input.\n *\n * @return                  IQ2 type result of exponential.\n */\nint32_t _IQ2log(int32_t a)\n{\n    return __IQNlog(a, 1, 2);\n}\n/**\n * @brief Computes the base-e logarithm of an IQ1 input.\n *\n * @param a                 IQ1 type input.\n *\n * @return                  IQ1 type result of exponential.\n */\nint32_t _IQ1log(int32_t a)\n{\n    return __IQNlog(a, 1, 1);\n}\n"
  },
  {
    "path": "iqmath/_IQNfunctions/_IQNmpy.c",
    "content": "/*!****************************************************************************\n *  @file       _IQNmpy.c\n *  @brief      Functions to multiply two values of IQN type.\n *\n *  <hr>\n ******************************************************************************/\n#include \"_IQNmpy.h\"\n\n/**\n * @brief Multiplies two values of IQ31 format.\n *\n * @param a             IQ31 type value to be multiplied.\n * @param b             IQ31 type value to be multiplied.\n *\n * @return              IQ31 type result of the multiplication.\n */\nint32_t _IQ31mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 31);\n}\n/**\n * @brief Multiplies two values of IQ30 format.\n *\n * @param a             IQ30 type value to be multiplied.\n * @param b             IQ30 type value to be multiplied.\n *\n * @return              IQ30 type result of the multiplication.\n */\nint32_t _IQ30mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 30);\n}\n/**\n * @brief Multiplies two values of IQ29 format.\n *\n * @param a             IQ29 type value to be multiplied.\n * @param b             IQ29 type value to be multiplied.\n *\n * @return              IQ29 type result of the multiplication.\n */\nint32_t _IQ29mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 29);\n}\n/**\n * @brief Multiplies two values of IQ28 format.\n *\n * @param a             IQ28 type value to be multiplied.\n * @param b             IQ28 type value to be multiplied.\n *\n * @return              IQ28 type result of the multiplication.\n */\nint32_t _IQ28mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 28);\n}\n/**\n * @brief Multiplies two values of IQ27 format.\n *\n * @param a             IQ27 type value to be multiplied.\n * @param b             IQ27 type value to be multiplied.\n *\n * @return              IQ27 type result of the multiplication.\n */\nint32_t _IQ27mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 27);\n}\n/**\n * @brief Multiplies two values of IQ26 format.\n *\n * @param a             IQ26 type value to be multiplied.\n * @param b             IQ26 type value to be multiplied.\n *\n * @return              IQ26 type result of the multiplication.\n */\nint32_t _IQ26mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 26);\n}\n/**\n * @brief Multiplies two values of IQ25 format.\n *\n * @param a             IQ25 type value to be multiplied.\n * @param b             IQ25 type value to be multiplied.\n *\n * @return              IQ25 type result of the multiplication.\n */\nint32_t _IQ25mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 25);\n}\n/**\n * @brief Multiplies two values of IQ24 format.\n *\n * @param a             IQ24 type value to be multiplied.\n * @param b             IQ24 type value to be multiplied.\n *\n * @return              IQ24 type result of the multiplication.\n */\nint32_t _IQ24mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 24);\n}\n/**\n * @brief Multiplies two values of IQ23 format.\n *\n * @param a             IQ23 type value to be multiplied.\n * @param b             IQ23 type value to be multiplied.\n *\n * @return              IQ23 type result of the multiplication.\n */\nint32_t _IQ23mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 23);\n}\n/**\n * @brief Multiplies two values of IQ22 format.\n *\n * @param a             IQ22 type value to be multiplied.\n * @param b             IQ22 type value to be multiplied.\n *\n * @return              IQ22 type result of the multiplication.\n */\nint32_t _IQ22mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 22);\n}\n/**\n * @brief Multiplies two values of IQ21 format.\n *\n * @param a             IQ21 type value to be multiplied.\n * @param b             IQ21 type value to be multiplied.\n *\n * @return              IQ21 type result of the multiplication.\n */\nint32_t _IQ21mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 21);\n}\n/**\n * @brief Multiplies two values of IQ20 format.\n *\n * @param a             IQ20 type value to be multiplied.\n * @param b             IQ20 type value to be multiplied.\n *\n * @return              IQ20 type result of the multiplication.\n */\nint32_t _IQ20mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 20);\n}\n/**\n * @brief Multiplies two values of IQ19 format.\n *\n * @param a             IQ19 type value to be multiplied.\n * @param b             IQ19 type value to be multiplied.\n *\n * @return              IQ19 type result of the multiplication.\n */\nint32_t _IQ19mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 19);\n}\n/**\n * @brief Multiplies two values of IQ18 format.\n *\n * @param a             IQ18 type value to be multiplied.\n * @param b             IQ18 type value to be multiplied.\n *\n * @return              IQ18 type result of the multiplication.\n */\nint32_t _IQ18mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 18);\n}\n/**\n * @brief Multiplies two values of IQ17 format.\n *\n * @param a             IQ17 type value to be multiplied.\n * @param b             IQ17 type value to be multiplied.\n *\n * @return              IQ17 type result of the multiplication.\n */\nint32_t _IQ17mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 17);\n}\n/**\n * @brief Multiplies two values of IQ16 format.\n *\n * @param a             IQ16 type value to be multiplied.\n * @param b             IQ16 type value to be multiplied.\n *\n * @return              IQ16 type result of the multiplication.\n */\nint32_t _IQ16mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 16);\n}\n/**\n * @brief Multiplies two values of IQ15 format.\n *\n * @param a             IQ15 type value to be multiplied.\n * @param b             IQ15 type value to be multiplied.\n *\n * @return              IQ15 type result of the multiplication.\n */\nint32_t _IQ15mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 15);\n}\n/**\n * @brief Multiplies two values of IQ14 format.\n *\n * @param a             IQ14 type value to be multiplied.\n * @param b             IQ14 type value to be multiplied.\n *\n * @return              IQ14 type result of the multiplication.\n */\nint32_t _IQ14mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 14);\n}\n/**\n * @brief Multiplies two values of IQ13 format.\n *\n * @param a             IQ13 type value to be multiplied.\n * @param b             IQ13 type value to be multiplied.\n *\n * @return              IQ13 type result of the multiplication.\n */\nint32_t _IQ13mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 13);\n}\n/**\n * @brief Multiplies two values of IQ12 format.\n *\n * @param a             IQ12 type value to be multiplied.\n * @param b             IQ12 type value to be multiplied.\n *\n * @return              IQ12 type result of the multiplication.\n */\nint32_t _IQ12mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 12);\n}\n/**\n * @brief Multiplies two values of IQ11 format.\n *\n * @param a             IQ11 type value to be multiplied.\n * @param b             IQ11 type value to be multiplied.\n *\n * @return              IQ11 type result of the multiplication.\n */\nint32_t _IQ11mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 11);\n}\n/**\n * @brief Multiplies two values of IQ10 format.\n *\n * @param a             IQ10 type value to be multiplied.\n * @param b             IQ10 type value to be multiplied.\n *\n * @return              IQ10 type result of the multiplication.\n */\nint32_t _IQ10mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 10);\n}\n/**\n * @brief Multiplies two values of IQ9 format.\n *\n * @param a             IQ9 type value to be multiplied.\n * @param b             IQ9 type value to be multiplied.\n *\n * @return              IQ9 type result of the multiplication.\n */\nint32_t _IQ9mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 9);\n}\n/**\n * @brief Multiplies two values of IQ8 format.\n *\n * @param a             IQ8 type value to be multiplied.\n * @param b             IQ8 type value to be multiplied.\n *\n * @return              IQ8 type result of the multiplication.\n */\nint32_t _IQ8mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 8);\n}\n/**\n * @brief Multiplies two values of IQ7 format.\n *\n * @param a             IQ7 type value to be multiplied.\n * @param b             IQ7 type value to be multiplied.\n *\n * @return              IQ7 type result of the multiplication.\n */\nint32_t _IQ7mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 7);\n}\n/**\n * @brief Multiplies two values of IQ6 format.\n *\n * @param a             IQ6 type value to be multiplied.\n * @param b             IQ6 type value to be multiplied.\n *\n * @return              IQ6 type result of the multiplication.\n */\nint32_t _IQ6mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 6);\n}\n/**\n * @brief Multiplies two values of IQ5 format.\n *\n * @param a             IQ5 type value to be multiplied.\n * @param b             IQ5 type value to be multiplied.\n *\n * @return              IQ5 type result of the multiplication.\n */\nint32_t _IQ5mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 5);\n}\n/**\n * @brief Multiplies two values of IQ4 format.\n *\n * @param a             IQ4 type value to be multiplied.\n * @param b             IQ4 type value to be multiplied.\n *\n * @return              IQ4 type result of the multiplication.\n */\nint32_t _IQ4mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 4);\n}\n/**\n * @brief Multiplies two values of IQ3 format.\n *\n * @param a             IQ3 type value to be multiplied.\n * @param b             IQ3 type value to be multiplied.\n *\n * @return              IQ3 type result of the multiplication.\n */\nint32_t _IQ3mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 3);\n}\n/**\n * @brief Multiplies two values of IQ2 format.\n *\n * @param a             IQ2 type value to be multiplied.\n * @param b             IQ2 type value to be multiplied.\n *\n * @return              IQ2 type result of the multiplication.\n */\nint32_t _IQ2mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 2);\n}\n/**\n * @brief Multiplies two values of IQ1 format.\n *\n * @param a             IQ1 type value to be multiplied.\n * @param b             IQ1 type value to be multiplied.\n *\n * @return              IQ1 type result of the multiplication.\n */\nint32_t _IQ1mpy(int32_t a, int32_t b)\n{\n    return __IQNmpy(a, b, 1);\n}\n"
  },
  {
    "path": "iqmath/_IQNfunctions/_IQNmpy.h",
    "content": "/*!****************************************************************************\n *  @file       _IQNmpy.c\n *  @brief      Functions to multiply two values of IQN type.\n *\n *  <hr>\n ******************************************************************************/\n#ifndef ti_iq_iqnmpy__include\n#define ti_iq_iqnmpy__include\n#include <stdint.h>\n\n#include \"../support/support.h\"\n\n#if ((!defined (__IQMATH_USE_MATHACL__)) || (!defined (__MSPM0_HAS_MATHACL__)))\n/**\n * @brief Multiply two values of IQN type.\n *\n * @param iqNInput1       IQN type value input to be multiplied.\n * @param iqNInput2       IQN type value input to be multiplied.\n * @param q_value         IQ format.\n *\n * @return                IQN type result of the multiplication.\n */\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNmpy)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n__STATIC_INLINE int_fast32_t __IQNmpy(int_fast32_t iqNInput1, int_fast32_t iqNInput2, const int8_t q_value)\n{\n    int_fast64_t iqNResult;\n\n    iqNResult = (int_fast64_t)iqNInput1 * (int_fast64_t)iqNInput2;\n    iqNResult = iqNResult >> q_value;\n\n    return (int_fast32_t)iqNResult;\n}\n#else\n/**\n * @brief Multiply two values of IQN type, using MathACL.\n *\n * @param iqNInput1       IQN type value input to be multiplied.\n * @param iqNInput2       IQN type value input to be multiplied.\n * @param q_value         IQ format.\n *\n * @return                IQN type result of the multiplication.\n */\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNmpy)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n__STATIC_INLINE int_fast32_t __IQNmpy(int_fast32_t iqNInput1, int_fast32_t iqNInput2, const int8_t q_value)\n{\n    /* write control */\n    MATHACL->CTL = 6 | (q_value << 8) | (1 << 5);\n    /* write operands to HWA */\n    MATHACL->OP2 = iqNInput2;\n    /* write trigger word last */\n    MATHACL->OP1 = iqNInput1;\n    /* read iqmpy product */\n    return MATHACL->RES1;\n}\n#endif\n#endif"
  },
  {
    "path": "iqmath/_IQNfunctions/_IQNmpyIQX.c",
    "content": "/*!****************************************************************************\n *  @file       _IQNmpyIQX.c\n *  @brief      Functions to multiply two IQ numbers in different IQ formats,\n * returning the product in a third IQ format.  The result is neither rounded\n * nor saturated, so if the product is greater than the minimum or maximum\n * values for the given output IQ format, the return value will wrap around\n * and produce inaccurate results.\n *\n *  <hr>\n ******************************************************************************/\n\n#include <stdint.h>\n\n#include \"../support/support.h\"\n#include \"_IQNtables.h\"\n\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in a third IQ format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n * @param q_value         IQ format for result.\n *\n * @return                IQN type result of the multiplication.\n */\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNmpyIQX)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n__STATIC_INLINE int_fast32_t __IQNmpyIQX(int_fast32_t a, int n1, int_fast32_t b, int n2, int8_t q_value)\n{\n    uint_fast16_t ui16IntState;\n    uint_fast16_t ui16MPYState;\n    int_fast32_t i32Shift;\n    int_fast64_t i64Result;\n\n    /*\n     * Mark the start of any multiplies. This will disable interrupts and set\n     * the multiplier to fractional mode. This is designed to reduce overhead\n     * of constantly switching states when using repeated multiplies (MSP430\n     * only).\n     */\n    __mpy_start(&ui16IntState, &ui16MPYState);\n\n    i64Result = __mpyx(a, b);\n\n    /*\n     * Mark the end of all multiplies. This restores MPY and interrupt states\n     * (MSP430 only).\n     */\n    __mpy_stop(&ui16IntState, &ui16MPYState);\n\n    i32Shift = (n1 + n2) - q_value;\n\n    if (i32Shift > 0) {\n        i64Result >>= i32Shift;\n    } else {\n        i64Result <<= -i32Shift;\n    }\n\n    return (int_fast32_t)i64Result;\n}\n\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ30 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ30 type result of the multiplication.\n */\nint32_t _IQ30mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 30);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ29 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ29 type result of the multiplication.\n */\nint32_t _IQ29mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 29);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ28 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ28 type result of the multiplication.\n */\nint32_t _IQ28mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 28);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ27 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ27 type result of the multiplication.\n */\nint32_t _IQ27mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 27);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ26 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ26 type result of the multiplication.\n */\nint32_t _IQ26mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 26);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ25 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ25 type result of the multiplication.\n */\nint32_t _IQ25mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 25);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ24 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ24 type result of the multiplication.\n */\nint32_t _IQ24mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 24);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ23 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ23 type result of the multiplication.\n */\nint32_t _IQ23mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 23);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ22 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ22 type result of the multiplication.\n */\nint32_t _IQ22mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 22);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ21 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ21 type result of the multiplication.\n */\nint32_t _IQ21mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 21);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ20 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ20 type result of the multiplication.\n */\nint32_t _IQ20mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 20);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ19 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ19 type result of the multiplication.\n */\nint32_t _IQ19mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 19);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ18 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ18 type result of the multiplication.\n */\nint32_t _IQ18mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 18);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ17 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ17 type result of the multiplication.\n */\nint32_t _IQ17mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 17);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ16 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ16 type result of the multiplication.\n */\nint32_t _IQ16mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 16);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ15 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ15 type result of the multiplication.\n */\nint32_t _IQ15mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 15);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ14 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ14 type result of the multiplication.\n */\nint32_t _IQ14mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 14);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ13 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ13 type result of the multiplication.\n */\nint32_t _IQ13mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 13);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ12 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ12 type result of the multiplication.\n */\nint32_t _IQ12mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 12);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ11 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ11 type result of the multiplication.\n */\nint32_t _IQ11mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 11);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ10 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ10 type result of the multiplication.\n */\nint32_t _IQ10mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 10);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ9 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ9 type result of the multiplication.\n */\nint32_t _IQ9mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 9);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ8 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ8 type result of the multiplication.\n */\nint32_t _IQ8mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 8);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ7 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ7 type result of the multiplication.\n */\nint32_t _IQ7mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 7);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ6 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ6 type result of the multiplication.\n */\nint32_t _IQ6mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 6);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ5 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ5 type result of the multiplication.\n */\nint32_t _IQ5mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 5);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ4 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ4 type result of the multiplication.\n */\nint32_t _IQ4mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 4);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ3 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ3 type result of the multiplication.\n */\nint32_t _IQ3mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 3);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ2 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ2 type result of the multiplication.\n */\nint32_t _IQ2mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 2);\n}\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in  IQ1 format.\n *\n * @param a               IQN1 type value input to be multiplied.\n * @param n1              IQ format for first value.\n * @param b               IQN2 type value input to be multiplied.\n * @param n2              IQ format for second value.\n *\n * @return                IQ1 type result of the multiplication.\n */\nint32_t _IQ1mpyIQX(int32_t a, int n1, int32_t b, int n2)\n{\n    return __IQNmpyIQX(a, n1, b, n2, 1);\n}\n"
  },
  {
    "path": "iqmath/_IQNfunctions/_IQNrepeat.c",
    "content": "#include <stdint.h>\n\n#include \"../support/support.h\"\n\n#if ((defined (__IQMATH_USE_MATHACL__)) && (defined (__MSPM0_HAS_MATHACL__)))\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNmpy)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n/**\n * @brief Repeats the last IQMath multiplication or division operation on two given parameters.\n *        Function assumes MathACL Control register has been initialized by previous function call\n *        with operation and IQ format. Using without initializing can lead to unexpected results.\n *\n * @param iqNInput1       IQN format number to be multiplied or divided.\n * @param iqNInput2       IQN format number to be multiplied or divided by.\n *\n * @return                IQN type result of operation.\n */\n__STATIC_INLINE int_fast32_t __IQopRepeat(int_fast32_t iqNInput1, int_fast32_t iqNInput2)\n{\n    /* write operands to HWA */\n    MATHACL->OP2 = iqNInput2;\n    /* write trigger word last */\n    MATHACL->OP1 = iqNInput1;\n    /* read operation result */\n    return MATHACL->RES1;\n}\n\n/**\n * @brief Repeats the last IQMath multiplication or division operation on two given parameters.\n *        Function assumes MathACL Control register has been initialized by previous function call\n *        with operation and IQ format. Using without initializing can lead to unexpected results.\n *\n * @param A               IQN format number to be multiplied or divided.\n * @param B               IQN format number to be multiplied or divided by.\n *\n * @return                IQN type result of operation.\n */\nint32_t _IQrepeat(int32_t A, int32_t B)\n{\n    return __IQopRepeat(A, B);\n}\n\n\n#endif\n\n\n"
  },
  {
    "path": "iqmath/_IQNfunctions/_IQNrmpy.c",
    "content": "/*!****************************************************************************\n *  @file       _IQNrmpy.c\n *  @brief      Functions to multiply two IQ numbers, returning the product\n *  in IQ format. The result is rounded but not saturated, so if the product\n *  is greater than the minimum or maximum values for the given IQ format,\n *  the return value wraps around and produces inaccurate results.\n *\n *  <hr>\n ******************************************************************************/\n\n#include <stdint.h>\n\n#include \"../support/support.h\"\n\n/**\n * @brief Multiply two values of IQN type, with rounding.\n *\n * @param iqNInput1       IQN type value input to be multiplied.\n * @param iqNInput2       IQN type value input to be multiplied.\n * @param q_value         IQ format for result.\n *\n * @return                IQN type result of the multiplication.\n */\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNrmpy)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n__STATIC_INLINE int_fast32_t __IQNrmpy(int_fast32_t iqNInput1, int_fast32_t iqNInput2, const int8_t q_value)\n{\n    int_fast64_t iqNResult;\n\n    iqNResult = (int_fast64_t)iqNInput1 * (int_fast64_t)iqNInput2;\n    iqNResult = iqNResult + ((uint_fast32_t)1 << (q_value - 1));\n    iqNResult = iqNResult >> q_value;\n\n    return (int_fast32_t)iqNResult;\n}\n\n/**\n * @brief Multiply two values of IQ31 type, with rounding.\n *\n * @param a               IQ31 type value input to be multiplied.\n * @param b               IQ31 type value input to be multiplied.\n *\n * @return                IQ31 type result of the multiplication.\n */\nint32_t _IQ31rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 31);\n}\n/**\n * @brief Multiply two values of IQ30 type, with rounding.\n *\n * @param a               IQ30 type value input to be multiplied.\n * @param b               IQ30 type value input to be multiplied.\n *\n * @return                IQ30 type result of the multiplication.\n */\nint32_t _IQ30rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 30);\n}\n/**\n * @brief Multiply two values of IQ29 type, with rounding.\n *\n * @param a               IQ29 type value input to be multiplied.\n * @param b               IQ29 type value input to be multiplied.\n *\n * @return                IQ29 type result of the multiplication.\n */\nint32_t _IQ29rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 29);\n}\n/**\n * @brief Multiply two values of IQ28 type, with rounding.\n *\n * @param a               IQ28 type value input to be multiplied.\n * @param b               IQ28 type value input to be multiplied.\n *\n * @return                IQ28 type result of the multiplication.\n */\nint32_t _IQ28rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 28);\n}\n/**\n * @brief Multiply two values of IQ27 type, with rounding.\n *\n * @param a               IQ27 type value input to be multiplied.\n * @param b               IQ27 type value input to be multiplied.\n *\n * @return                IQ27 type result of the multiplication.\n */\nint32_t _IQ27rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 27);\n}\n/**\n * @brief Multiply two values of IQ26 type, with rounding.\n *\n * @param a               IQ26 type value input to be multiplied.\n * @param b               IQ26 type value input to be multiplied.\n *\n * @return                IQ26 type result of the multiplication.\n */\nint32_t _IQ26rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 26);\n}\n/**\n * @brief Multiply two values of IQ25 type, with rounding.\n *\n * @param a               IQ25 type value input to be multiplied.\n * @param b               IQ25 type value input to be multiplied.\n *\n * @return                IQ25 type result of the multiplication.\n */\nint32_t _IQ25rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 25);\n}\n/**\n * @brief Multiply two values of IQ24 type, with rounding.\n *\n * @param a               IQ24 type value input to be multiplied.\n * @param b               IQ24 type value input to be multiplied.\n *\n * @return                IQ24 type result of the multiplication.\n */\nint32_t _IQ24rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 24);\n}\n/**\n * @brief Multiply two values of IQ23 type, with rounding.\n *\n * @param a               IQ23 type value input to be multiplied.\n * @param b               IQ23 type value input to be multiplied.\n *\n * @return                IQ23 type result of the multiplication.\n */\nint32_t _IQ23rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 23);\n}\n/**\n * @brief Multiply two values of IQ22 type, with rounding.\n *\n * @param a               IQ22 type value input to be multiplied.\n * @param b               IQ22 type value input to be multiplied.\n *\n * @return                IQ22 type result of the multiplication.\n */\nint32_t _IQ22rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 22);\n}\n/**\n * @brief Multiply two values of IQ21 type, with rounding.\n *\n * @param a               IQ21 type value input to be multiplied.\n * @param b               IQ21 type value input to be multiplied.\n *\n * @return                IQ21 type result of the multiplication.\n */\nint32_t _IQ21rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 21);\n}\n/**\n * @brief Multiply two values of IQ20 type, with rounding.\n *\n * @param a               IQ20 type value input to be multiplied.\n * @param b               IQ20 type value input to be multiplied.\n *\n * @return                IQ20 type result of the multiplication.\n */\nint32_t _IQ20rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 20);\n}\n/**\n * @brief Multiply two values of IQ19 type, with rounding.\n *\n * @param a               IQ19 type value input to be multiplied.\n * @param b               IQ19 type value input to be multiplied.\n *\n * @return                IQ19 type result of the multiplication.\n */\nint32_t _IQ19rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 19);\n}\n/**\n * @brief Multiply two values of IQ18 type, with rounding.\n *\n * @param a               IQ18 type value input to be multiplied.\n * @param b               IQ18 type value input to be multiplied.\n *\n * @return                IQ18 type result of the multiplication.\n */\nint32_t _IQ18rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 18);\n}\n/**\n * @brief Multiply two values of IQ17 type, with rounding.\n *\n * @param a               IQ17 type value input to be multiplied.\n * @param b               IQ17 type value input to be multiplied.\n *\n * @return                IQ17 type result of the multiplication.\n */\nint32_t _IQ17rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 17);\n}\n/**\n * @brief Multiply two values of IQ16 type, with rounding.\n *\n * @param a               IQ16 type value input to be multiplied.\n * @param b               IQ16 type value input to be multiplied.\n *\n * @return                IQ16 type result of the multiplication.\n */\nint32_t _IQ16rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 16);\n}\n/**\n * @brief Multiply two values of IQ15 type, with rounding.\n *\n * @param a               IQ15 type value input to be multiplied.\n * @param b               IQ15 type value input to be multiplied.\n *\n * @return                IQ15 type result of the multiplication.\n */\nint32_t _IQ15rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 15);\n}\n/**\n * @brief Multiply two values of IQ14 type, with rounding.\n *\n * @param a               IQ14 type value input to be multiplied.\n * @param b               IQ14 type value input to be multiplied.\n *\n * @return                IQ14 type result of the multiplication.\n */\nint32_t _IQ14rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 14);\n}\n/**\n * @brief Multiply two values of IQ13 type, with rounding.\n *\n * @param a               IQ13 type value input to be multiplied.\n * @param b               IQ13 type value input to be multiplied.\n *\n * @return                IQ13 type result of the multiplication.\n */\nint32_t _IQ13rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 13);\n}\n/**\n * @brief Multiply two values of IQ12 type, with rounding.\n *\n * @param a               IQ12 type value input to be multiplied.\n * @param b               IQ12 type value input to be multiplied.\n *\n * @return                IQ12 type result of the multiplication.\n */\nint32_t _IQ12rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 12);\n}\n/**\n * @brief Multiply two values of IQ11 type, with rounding.\n *\n * @param a               IQ11 type value input to be multiplied.\n * @param b               IQ11 type value input to be multiplied.\n *\n * @return                IQ11 type result of the multiplication.\n */\nint32_t _IQ11rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 11);\n}\n/**\n * @brief Multiply two values of IQ10 type, with rounding.\n *\n * @param a               IQ10 type value input to be multiplied.\n * @param b               IQ10 type value input to be multiplied.\n *\n * @return                IQ10 type result of the multiplication.\n */\nint32_t _IQ10rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 10);\n}\n/**\n * @brief Multiply two values of IQ9 type, with rounding.\n *\n * @param a               IQ9 type value input to be multiplied.\n * @param b               IQ9 type value input to be multiplied.\n *\n * @return                IQ9 type result of the multiplication.\n */\nint32_t _IQ9rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 9);\n}\n/**\n * @brief Multiply two values of IQ8 type, with rounding.\n *\n * @param a               IQ8 type value input to be multiplied.\n * @param b               IQ8 type value input to be multiplied.\n *\n * @return                IQ8 type result of the multiplication.\n */\nint32_t _IQ8rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 8);\n}\n/**\n * @brief Multiply two values of IQ7 type, with rounding.\n *\n * @param a               IQ7 type value input to be multiplied.\n * @param b               IQ7 type value input to be multiplied.\n *\n * @return                IQ7 type result of the multiplication.\n */\nint32_t _IQ7rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 7);\n}\n/**\n * @brief Multiply two values of IQ6 type, with rounding.\n *\n * @param a               IQ6 type value input to be multiplied.\n * @param b               IQ6 type value input to be multiplied.\n *\n * @return                IQ6 type result of the multiplication.\n */\nint32_t _IQ6rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 6);\n}\n/**\n * @brief Multiply two values of IQ5 type, with rounding.\n *\n * @param a               IQ5 type value input to be multiplied.\n * @param b               IQ5 type value input to be multiplied.\n *\n * @return                IQ5 type result of the multiplication.\n */\nint32_t _IQ5rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 5);\n}\n/**\n * @brief Multiply two values of IQ4 type, with rounding.\n *\n * @param a               IQ4 type value input to be multiplied.\n * @param b               IQ4 type value input to be multiplied.\n *\n * @return                IQ4 type result of the multiplication.\n */\nint32_t _IQ4rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 4);\n}\n/**\n * @brief Multiply two values of IQ3 type, with rounding.\n *\n * @param a               IQ3 type value input to be multiplied.\n * @param b               IQ3 type value input to be multiplied.\n *\n * @return                IQ3 type result of the multiplication.\n */\nint32_t _IQ3rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 3);\n}\n/**\n * @brief Multiply two values of IQ2 type, with rounding.\n *\n * @param a               IQ2 type value input to be multiplied.\n * @param b               IQ2 type value input to be multiplied.\n *\n * @return                IQ2 type result of the multiplication.\n */\nint32_t _IQ2rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 2);\n}\n/**\n * @brief Multiply two values of IQ1 type, with rounding.\n *\n * @param a               IQ1 type value input to be multiplied.\n * @param b               IQ1 type value input to be multiplied.\n *\n * @return                IQ1 type result of the multiplication.\n */\nint32_t _IQ1rmpy(int32_t a, int32_t b)\n{\n    return __IQNrmpy(a, b, 1);\n}\n"
  },
  {
    "path": "iqmath/_IQNfunctions/_IQNrsmpy.c",
    "content": "/*!****************************************************************************\n *  @file       _IQNrsmpy.c\n *  @brief      Functions to multiply two IQ numbers, returning the product in\n *  IQ format. The result is rounded and saturated, so if the product is\n * greater than the minimum or maximum values for the given IQ format, the\n * return value is saturated to the minimum or maximum value for the given IQ\n * format (as appropriate).\n *\n *  <hr>\n ******************************************************************************/\n\n#include <stdint.h>\n\n#include \"../support/support.h\"\n\n/**\n * @brief Multiplies two IQN numbers, with rounding and saturation.\n *\n * @param iqNInput1       IQN type value input to be multiplied.\n * @param iqNInput2       IQN type value input to be multiplied.\n * @param q_value         IQ format for result.\n *\n * @return                IQN type result of the multiplication.\n */\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNrsmpy)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n__STATIC_INLINE int_fast32_t __IQNrsmpy(int_fast32_t iqNInput1, int_fast32_t iqNInput2, const int8_t q_value)\n{\n    int_fast64_t iqNResult;\n\n    iqNResult = (int_fast64_t)iqNInput1 * (int_fast64_t)iqNInput2;\n    iqNResult = iqNResult + ((uint_fast32_t)1 << (q_value - 1));\n    iqNResult = iqNResult >> q_value;\n\n    if (iqNResult > INT32_MAX) {\n        return INT32_MAX;\n    } else if (iqNResult < INT32_MIN) {\n        return INT32_MIN;\n    } else {\n        return (int_fast32_t)iqNResult;\n    }\n}\n\n/**\n * @brief Multiplies two IQ31 numbers, with rounding and saturation.\n *\n * @param a               IQ31 type value input to be multiplied.\n * @param b               IQ31 type value input to be multiplied.\n *\n * @return                IQ31 type result of the multiplication.\n */\nint32_t _IQ31rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 31);\n}\n/**\n * @brief Multiplies two IQ30 numbers, with rounding and saturation.\n *\n * @param a               IQ30 type value input to be multiplied.\n * @param b               IQ30 type value input to be multiplied.\n *\n * @return                IQ30 type result of the multiplication.\n */\nint32_t _IQ30rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 30);\n}\n/**\n * @brief Multiplies two IQ29 numbers, with rounding and saturation.\n *\n * @param a               IQ29 type value input to be multiplied.\n * @param b               IQ29 type value input to be multiplied.\n *\n * @return                IQ29 type result of the multiplication.\n */\nint32_t _IQ29rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 29);\n}\n/**\n * @brief Multiplies two IQ28 numbers, with rounding and saturation.\n *\n * @param a               IQ28 type value input to be multiplied.\n * @param b               IQ28 type value input to be multiplied.\n *\n * @return                IQ28 type result of the multiplication.\n */\nint32_t _IQ28rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 28);\n}\n/**\n * @brief Multiplies two IQ27 numbers, with rounding and saturation.\n *\n * @param a               IQ27 type value input to be multiplied.\n * @param b               IQ27 type value input to be multiplied.\n *\n * @return                IQ27 type result of the multiplication.\n */\nint32_t _IQ27rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 27);\n}\n/**\n * @brief Multiplies two IQ26 numbers, with rounding and saturation.\n *\n * @param a               IQ26 type value input to be multiplied.\n * @param b               IQ26 type value input to be multiplied.\n *\n * @return                IQ26 type result of the multiplication.\n */\nint32_t _IQ26rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 26);\n}\n/**\n * @brief Multiplies two IQ25 numbers, with rounding and saturation.\n *\n * @param a               IQ25 type value input to be multiplied.\n * @param b               IQ25 type value input to be multiplied.\n *\n * @return                IQ25 type result of the multiplication.\n */\nint32_t _IQ25rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 25);\n}\n/**\n * @brief Multiplies two IQ24 numbers, with rounding and saturation.\n *\n * @param a               IQ24 type value input to be multiplied.\n * @param b               IQ24 type value input to be multiplied.\n *\n * @return                IQ24 type result of the multiplication.\n */\nint32_t _IQ24rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 24);\n}\n/**\n * @brief Multiplies two IQ23 numbers, with rounding and saturation.\n *\n * @param a               IQ23 type value input to be multiplied.\n * @param b               IQ23 type value input to be multiplied.\n *\n * @return                IQ23 type result of the multiplication.\n */\nint32_t _IQ23rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 23);\n}\n/**\n * @brief Multiplies two IQ22 numbers, with rounding and saturation.\n *\n * @param a               IQ22 type value input to be multiplied.\n * @param b               IQ22 type value input to be multiplied.\n *\n * @return                IQ22 type result of the multiplication.\n */\nint32_t _IQ22rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 22);\n}\n/**\n * @brief Multiplies two IQ21 numbers, with rounding and saturation.\n *\n * @param a               IQ21 type value input to be multiplied.\n * @param b               IQ21 type value input to be multiplied.\n *\n * @return                IQ21 type result of the multiplication.\n */\nint32_t _IQ21rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 21);\n}\n/**\n * @brief Multiplies two IQ20 numbers, with rounding and saturation.\n *\n * @param a               IQ20 type value input to be multiplied.\n * @param b               IQ20 type value input to be multiplied.\n *\n * @return                IQ20 type result of the multiplication.\n */\nint32_t _IQ20rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 20);\n}\n/**\n * @brief Multiplies two IQ19 numbers, with rounding and saturation.\n *\n * @param a               IQ19 type value input to be multiplied.\n * @param b               IQ19 type value input to be multiplied.\n *\n * @return                IQ19 type result of the multiplication.\n */\nint32_t _IQ19rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 19);\n}\n/**\n * @brief Multiplies two IQ18 numbers, with rounding and saturation.\n *\n * @param a               IQ18 type value input to be multiplied.\n * @param b               IQ18 type value input to be multiplied.\n *\n * @return                IQ18 type result of the multiplication.\n */\nint32_t _IQ18rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 18);\n}\n/**\n * @brief Multiplies two IQ17 numbers, with rounding and saturation.\n *\n * @param a               IQ17 type value input to be multiplied.\n * @param b               IQ17 type value input to be multiplied.\n *\n * @return                IQ17 type result of the multiplication.\n */\nint32_t _IQ17rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 17);\n}\n/**\n * @brief Multiplies two IQ16 numbers, with rounding and saturation.\n *\n * @param a               IQ16 type value input to be multiplied.\n * @param b               IQ16 type value input to be multiplied.\n *\n * @return                IQ16 type result of the multiplication.\n */\nint32_t _IQ16rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 16);\n}\n/**\n * @brief Multiplies two IQ15 numbers, with rounding and saturation.\n *\n * @param a               IQ15 type value input to be multiplied.\n * @param b               IQ15 type value input to be multiplied.\n *\n * @return                IQ15 type result of the multiplication.\n */\nint32_t _IQ15rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 15);\n}\n/**\n * @brief Multiplies two IQ14 numbers, with rounding and saturation.\n *\n * @param a               IQ14 type value input to be multiplied.\n * @param b               IQ14 type value input to be multiplied.\n *\n * @return                IQ14 type result of the multiplication.\n */\nint32_t _IQ14rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 14);\n}\n/**\n * @brief Multiplies two IQ13 numbers, with rounding and saturation.\n *\n * @param a               IQ13 type value input to be multiplied.\n * @param b               IQ13 type value input to be multiplied.\n *\n * @return                IQ13 type result of the multiplication.\n */\nint32_t _IQ13rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 13);\n}\n/**\n * @brief Multiplies two IQ12 numbers, with rounding and saturation.\n *\n * @param a               IQ12 type value input to be multiplied.\n * @param b               IQ12 type value input to be multiplied.\n *\n * @return                IQ12 type result of the multiplication.\n */\nint32_t _IQ12rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 12);\n}\n/**\n * @brief Multiplies two IQ11 numbers, with rounding and saturation.\n *\n * @param a               IQ11 type value input to be multiplied.\n * @param b               IQ11 type value input to be multiplied.\n *\n * @return                IQ11 type result of the multiplication.\n */\nint32_t _IQ11rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 11);\n}\n/**\n * @brief Multiplies two IQ10 numbers, with rounding and saturation.\n *\n * @param a               IQ10 type value input to be multiplied.\n * @param b               IQ10 type value input to be multiplied.\n *\n * @return                IQ10 type result of the multiplication.\n */\nint32_t _IQ10rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 10);\n}\n/**\n * @brief Multiplies two IQ9 numbers, with rounding and saturation.\n *\n * @param a               IQ9 type value input to be multiplied.\n * @param b               IQ9 type value input to be multiplied.\n *\n * @return                IQ9 type result of the multiplication.\n */\nint32_t _IQ9rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 9);\n}\n/**\n * @brief Multiplies two IQ8 numbers, with rounding and saturation.\n *\n * @param a               IQ8 type value input to be multiplied.\n * @param b               IQ8 type value input to be multiplied.\n *\n * @return                IQ8 type result of the multiplication.\n */\nint32_t _IQ8rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 8);\n}\n/**\n * @brief Multiplies two IQ7 numbers, with rounding and saturation.\n *\n * @param a               IQ7 type value input to be multiplied.\n * @param b               IQ7 type value input to be multiplied.\n *\n * @return                IQ7 type result of the multiplication.\n */\nint32_t _IQ7rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 7);\n}\n/**\n * @brief Multiplies two IQ6 numbers, with rounding and saturation.\n *\n * @param a               IQ6 type value input to be multiplied.\n * @param b               IQ6 type value input to be multiplied.\n *\n * @return                IQ6 type result of the multiplication.\n */\nint32_t _IQ6rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 6);\n}\n/**\n * @brief Multiplies two IQ5 numbers, with rounding and saturation.\n *\n * @param a               IQ5 type value input to be multiplied.\n * @param b               IQ5 type value input to be multiplied.\n *\n * @return                IQ5 type result of the multiplication.\n */\nint32_t _IQ5rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 5);\n}\n/**\n * @brief Multiplies two IQ4 numbers, with rounding and saturation.\n *\n * @param a               IQ4 type value input to be multiplied.\n * @param b               IQ4 type value input to be multiplied.\n *\n * @return                IQ4 type result of the multiplication.\n */\nint32_t _IQ4rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 4);\n}\n/**\n * @brief Multiplies two IQ3 numbers, with rounding and saturation.\n *\n * @param a               IQ3 type value input to be multiplied.\n * @param b               IQ3 type value input to be multiplied.\n *\n * @return                IQ3 type result of the multiplication.\n */\nint32_t _IQ3rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 3);\n}\n/**\n * @brief Multiplies two IQ2 numbers, with rounding and saturation.\n *\n * @param a               IQ2 type value input to be multiplied.\n * @param b               IQ2 type value input to be multiplied.\n *\n * @return                IQ2 type result of the multiplication.\n */\nint32_t _IQ2rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 2);\n}\n/**\n * @brief Multiplies two IQ1 numbers, with rounding and saturation.\n *\n * @param a               IQ1 type value input to be multiplied.\n * @param b               IQ1 type value input to be multiplied.\n *\n * @return                IQ1 type result of the multiplication.\n */\nint32_t _IQ1rsmpy(int32_t a, int32_t b)\n{\n    return __IQNrsmpy(a, b, 1);\n}\n"
  },
  {
    "path": "iqmath/_IQNfunctions/_IQNsin_cos.c",
    "content": "/*!****************************************************************************\n *  @file       _IQNsin_cos.c\n *  @brief      Functions to compute the sine and cosine of the input\n *              and return the result.\n *\n *  <hr>\n ******************************************************************************/\n\n#include <stdint.h>\n\n#include \"../support/support.h\"\n#include \"_IQNtables.h\"\n#include \"../include/IQmathLib.h\"\n\n/*!\n * @brief The value of PI\n */\n#define PI (3.1415926536)\n\n/*!\n * @brief Used to specify sine operation\n */\n#define TYPE_SIN     (0)\n/*!\n * @brief Used to specify cosine operation\n */\n#define TYPE_COS     (1)\n/*!\n * @brief Used to specify result in radians\n */\n#define TYPE_RAD     (0)\n/*!\n * @brief Used to specify per-unit result\n */\n#define TYPE_PU      (1)\n\n\n#if ((!defined (__IQMATH_USE_MATHACL__)) || (!defined (__MSPM0_HAS_MATHACL__)))\n/**\n * @brief Computes the sine of an UIQ31 input.\n *\n * @param uiq31Input      UIQ31 type input.\n *\n * @return                UIQ31 type result of sine.\n */\n/*\n * Perform the calculation where the input is only in the first quadrant\n * using one of the following two functions.\n *\n * This algorithm is derived from the following trig identities:\n *     sin(k + x) = sin(k)*cos(x) + cos(k)*sin(x)\n *     cos(k + x) = cos(k)*cos(x) - sin(k)*sin(x)\n *\n * First we calculate an index k and the remainder x according to the following\n * formulas:\n *\n *     k = 0x3F & int(Radian*64)\n *     x = fract(Radian*64)/64\n *\n * Two lookup tables store the values of sin(k) and cos(k) for all possible\n * indexes. The remainder, x, is calculated using second order Taylor series.\n *\n *     sin(x) = x - (x^3)/6     (~36.9 bits of accuracy)\n *     cos(x) = 1 - (x^2)/2     (~28.5 bits of accuracy)\n *\n * Combining the trig identities with the Taylor series approximiations gives\n * the following two functions:\n *\n *     cos(Radian) = C(k) + x*(-S(k) + 0.5*x*(-C(k) + 0.333*x*S(k)))\n *     sin(Radian) = S(k) + x*(C(k) + 0.5*x*(-S(k) - 0.333*x*C(k)))\n *\n *     where  S(k) = Sin table value at offset \"k\"\n *            C(k) = Cos table value at offset \"k\"\n *\n * Using a lookup table with a 64 bit index (52 indexes since the input range is\n * only 0 - 0.785398) and second order Taylor series gives 28 bits of accuracy.\n */\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNcalcSin)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n__STATIC_INLINE int_fast32_t __IQNcalcSin(uint_fast32_t uiq31Input)\n{\n    uint_fast16_t index;\n    int_fast32_t iq31X;\n    int_fast32_t iq31Sin;\n    int_fast32_t iq31Cos;\n    int_fast32_t iq31Res;\n\n    /* Calculate index for sin and cos lookup using bits 31:26 */\n    index = (uint_fast16_t)(uiq31Input >> 25) & 0x003f;\n\n    /* Lookup S(k) and C(k) values. */\n    iq31Sin = _IQ31SinLookup[index];\n    iq31Cos = _IQ31CosLookup[index];\n\n    /*\n     * Calculated x (the remainder) by subtracting the index from the unsigned\n     * iq31 input. This can be accomplished by masking out the bits used for\n     * the index.\n     */\n    iq31X = uiq31Input & 0x01ffffff;\n\n    /* 0.333*x*C(k) */\n    iq31Res = __mpyf_l(0x2aaaaaab, iq31X);\n    iq31Res = __mpyf_l(iq31Cos, iq31Res);\n\n    /* -S(k) - 0.333*x*C(k) */\n    iq31Res = -(iq31Sin + iq31Res);\n\n    /* 0.5*x*(-S(k) - 0.333*x*C(k)) */\n    iq31Res = iq31Res >> 1;\n    iq31Res = __mpyf_l(iq31X, iq31Res);\n\n    /* C(k) + 0.5*x*(-S(k) - 0.333*x*C(k)) */\n    iq31Res = iq31Cos + iq31Res;\n\n    /* x*(C(k) + 0.5*x*(-S(k) - 0.333*x*C(k))) */\n    iq31Res = __mpyf_l(iq31X, iq31Res);\n\n    /* sin(Radian) = S(k) + x*(C(k) + 0.5*x*(-S(k) - 0.333*x*C(k))) */\n    iq31Res = iq31Sin + iq31Res;\n\n    return iq31Res;\n}\n/**\n * @brief Computes the cosine of an UIQ31 input.\n *\n * @param uiq31Input      UIQ31 type input.\n *\n * @return                UIQ31 type result of cosine.\n */\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNcalcCos)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n__STATIC_INLINE int_fast32_t __IQNcalcCos(uint_fast32_t uiq31Input)\n{\n    uint_fast16_t index;\n    int_fast32_t iq31X;\n    int_fast32_t iq31Sin;\n    int_fast32_t iq31Cos;\n    int_fast32_t iq31Res;\n\n    /* Calculate index for sin and cos lookup using bits 31:26 */\n    index = (uint_fast16_t)(uiq31Input >> 25) & 0x003f;\n\n    /* Lookup S(k) and C(k) values. */\n    iq31Sin = _IQ31SinLookup[index];\n    iq31Cos = _IQ31CosLookup[index];\n\n    /*\n     * Calculated x (the remainder) by subtracting the index from the unsigned\n     * iq31 input. This can be accomplished by masking out the bits used for\n     * the index.\n     */\n    iq31X = uiq31Input & 0x01ffffff;\n\n    /* 0.333*x*S(k) */\n    iq31Res = __mpyf_l(0x2aaaaaab, iq31X);\n    iq31Res = __mpyf_l(iq31Sin, iq31Res);\n\n    /* -C(k) + 0.333*x*S(k) */\n    iq31Res = iq31Res - iq31Cos;\n\n    /* 0.5*x*(-C(k) + 0.333*x*S(k)) */\n    iq31Res = iq31Res >> 1;\n    iq31Res = __mpyf_l(iq31X, iq31Res);\n\n    /* -S(k) + 0.5*x*(-C(k) + 0.333*x*S(k)) */\n    iq31Res = iq31Res - iq31Sin;\n\n    /* x*(-S(k) + 0.5*x*(-C(k) + 0.333*x*S(k))) */\n    iq31Res = __mpyf_l(iq31X, iq31Res);\n\n    /* cos(Radian) = C(k) + x*(-S(k) + 0.5*x*(-C(k) + 0.333*x*S(k))) */\n    iq31Res = iq31Cos + iq31Res;\n\n    return iq31Res;\n}\n\n/**\n * @brief Computes the sine or cosine of an IQN input.\n *\n * @param iqNInput        IQN type input.\n * @param q_value         IQ format.\n * @param type            Specifies sine or cosine operation.\n * @param format          Specifies radians or per-unit operation.\n *\n * @return                IQN type result of sin or cosine operation.\n */\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNsin_cos)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n__STATIC_INLINE int_fast32_t __IQNsin_cos(int_fast32_t iqNInput, const int8_t q_value,\n        const int8_t type, const int8_t format)\n{\n    uint8_t ui8Sign = 0;\n    uint_fast16_t ui16IntState;\n    uint_fast16_t ui16MPYState;\n    uint_fast32_t uiq29Input;\n    uint_fast32_t uiq30Input;\n    uint_fast32_t uiq31Input;\n    uint_fast32_t uiq32Input;\n    uint_fast32_t uiq31Result = 0;\n\n    /* Remove sign from input */\n    if (iqNInput < 0) {\n        iqNInput = -iqNInput;\n\n        /* Flip sign only for sin */\n        if (type == TYPE_SIN) {\n            ui8Sign = 1;\n        }\n    }\n\n    /*\n     * Mark the start of any multiplies. This will disable interrupts and set\n     * the multiplier to fractional mode. This is designed to reduce overhead\n     * of constantly switching states when using repeated multiplies (MSP430\n     * only).\n     */\n    __mpyf_start(&ui16IntState, &ui16MPYState);\n\n    /* Per unit API */\n    if (format == TYPE_PU) {\n        /*\n         * Scale input to unsigned iq32 to allow for maximum range. This removes\n         * the integer component of the per unit input.\n         */\n        uiq32Input = (uint_fast32_t)iqNInput << (32 - q_value);\n\n        /* Reduce the input to the first two quadrants. */\n        if (uiq32Input >= 0x80000000) {\n            uiq32Input -= 0x80000000;\n            ui8Sign ^= 1;\n        }\n\n        /*\n         * Multiply unsigned iq32 input by 2*pi and scale to unsigned iq30:\n         *     iq32 * iq30 = iq30 * 2\n         */\n        uiq30Input = __mpyf_ul(uiq32Input, iq30_pi);\n\n    }\n    /* Radians API */\n    else {\n        /* Calculate the exponent difference from input format to iq29. */\n        int_fast16_t exp = 29 - q_value;\n\n        /* Save input as unsigned iq29 format. */\n        uiq29Input = (uint_fast32_t)iqNInput;\n\n        /* Reduce the input exponent to zero by scaling by 2*pi. */\n        while (exp) {\n            if (uiq29Input >= iq29_pi) {\n                uiq29Input -= iq29_pi;\n            }\n            uiq29Input <<= 1;\n            exp--;\n        }\n\n        /* Reduce the range to the first two quadrants. */\n        if (uiq29Input >= iq29_pi) {\n            uiq29Input -= iq29_pi;\n            ui8Sign ^= 1;\n        }\n\n        /* Scale the unsigned iq29 input to unsigned iq30. */\n        uiq30Input = uiq29Input << 1;\n    }\n\n    /* Reduce the iq30 input range to the first quadrant. */\n    if (uiq30Input >= iq30_halfPi) {\n        uiq30Input = iq30_pi - uiq30Input;\n\n        /* flip sign for cos calculations */\n        if (type == TYPE_COS) {\n            ui8Sign ^= 1;\n        }\n    }\n\n    /* Convert the unsigned iq30 input to unsigned iq31 */\n    uiq31Input = uiq30Input << 1;\n\n    /* Only one of these cases will be compiled per function. */\n    if (type == TYPE_COS) {\n        /* If input is greater than pi/4 use sin for calculations */\n        if (uiq31Input > iq31_quarterPi) {\n            uiq31Input = iq31_halfPi - uiq31Input;\n            uiq31Result = __IQNcalcSin(uiq31Input);\n        } else {\n            uiq31Result = __IQNcalcCos(uiq31Input);\n        }\n    } else if (type == TYPE_SIN) {\n        /* If input is greater than pi/4 use cos for calculations */\n        if (uiq31Input > iq31_quarterPi) {\n            uiq31Input = iq31_halfPi - uiq31Input;\n            uiq31Result = __IQNcalcCos(uiq31Input);\n        } else {\n            uiq31Result = __IQNcalcSin(uiq31Input);\n        }\n    }\n\n    /*\n     * Mark the end of all multiplies. This restores MPY and interrupt states\n     * (MSP430 only).\n     */\n    __mpy_stop(&ui16IntState, &ui16MPYState);\n\n    /* Shift to Q type */\n    uiq31Result >>= (31 - q_value);\n\n    /* set sign */\n    if (ui8Sign) {\n        uiq31Result = -uiq31Result;\n    }\n\n    return uiq31Result;\n}\n#else\n/**\n * @brief Computes the sine or cosine of an IQN input, using MathACL.\n *\n * @param iqNInput        IQN type input.\n * @param q_value         IQ format.\n * @param type            Specifies sine or cosine operation.\n * @param format          Specifies radians or per-unit operation.\n *\n * @return                IQN type result of sin or cosine operation.\n */\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNsin_cos)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n__STATIC_INLINE int_fast32_t __IQNsin_cos(int_fast32_t iqNInput, const int8_t q_value,\n        const int8_t type, const int8_t format)\n{\n    int_fast32_t res, res1, resMult, resDiv;\n    int_fast32_t iq31input;\n    /* Per unit API */\n    if (format == TYPE_PU) {\n        /* multiply by 2 for MathACL scaling. */\n        resMult = (uint_fast32_t)iqNInput << (1);\n        /* shift to IQ31 for sin/cos calculation */\n        iq31input = (uint_fast32_t)resMult << (31 - q_value);\n    }\n    /* Radians API */\n    else {\n        /* divide by PI for MathACL scaling\n            * write control\n            */\n        MATHACL->CTL = 4 | (q_value << 8) | (1 << 5);\n        /* write operands to HWA. OP2 = divisor, OP1 = dividend */\n        MATHACL->OP2 = ((uint_fast32_t)((PI) * ((uint_fast32_t)1 << q_value)));\n        /* trigger is write to OP1 */\n        MATHACL->OP1 = iqNInput;\n        /* read quotient and remainder */\n        resDiv = MATHACL->RES1;\n        /* shift from q_value to IQ31 for sin/cos calculation */\n        iq31input = (uint_fast32_t)resDiv << (31 - q_value);\n    }\n    /*\n     * write control\n     * operation = sincos, iterations = 31\n     */\n    MATHACL->CTL = 1 | (31 << 24);\n    /* write operand to HWA */\n    MATHACL->OP1 = iq31input;\n    if (type == TYPE_COS) {\n        /* read cosine */\n        res1 = MATHACL->RES1;\n    } else if (type == TYPE_SIN) {\n        /* read sine */\n        res1 = MATHACL->RES2;\n    }\n    /* Shift to q_value type */\n    res = res1 >> (31 - q_value);\n    return res;\n}\n#endif\n\n/* IQ sin functions */\n\n/**\n * @brief Computes the cosine of an IQ29 input.\n *\n * @param a               IQ29 type input.\n *\n * @return                IQ29 type result of cosine operation, in radians.\n */\nint32_t _IQ29sin(int32_t a)\n{\n    return __IQNsin_cos(a, 29, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ28 input.\n *\n * @param a               IQ28 type input.\n *\n * @return                IQ28 type result of sine operation, in radians.\n */\nint32_t _IQ28sin(int32_t a)\n{\n    return __IQNsin_cos(a, 28, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ27 input.\n *\n * @param a               IQ27 type input.\n *\n * @return                IQ27 type result of sine operation, in radians.\n */\nint32_t _IQ27sin(int32_t a)\n{\n    return __IQNsin_cos(a, 27, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ26 input.\n *\n * @param a               IQ26 type input.\n *\n * @return                IQ26 type result of sine operation, in radians.\n */\nint32_t _IQ26sin(int32_t a)\n{\n    return __IQNsin_cos(a, 26, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ25 input.\n *\n * @param a               IQ25 type input.\n *\n * @return                IQ25 type result of sine operation, in radians.\n */\nint32_t _IQ25sin(int32_t a)\n{\n    return __IQNsin_cos(a, 25, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ24 input.\n *\n * @param a               IQ24 type input.\n *\n * @return                IQ24 type result of sine operation, in radians.\n */\nint32_t _IQ24sin(int32_t a)\n{\n    return __IQNsin_cos(a, 24, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ23 input.\n *\n * @param a               IQ23 type input.\n *\n * @return                IQ23 type result of sine operation, in radians.\n */\nint32_t _IQ23sin(int32_t a)\n{\n    return __IQNsin_cos(a, 23, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ22 input.\n *\n * @param a               IQ22 type input.\n *\n * @return                IQ22 type result of sine operation, in radians.\n */\nint32_t _IQ22sin(int32_t a)\n{\n    return __IQNsin_cos(a, 22, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ21 input.\n *\n * @param a               IQ21 type input.\n *\n * @return                IQ21 type result of sine operation, in radians.\n */\nint32_t _IQ21sin(int32_t a)\n{\n    return __IQNsin_cos(a, 21, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ20 input.\n *\n * @param a               IQ20 type input.\n *\n * @return                IQ20 type result of sine operation, in radians.\n */\nint32_t _IQ20sin(int32_t a)\n{\n    return __IQNsin_cos(a, 20, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ19 input.\n *\n * @param a               IQ19 type input.\n *\n * @return                IQ19 type result of sine operation, in radians.\n */\nint32_t _IQ19sin(int32_t a)\n{\n    return __IQNsin_cos(a, 19, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ18 input.\n *\n * @param a               IQ18 type input.\n *\n * @return                IQ18 type result of sine operation, in radians.\n */\nint32_t _IQ18sin(int32_t a)\n{\n    return __IQNsin_cos(a, 18, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ17 input.\n *\n * @param a               IQ17 type input.\n *\n * @return                IQ17 type result of sine operation, in radians.\n */\nint32_t _IQ17sin(int32_t a)\n{\n    return __IQNsin_cos(a, 17, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ16 input.\n *\n * @param a               IQ16 type input.\n *\n * @return                IQ16 type result of sine operation, in radians.\n */\nint32_t _IQ16sin(int32_t a)\n{\n    return __IQNsin_cos(a, 16, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ15 input.\n *\n * @param a               IQ15 type input.\n *\n * @return                IQ15 type result of sine operation, in radians.\n */\nint32_t _IQ15sin(int32_t a)\n{\n    return __IQNsin_cos(a, 15, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ14 input.\n *\n * @param a               IQ14 type input.\n *\n * @return                IQ14 type result of sine operation, in radians.\n */\nint32_t _IQ14sin(int32_t a)\n{\n    return __IQNsin_cos(a, 14, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ13 input.\n *\n * @param a               IQ13 type input.\n *\n * @return                IQ13 type result of sine operation, in radians.\n */\nint32_t _IQ13sin(int32_t a)\n{\n    return __IQNsin_cos(a, 13, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ12 input.\n *\n * @param a               IQ12 type input.\n *\n * @return                IQ12 type result of sine operation, in radians.\n */\nint32_t _IQ12sin(int32_t a)\n{\n    return __IQNsin_cos(a, 12, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ11 input.\n *\n * @param a               IQ11 type input.\n *\n * @return                IQ11 type result of sine operation, in radians.\n */\nint32_t _IQ11sin(int32_t a)\n{\n    return __IQNsin_cos(a, 11, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ10 input.\n *\n * @param a               IQ10 type input.\n *\n * @return                IQ10 type result of sine operation, in radians.\n */\nint32_t _IQ10sin(int32_t a)\n{\n    return __IQNsin_cos(a, 10, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ9 input.\n *\n * @param a               IQ9 type input.\n *\n * @return                IQ9 type result of sine operation, in radians.\n */\nint32_t _IQ9sin(int32_t a)\n{\n    return __IQNsin_cos(a, 9, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ8 input.\n *\n * @param a               IQ8 type input.\n *\n * @return                IQ8 type result of sine operation, in radians.\n */\nint32_t _IQ8sin(int32_t a)\n{\n    return __IQNsin_cos(a, 8, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ7 input.\n *\n * @param a               IQ7 type input.\n *\n * @return                IQ7 type result of sine operation, in radians.\n */\nint32_t _IQ7sin(int32_t a)\n{\n    return __IQNsin_cos(a, 7, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ6 input.\n *\n * @param a               IQ6 type input.\n *\n * @return                IQ6 type result of sine operation, in radians.\n */\nint32_t _IQ6sin(int32_t a)\n{\n    return __IQNsin_cos(a, 6, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ5 input.\n *\n * @param a               IQ5 type input.\n *\n * @return                IQ5 type result of sine operation, in radians.\n */\nint32_t _IQ5sin(int32_t a)\n{\n    return __IQNsin_cos(a, 5, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ4 input.\n *\n * @param a               IQ4 type input.\n *\n * @return                IQ4 type result of sine operation, in radians.\n */\nint32_t _IQ4sin(int32_t a)\n{\n    return __IQNsin_cos(a, 4, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ3 input.\n *\n * @param a               IQ3 type input.\n *\n * @return                IQ3 type result of sine operation, in radians.\n */\nint32_t _IQ3sin(int32_t a)\n{\n    return __IQNsin_cos(a, 3, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ2 input.\n *\n * @param a               IQ2 type input.\n *\n * @return                IQ2 type result of sine operation, in radians.\n */\nint32_t _IQ2sin(int32_t a)\n{\n    return __IQNsin_cos(a, 2, TYPE_SIN, TYPE_RAD);\n}\n/**\n * @brief Computes the sine of an IQ1 input.\n *\n * @param a               IQ1 type input.\n *\n * @return                IQ1 type result of sine operation, in radians.\n */\nint32_t _IQ1sin(int32_t a)\n{\n    return __IQNsin_cos(a, 1, TYPE_SIN, TYPE_RAD);\n}\n\n/* IQ cos functions */\n/**\n * @brief Computes the cosine of an IQ29 input.\n *\n * @param a               IQ29 type input.\n *\n * @return                IQ29 type result of cosine operation, in radians.\n */\nint32_t _IQ29cos(int32_t a)\n{\n    return __IQNsin_cos(a, 29, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ28 input.\n *\n * @param a               IQ28 type input.\n *\n * @return                IQ28 type result of cosine operation, in radians.\n */\nint32_t _IQ28cos(int32_t a)\n{\n    return __IQNsin_cos(a, 28, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ27 input.\n *\n * @param a               IQ27 type input.\n *\n * @return                IQ27 type result of cosine operation, in radians.\n */\nint32_t _IQ27cos(int32_t a)\n{\n    return __IQNsin_cos(a, 27, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ26 input.\n *\n * @param a               IQ26 type input.\n *\n * @return                IQ26 type result of cosine operation, in radians.\n */\nint32_t _IQ26cos(int32_t a)\n{\n    return __IQNsin_cos(a, 26, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ25 input.\n *\n * @param a               IQ25 type input.\n *\n * @return                IQ25 type result of cosine operation, in radians.\n */\nint32_t _IQ25cos(int32_t a)\n{\n    return __IQNsin_cos(a, 25, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ24 input.\n *\n * @param a               IQ24 type input.\n *\n * @return                IQ24 type result of cosine operation, in radians.\n */\nint32_t _IQ24cos(int32_t a)\n{\n    return __IQNsin_cos(a, 24, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ23 input.\n *\n * @param a               IQ23 type input.\n *\n * @return                IQ23 type result of cosine operation, in radians.\n */\nint32_t _IQ23cos(int32_t a)\n{\n    return __IQNsin_cos(a, 23, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ22 input.\n *\n * @param a               IQ22 type input.\n *\n * @return                IQ22 type result of cosine operation, in radians.\n */\nint32_t _IQ22cos(int32_t a)\n{\n    return __IQNsin_cos(a, 22, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ21 input.\n *\n * @param a               IQ21 type input.\n *\n * @return                IQ21 type result of cosine operation, in radians.\n */\nint32_t _IQ21cos(int32_t a)\n{\n    return __IQNsin_cos(a, 21, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ20 input.\n *\n * @param a               IQ20 type input.\n *\n * @return                IQ20 type result of cosine operation, in radians.\n */\nint32_t _IQ20cos(int32_t a)\n{\n    return __IQNsin_cos(a, 20, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ19 input.\n *\n * @param a               IQ19 type input.\n *\n * @return                IQ19 type result of cosine operation, in radians.\n */\nint32_t _IQ19cos(int32_t a)\n{\n    return __IQNsin_cos(a, 19, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ18 input.\n *\n * @param a               IQ18 type input.\n *\n * @return                IQ18 type result of cosine operation, in radians.\n */\nint32_t _IQ18cos(int32_t a)\n{\n    return __IQNsin_cos(a, 18, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ17 input.\n *\n * @param a               IQ17 type input.\n *\n * @return                IQ17 type result of cosine operation, in radians.\n */\nint32_t _IQ17cos(int32_t a)\n{\n    return __IQNsin_cos(a, 17, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ16 input.\n *\n * @param a               IQ16 type input.\n *\n * @return                IQ16 type result of cosine operation, in radians.\n */\nint32_t _IQ16cos(int32_t a)\n{\n    return __IQNsin_cos(a, 16, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ15 input.\n *\n * @param a               IQ15 type input.\n *\n * @return                IQ15 type result of cosine operation, in radians.\n */\nint32_t _IQ15cos(int32_t a)\n{\n    return __IQNsin_cos(a, 15, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ14 input.\n *\n * @param a               IQ14 type input.\n *\n * @return                IQ14 type result of cosine operation, in radians.\n */\nint32_t _IQ14cos(int32_t a)\n{\n    return __IQNsin_cos(a, 14, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ13 input.\n *\n * @param a               IQ13 type input.\n *\n * @return                IQ13 type result of cosine operation, in radians.\n */\nint32_t _IQ13cos(int32_t a)\n{\n    return __IQNsin_cos(a, 13, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ12 input.\n *\n * @param a               IQ12 type input.\n *\n * @return                IQ12 type result of cosine operation, in radians.\n */\nint32_t _IQ12cos(int32_t a)\n{\n    return __IQNsin_cos(a, 12, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ11 input.\n *\n * @param a               IQ11 type input.\n *\n * @return                IQ11 type result of cosine operation, in radians.\n */\nint32_t _IQ11cos(int32_t a)\n{\n    return __IQNsin_cos(a, 11, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ10 input.\n *\n * @param a               IQ10 type input.\n *\n * @return                IQ10 type result of cosine operation, in radians.\n */\nint32_t _IQ10cos(int32_t a)\n{\n    return __IQNsin_cos(a, 10, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ9 input.\n *\n * @param a               IQ9 type input.\n *\n * @return                IQ9 type result of cosine operation, in radians.\n */\nint32_t _IQ9cos(int32_t a)\n{\n    return __IQNsin_cos(a, 9, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ8 input.\n *\n * @param a               IQ8 type input.\n *\n * @return                IQ8 type result of cosine operation, in radians.\n */\nint32_t _IQ8cos(int32_t a)\n{\n    return __IQNsin_cos(a, 8, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ7 input.\n *\n * @param a               IQ7 type input.\n *\n * @return                IQ7 type result of cosine operation, in radians.\n */\nint32_t _IQ7cos(int32_t a)\n{\n    return __IQNsin_cos(a, 7, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ6 input.\n *\n * @param a               IQ6 type input.\n *\n * @return                IQ6 type result of cosine operation, in radians.\n */\nint32_t _IQ6cos(int32_t a)\n{\n    return __IQNsin_cos(a, 6, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ5 input.\n *\n * @param a               IQ5 type input.\n *\n * @return                IQ5 type result of cosine operation, in radians.\n */\nint32_t _IQ5cos(int32_t a)\n{\n    return __IQNsin_cos(a, 5, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ4 input.\n *\n * @param a               IQ4 type input.\n *\n * @return                IQ4 type result of cosine operation, in radians.\n */\nint32_t _IQ4cos(int32_t a)\n{\n    return __IQNsin_cos(a, 4, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ3 input.\n *\n * @param a               IQ3 type input.\n *\n * @return                IQ3 type result of cosine operation, in radians.\n */\nint32_t _IQ3cos(int32_t a)\n{\n    return __IQNsin_cos(a, 3, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ2 input.\n *\n * @param a               IQ2 type input.\n *\n * @return                IQ2 type result of cosine operation, in radians.\n */\nint32_t _IQ2cos(int32_t a)\n{\n    return __IQNsin_cos(a, 2, TYPE_COS, TYPE_RAD);\n}\n/**\n * @brief Computes the cosine of an IQ1 input.\n *\n * @param a               IQ1 type input.\n *\n * @return                IQ1 type result of cosine operation, in radians.\n */\nint32_t _IQ1cos(int32_t a)\n{\n    return __IQNsin_cos(a, 1, TYPE_COS, TYPE_RAD);\n}\n\n/* IQ sinPU functions */\n/**\n * @brief Computes the sine of an IQ31 input.\n *\n * @param a               IQ31 type input.\n *\n * @return                IQ31 type per-unit result of sine operation.\n */\nint32_t _IQ31sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 31, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ30 input.\n *\n * @param a               IQ30 type input.\n *\n * @return                IQ30 type per-unit result of sine operation.\n */\nint32_t _IQ30sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 30, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ29 input.\n *\n * @param a               IQ29 type input.\n *\n * @return                IQ29 type per-unit result of sine operation.\n */\nint32_t _IQ29sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 29, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ28 input.\n *\n * @param a               IQ28 type input.\n *\n * @return                IQ28 type per-unit result of sine operation.\n */\nint32_t _IQ28sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 28, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ27 input.\n *\n * @param a               IQ27 type input.\n *\n * @return                IQ27 type per-unit result of sine operation.\n */\nint32_t _IQ27sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 27, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ26 input.\n *\n * @param a               IQ26 type input.\n *\n * @return                IQ26 type per-unit result of sine operation.\n */\nint32_t _IQ26sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 26, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ25 input.\n *\n * @param a               IQ25 type input.\n *\n * @return                IQ25 type per-unit result of sine operation.\n */\nint32_t _IQ25sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 25, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ24 input.\n *\n * @param a               IQ24 type input.\n *\n * @return                IQ24 type per-unit result of sine operation.\n */\nint32_t _IQ24sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 24, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ23 input.\n *\n * @param a               IQ23 type input.\n *\n * @return                IQ23 type per-unit result of sine operation.\n */\nint32_t _IQ23sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 23, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ22 input.\n *\n * @param a               IQ22 type input.\n *\n * @return                IQ22 type per-unit result of sine operation.\n */\nint32_t _IQ22sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 22, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ21 input.\n *\n * @param a               IQ21 type input.\n *\n * @return                IQ21 type per-unit result of sine operation.\n */\nint32_t _IQ21sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 21, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ20 input.\n *\n * @param a               IQ20 type input.\n *\n * @return                IQ20 type per-unit result of sine operation.\n */\nint32_t _IQ20sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 20, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ19 input.\n *\n * @param a               IQ19 type input.\n *\n * @return                IQ19 type per-unit result of sine operation.\n */\nint32_t _IQ19sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 19, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ18 input.\n *\n * @param a               IQ18 type input.\n *\n * @return                IQ18 type per-unit result of sine operation.\n */\nint32_t _IQ18sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 18, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ17 input.\n *\n * @param a               IQ17 type input.\n *\n * @return                IQ17 type per-unit result of sine operation.\n */\nint32_t _IQ17sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 17, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ16 input.\n *\n * @param a               IQ16 type input.\n *\n * @return                IQ16 type per-unit result of sine operation.\n */\nint32_t _IQ16sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 16, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ15 input.\n *\n * @param a               IQ15 type input.\n *\n * @return                IQ15 type per-unit result of sine operation.\n */\nint32_t _IQ15sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 15, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ14 input.\n *\n * @param a               IQ14 type input.\n *\n * @return                IQ14 type per-unit result of sine operation.\n */\nint32_t _IQ14sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 14, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ13 input.\n *\n * @param a               IQ13 type input.\n *\n * @return                IQ13 type per-unit result of sine operation.\n */\nint32_t _IQ13sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 13, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ12 input.\n *\n * @param a               IQ12 type input.\n *\n * @return                IQ12 type per-unit result of sine operation.\n */\nint32_t _IQ12sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 12, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ11 input.\n *\n * @param a               IQ11 type input.\n *\n * @return                IQ11 type per-unit result of sine operation.\n */\nint32_t _IQ11sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 11, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ10 input.\n *\n * @param a               IQ10 type input.\n *\n * @return                IQ10 type per-unit result of sine operation.\n */\nint32_t _IQ10sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 10, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ9 input.\n *\n * @param a               IQ9 type input.\n *\n * @return                IQ9 type per-unit result of sine operation.\n */\nint32_t _IQ9sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 9, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ8 input.\n *\n * @param a               IQ8 type input.\n *\n * @return                IQ8 type per-unit result of sine operation.\n */\nint32_t _IQ8sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 8, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ7 input.\n *\n * @param a               IQ7 type input.\n *\n * @return                IQ7 type per-unit result of sine operation.\n */\nint32_t _IQ7sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 7, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ6 input.\n *\n * @param a               IQ6 type input.\n *\n * @return                IQ6 type per-unit result of sine operation.\n */\nint32_t _IQ6sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 6, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ5 input.\n *\n * @param a               IQ5 type input.\n *\n * @return                IQ5 type per-unit result of sine operation.\n */\nint32_t _IQ5sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 5, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ4 input.\n *\n * @param a               IQ4 type input.\n *\n * @return                IQ4 type per-unit result of sine operation.\n */\nint32_t _IQ4sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 4, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ3 input.\n *\n * @param a               IQ3 type input.\n *\n * @return                IQ3 type per-unit result of sine operation.\n */\nint32_t _IQ3sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 3, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ2 input.\n *\n * @param a               IQ2 type input.\n *\n * @return                IQ2 type per-unit result of sine operation.\n */\nint32_t _IQ2sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 2, TYPE_SIN, TYPE_PU);\n}\n/**\n * @brief Computes the sine of an IQ1 input.\n *\n * @param a               IQ1 type input.\n *\n * @return                IQ1 type per-unit result of sine operation.\n */\nint32_t _IQ1sinPU(int32_t a)\n{\n    return __IQNsin_cos(a, 1, TYPE_SIN, TYPE_PU);\n}\n\n/* IQ cosPU functions */\n/**\n * @brief Computes the cosine of an IQ31 input.\n *\n * @param a               IQ31 type input.\n *\n * @return                IQ31 type per-unit result of cosine operation.\n */\nint32_t _IQ31cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 31, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ30 input.\n *\n * @param a               IQ30 type input.\n *\n * @return                IQ30 type per-unit result of cosine operation.\n */\nint32_t _IQ30cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 30, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ29 input.\n *\n * @param a               IQ29 type input.\n *\n * @return                IQ29 type per-unit result of cosine operation.\n */\nint32_t _IQ29cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 29, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ28 input.\n *\n * @param a               IQ28 type input.\n *\n * @return                IQ28 type per-unit result of cosine operation.\n */\nint32_t _IQ28cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 28, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ27 input.\n *\n * @param a               IQ27 type input.\n *\n * @return                IQ27 type per-unit result of cosine operation.\n */\nint32_t _IQ27cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 27, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ26 input.\n *\n * @param a               IQ26 type input.\n *\n * @return                IQ26 type per-unit result of cosine operation.\n */\nint32_t _IQ26cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 26, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ25 input.\n *\n * @param a               IQ25 type input.\n *\n * @return                IQ25 type per-unit result of cosine operation.\n */\nint32_t _IQ25cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 25, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ24 input.\n *\n * @param a               IQ24 type input.\n *\n * @return                IQ24 type per-unit result of cosine operation.\n */\nint32_t _IQ24cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 24, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ23 input.\n *\n * @param a               IQ23 type input.\n *\n * @return                IQ23 type per-unit result of cosine operation.\n */\nint32_t _IQ23cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 23, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ22 input.\n *\n * @param a               IQ22 type input.\n *\n * @return                IQ22 type per-unit result of cosine operation.\n */\nint32_t _IQ22cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 22, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ21 input.\n *\n * @param a               IQ21 type input.\n *\n * @return                IQ21 type per-unit result of cosine operation.\n */\nint32_t _IQ21cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 21, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ20 input.\n *\n * @param a               IQ20 type input.\n *\n * @return                IQ20 type per-unit result of cosine operation.\n */\nint32_t _IQ20cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 20, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ19 input.\n *\n * @param a               IQ19 type input.\n *\n * @return                IQ19 type per-unit result of cosine operation.\n */\nint32_t _IQ19cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 19, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ18 input.\n *\n * @param a               IQ18 type input.\n *\n * @return                IQ18 type per-unit result of cosine operation.\n */\nint32_t _IQ18cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 18, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ17 input.\n *\n * @param a               IQ17 type input.\n *\n * @return                IQ17 type per-unit result of cosine operation.\n */\nint32_t _IQ17cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 17, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ16 input.\n *\n * @param a               IQ16 type input.\n *\n * @return                IQ16 type per-unit result of cosine operation.\n */\nint32_t _IQ16cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 16, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ15 input.\n *\n * @param a               IQ15 type input.\n *\n * @return                IQ15 type per-unit result of cosine operation.\n */\nint32_t _IQ15cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 15, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ14 input.\n *\n * @param a               IQ14 type input.\n *\n * @return                IQ14 type per-unit result of cosine operation.\n */\nint32_t _IQ14cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 14, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ13 input.\n *\n * @param a               IQ13 type input.\n *\n * @return                IQ13 type per-unit result of cosine operation.\n */\nint32_t _IQ13cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 13, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ12 input.\n *\n * @param a               IQ12 type input.\n *\n * @return                IQ12 type per-unit result of cosine operation.\n */\nint32_t _IQ12cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 12, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ11 input.\n *\n * @param a               IQ11 type input.\n *\n * @return                IQ11 type per-unit result of cosine operation.\n */\nint32_t _IQ11cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 11, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ10 input.\n *\n * @param a               IQ10 type input.\n *\n * @return                IQ10 type per-unit result of cosine operation.\n */\nint32_t _IQ10cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 10, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ9 input.\n *\n * @param a               IQ9 type input.\n *\n * @return                IQ9 type per-unit result of cosine operation.\n */\nint32_t _IQ9cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 9, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ8 input.\n *\n * @param a               IQ8 type input.\n *\n * @return                IQ8 type per-unit result of cosine operation.\n */\nint32_t _IQ8cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 8, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ7 input.\n *\n * @param a               IQ7 type input.\n *\n * @return                IQ7 type per-unit result of cosine operation.\n */\nint32_t _IQ7cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 7, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ6 input.\n *\n * @param a               IQ6 type input.\n *\n * @return                IQ6 type per-unit result of cosine operation.\n */\nint32_t _IQ6cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 6, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ5 input.\n *\n * @param a               IQ5 type input.\n *\n * @return                IQ5 type per-unit result of cosine operation.\n */\nint32_t _IQ5cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 5, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ4 input.\n *\n * @param a               IQ4 type input.\n *\n * @return                IQ4 type per-unit result of cosine operation.\n */\nint32_t _IQ4cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 4, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ3 input.\n *\n * @param a               IQ3 type input.\n *\n * @return                IQ3 type per-unit result of cosine operation.\n */\nint32_t _IQ3cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 3, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ2 input.\n *\n * @param a               IQ2 type input.\n *\n * @return                IQ2 type per-unit result of cosine operation.\n */\nint32_t _IQ2cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 2, TYPE_COS, TYPE_PU);\n}\n/**\n * @brief Computes the cosine of an IQ1 input.\n *\n * @param a               IQ1 type input.\n *\n * @return                IQ1 type per-unit result of cosine operation.\n */\nint32_t _IQ1cosPU(int32_t a)\n{\n    return __IQNsin_cos(a, 1, TYPE_COS, TYPE_PU);\n}\n"
  },
  {
    "path": "iqmath/_IQNfunctions/_IQNsqrt.c",
    "content": "/*!****************************************************************************\n *  @file       _IQNsqrt.c\n *  @brief      Functions to compute square root, inverse square root and the\n *              magnitude of two IQN inputs.\n *\n *  <hr>\n ******************************************************************************/\n\n#include <stdint.h>\n\n#include \"../support/support.h\"\n#include \"_IQNtables.h\"\n#include \"../include/IQmathLib.h\"\n\n/*!\n * @brief Specifies inverse square root operation type.\n */\n#define TYPE_ISQRT   (0)\n/*!\n * @brief Specifies square root operation type.\n */\n#define TYPE_SQRT    (1)\n/*!\n * @brief Specifies magnitude operation type.\n */\n#define TYPE_MAG     (2)\n/*!\n * @brief Specifies inverse magnitude operation type.\n */\n#define TYPE_IMAG    (3)\n\n/**\n * @brief Calculate square root, inverse square root and the magnitude of two inputs.\n *\n * @param iqNInputX         IQN type input x.\n * @param iqNInputY         IQN type input y.\n * @param type              Operation type.\n * @param q_value           IQ format.\n *\n * @return                  IQN type result of the square root or magnitude operation.\n */\n/*\n * Calculate square root, inverse square root and the magnitude of two inputs\n * using a Newton-Raphson iterative method. This method takes an initial guess\n * and performs an error correction with each iteration. The equation is:\n *\n *     x1 = x0 - f(x0)/f'(x0)\n *\n * Where f' is the derivative of f. The approximation for inverse square root\n * is:\n *\n *     g' = g * (1.5 - (x/2) * g * g)\n *\n *     g' = new guess approximation\n *     g = best guess approximation\n *     x = input\n *\n * The inverse square root is multiplied by the initial input x to get the\n * square root result for square root and magnitude functions.\n *\n *     root(x) = x * 1/root(x)\n */\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNsqrt)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n__STATIC_INLINE int_fast32_t __IQNsqrt(int_fast32_t iqNInputX, int_fast32_t iqNInputY, const int8_t q_value, const int8_t type)\n{\n    uint8_t ui8Index;\n    uint8_t ui8Loops;\n    int_fast16_t i16Exponent;\n    uint_fast16_t ui16IntState;\n    uint_fast16_t ui16MPYState;\n    uint_fast32_t uiq30Guess;\n    uint_fast32_t uiq30Result;\n    uint_fast32_t uiq31Result;\n    uint_fast32_t uiq32Input;\n\n    /* If the type is (inverse) magnitude we need to calculate x^2 + y^2 first. */\n    if (type == TYPE_MAG || type == TYPE_IMAG) {\n        uint_fast64_t ui64Sum;\n\n        __mpy_start(&ui16IntState, &ui16MPYState);\n\n        /* Calculate x^2 */\n        ui64Sum = __mpyx(iqNInputX, iqNInputX);\n\n        /* Calculate y^2 and add to x^2 */\n        ui64Sum += __mpyx(iqNInputY, iqNInputY);\n\n        __mpy_stop(&ui16IntState, &ui16MPYState);\n\n        /* Return if the magnitude is simply zero. */\n        if (ui64Sum == 0) {\n            return 0;\n        }\n\n        /*\n         * Initialize the exponent to positive for magnitude, negative for\n         * inverse magnitude.\n         */\n        if (type == TYPE_MAG) {\n            i16Exponent = (32 - q_value);\n        } else {\n            i16Exponent = -(32 - q_value);\n        }\n\n        /* Shift to iq64 by keeping track of exponent. */\n        while ((uint_fast16_t)(ui64Sum >> 48) < 0x4000) {\n            ui64Sum <<= 2;\n            /* Decrement exponent for mag */\n            if (type == TYPE_MAG) {\n                i16Exponent--;\n            }\n            /* Increment exponent for imag */\n            else {\n                i16Exponent++;\n            }\n        }\n\n        /* Shift ui64Sum to unsigned iq32 and set as uiq32Input */\n        uiq32Input = (uint_fast32_t)(ui64Sum >> 32);\n    } else {\n        /* check sign of input */\n        if (iqNInputX <= 0) {\n            return 0;\n        }\n\n        /* If the q_value gives an odd starting exponent make it even. */\n        if ((32 - q_value) % 2 == 1) {\n            iqNInputX <<= 1;\n            /* Start with positive exponent for sqrt */\n            if (type == TYPE_SQRT) {\n                i16Exponent = ((32 - q_value) - 1) >> 1;\n            }\n            /* start with negative exponent for isqrt */\n            else {\n                i16Exponent = -(((32 - q_value) - 1) >> 1);\n            }\n        } else {\n            /* start with positive exponent for sqrt */\n            if (type == TYPE_SQRT) {\n                i16Exponent = (32 - q_value) >> 1;\n            }\n            /* start with negative exponent for isqrt */\n            else {\n                i16Exponent = -((32 - q_value) >> 1);\n            }\n        }\n\n        /* Save input as unsigned iq32. */\n        uiq32Input = (uint_fast32_t)iqNInputX;\n\n        /* Shift to iq32 by keeping track of exponent */\n        while ((uint_fast16_t)(uiq32Input >> 16) < 0x4000) {\n            uiq32Input <<= 2;\n            /* Decrement exponent for sqrt and mag */\n            if (type) {\n                i16Exponent--;\n            }\n            /* Increment exponent for isqrt */\n            else {\n                i16Exponent++;\n            }\n        }\n    }\n\n\n    /* Use left most byte as index into lookup table (range: 32-128) */\n    ui8Index = uiq32Input >> 25;\n    ui8Index -= 32;\n    uiq30Guess = (uint_fast32_t)_IQ14sqrt_lookup[ui8Index] << 16;\n\n    /*\n     * Mark the start of any multiplies. This will disable interrupts and set\n     * the multiplier to fractional mode. This is designed to reduce overhead\n     * of constantly switching states when using repeated multiplies (MSP430\n     * only).\n     */\n    __mpyf_start(&ui16IntState, &ui16MPYState);\n\n    /*\n     * Set the loop counter:\n     *\n     *     iq1 <= q_value < 24 - 2 loops\n     *     iq22 <= q_value <= 31 - 3 loops\n     */\n    if (q_value < 24) {\n        ui8Loops = 2;\n    } else {\n        ui8Loops = 3;\n    }\n\n    /* Iterate through Newton-Raphson algorithm. */\n    while (ui8Loops--) {\n        /* x*g */\n        uiq31Result = __mpyf_ul(uiq32Input, uiq30Guess);\n\n        /* x*g*g */\n        uiq30Result = __mpyf_ul(uiq31Result, uiq30Guess);\n\n        /* 3 - x*g*g */\n        uiq30Result = -(uiq30Result - 0xC0000000);\n\n        /*\n         * g/2*(3 - x*g*g)\n         * uiq30Guess = uiq31Guess/2\n         */\n        uiq30Guess = __mpyf_ul(uiq30Guess, uiq30Result);\n    }\n\n    /* Calculate sqrt(x) for both sqrt and mag */\n    if (type == TYPE_SQRT || type == TYPE_MAG) {\n        /*\n         * uiq30Guess contains the inverse square root approximation, multiply\n         * by uiq32Input to get square root result.\n         */\n        uiq31Result = __mpyf_ul(uiq30Guess, uiq32Input);\n\n        __mpy_stop(&ui16IntState, &ui16MPYState);\n\n        /*\n         * Shift the result right by 31 - q_value.\n         */\n        i16Exponent -= (31 - q_value);\n\n        /* Saturate value for any shift larger than 1 (only need this for mag) */\n        if (type == TYPE_MAG) {\n            if (i16Exponent > 0) {\n                return 0x7fffffff;\n            }\n        }\n\n        /* Shift left by 1 check only needed for iq30 and iq31 mag/sqrt */\n        if (q_value >= 30) {\n            if (i16Exponent > 0) {\n                uiq31Result <<= 1;\n                return uiq31Result;\n            }\n        }\n    }\n    /* Separate handling for isqrt and imag. */\n    else {\n        __mpy_stop(&ui16IntState, &ui16MPYState);\n\n        /*\n         * Shift the result right by 31 - q_value, add one since we use the uiq30\n         * result without shifting.\n         */\n        i16Exponent = i16Exponent - (31 - q_value) + 1;\n        uiq31Result = uiq30Guess;\n\n        /* Saturate any positive non-zero exponent for isqrt. */\n        if (i16Exponent > 0) {\n            return 0x7fffffff;\n        }\n    }\n\n    /* Shift uiq31Result right by -exponent */\n    if (i16Exponent <= -32) {\n        return 0;\n    }\n    if (i16Exponent <= -16) {\n        uiq31Result >>= 16;\n        i16Exponent += 16;\n    }\n    if (i16Exponent <= -8) {\n        uiq31Result >>= 8;\n        i16Exponent += 8;\n    }\n    while (i16Exponent < -1) {\n        uiq31Result >>= 1;\n        i16Exponent++;\n    }\n    if (i16Exponent) {\n        uiq31Result++;\n        uiq31Result >>= 1;\n    }\n\n    return uiq31Result;\n}\n\n#if ((defined (__IQMATH_USE_MATHACL__)) && (defined (__MSPM0_HAS_MATHACL__)))\n/**\n * @brief Calculate square root of an  IQN input, using MathACL.\n *\n * @param iqNInputX         IQN type input.\n * @param q_value           IQ format.\n *\n * @return                  IQN type result of the square root operation.\n */\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNsqrt_MathACL)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n__STATIC_INLINE int_fast32_t __IQNsqrt_MathACL(int_fast32_t iqNInputX, const int8_t q_value)\n{\n    /* check sign of input */\n    if (iqNInputX <= 0) {\n        return 0;\n    }\n\n    /* Scale factor computation:\n     * output: IQ30 format value whose square root is to be computed by MATHACL\n     * scale_factor: (n) where the input has been divided by 2^(2n) to render IQ30\n     * value in the range (1,2).\n     */\n    uint32_t input, output;\n    uint8_t scale_factor;\n    uint8_t n = 0;\n\n    input = iqNInputX;\n    /* check input is within 32-bit boundaries */\n    if (input & 0x80000000) {\n        scale_factor = 0;\n        output = input;\n    } else {\n        n = 0;\n        /* check while input != IQ30(1.0) */\n        while ((input & 0x40000000) == 0) {\n            n++;\n            /* multiply by 2 until reaching IQ30 [1.0,2.0 range] */\n            input <<= 1;\n        }\n        /*\n         * Scale factor: take into account the shift from q_value to IQ30, the remaining value\n         * is the scale factor such that scaled number = (nonscaled number)^(2^scale_factor)\n         */\n        scale_factor = (30 - q_value) - n;\n        output = input;\n    }\n    /* SQRT MATHACL Operation\n     * write control\n     * CTL parameters are: sqrt operation | number of iterations | scale factor\n     */\n    MATHACL->CTL = 5 | (31 << 24) | (scale_factor << 16);\n    /* write operands to HWA\n     * write to OP1 is the trigger\n     */\n    MATHACL->OP1 = output;\n    /* read sqrt\n     * shift output from IQ16 to q_value\n     */\n    if (q_value > 16) {\n        return (uint_fast32_t)MATHACL->RES1 << (q_value - 16);\n    } else {\n        return (uint_fast32_t)MATHACL->RES1 >> (16 - q_value);\n    }\n}\n#endif\n\n#if ((!defined (__IQMATH_USE_MATHACL__)) || (!defined (__MSPM0_HAS_MATHACL__)))\n/* RTS SQRT */\n/**\n * @brief Calculate square root of an IQ31 input.\n *\n * @param a                 IQ31 type input.\n *\n * @return                  IQ31 type result of the square root operation.\n */\nint32_t _IQ31sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 31, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ30 input.\n *\n * @param a                 IQ30 type input.\n *\n * @return                  IQ30 type result of the square root operation.\n */\nint32_t _IQ30sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 30, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ29 input.\n *\n * @param a                 IQ29 type input.\n *\n * @return                  IQ29 type result of the square root operation.\n */\nint32_t _IQ29sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 29, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ28 input.\n *\n * @param a                 IQ28 type input.\n *\n * @return                  IQ28 type result of the square root operation.\n */\nint32_t _IQ28sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 28, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ27 input.\n *\n * @param a                 IQ27 type input.\n *\n * @return                  IQ27 type result of the square root operation.\n */\nint32_t _IQ27sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 27, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ26 input.\n *\n * @param a                 IQ26 type input.\n *\n * @return                  IQ26 type result of the square root operation.\n */\nint32_t _IQ26sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 26, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ25 input.\n *\n * @param a                 IQ25 type input.\n *\n * @return                  IQ25 type result of the square root operation.\n */\nint32_t _IQ25sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 25, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ24 input.\n *\n * @param a                 IQ24 type input.\n *\n * @return                  IQ24 type result of the square root operation.\n */\nint32_t _IQ24sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 24, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ23 input.\n *\n * @param a                 IQ23 type input.\n *\n * @return                  IQ23 type result of the square root operation.\n */\nint32_t _IQ23sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 23, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ22 input.\n *\n * @param a                 IQ22 type input.\n *\n * @return                  IQ22 type result of the square root operation.\n */\nint32_t _IQ22sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 22, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ21 input.\n *\n * @param a                 IQ21 type input.\n *\n * @return                  IQ21 type result of the square root operation.\n */\nint32_t _IQ21sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 21, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ20 input.\n *\n * @param a                 IQ20 type input.\n *\n * @return                  IQ20 type result of the square root operation.\n */\nint32_t _IQ20sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 20, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ19 input.\n *\n * @param a                 IQ19 type input.\n *\n * @return                  IQ19 type result of the square root operation.\n */\nint32_t _IQ19sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 19, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ18 input.\n *\n * @param a                 IQ18 type input.\n *\n * @return                  IQ18 type result of the square root operation.\n */\nint32_t _IQ18sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 18, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ17 input.\n *\n * @param a                 IQ17 type input.\n *\n * @return                  IQ17 type result of the square root operation.\n */\nint32_t _IQ17sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 17, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ16 input.\n *\n * @param a                 IQ16 type input.\n *\n * @return                  IQ16 type result of the square root operation.\n */\nint32_t _IQ16sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 16, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ15 input.\n *\n * @param a                 IQ15 type input.\n *\n * @return                  IQ15 type result of the square root operation.\n */\nint32_t _IQ15sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 15, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ14 input.\n *\n * @param a                 IQ14 type input.\n *\n * @return                  IQ14 type result of the square root operation.\n */\nint32_t _IQ14sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 14, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ13 input.\n *\n * @param a                 IQ13 type input.\n *\n * @return                  IQ13 type result of the square root operation.\n */\nint32_t _IQ13sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 13, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ12 input.\n *\n * @param a                 IQ12 type input.\n *\n * @return                  IQ12 type result of the square root operation.\n */\nint32_t _IQ12sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 12, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ11 input.\n *\n * @param a                 IQ11 type input.\n *\n * @return                  IQ11 type result of the square root operation.\n */\nint32_t _IQ11sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 11, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ10 input.\n *\n * @param a                 IQ10 type input.\n *\n * @return                  IQ10 type result of the square root operation.\n */\nint32_t _IQ10sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 10, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ9 input.\n *\n * @param a                 IQ9 type input.\n *\n * @return                  IQ9 type result of the square root operation.\n */\nint32_t _IQ9sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 9, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ8 input.\n *\n * @param a                 IQ8 type input.\n *\n * @return                  IQ8 type result of the square root operation.\n */\nint32_t _IQ8sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 8, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ7 input.\n *\n * @param a                 IQ7 type input.\n *\n * @return                  IQ7 type result of the square root operation.\n */\nint32_t _IQ7sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 7, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ6 input.\n *\n * @param a                 IQ6 type input.\n *\n * @return                  IQ6 type result of the square root operation.\n */\nint32_t _IQ6sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 6, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ5 input.\n *\n * @param a                 IQ5 type input.\n *\n * @return                  IQ5 type result of the square root operation.\n */\nint32_t _IQ5sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 5, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ4 input.\n *\n * @param a                 IQ4 type input.\n *\n * @return                  IQ4 type result of the square root operation.\n */\nint32_t _IQ4sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 4, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ3 input.\n *\n * @param a                 IQ3 type input.\n *\n * @return                  IQ3 type result of the square root operation.\n */\nint32_t _IQ3sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 3, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ2 input.\n *\n * @param a                 IQ2 type input.\n *\n * @return                  IQ2 type result of the square root operation.\n */\nint32_t _IQ2sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 2, TYPE_SQRT);\n}\n/**\n * @brief Calculate square root of an IQ1 input.\n *\n * @param a                 IQ1 type input.\n *\n * @return                  IQ1 type result of the square root operation.\n */\nint32_t _IQ1sqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 1, TYPE_SQRT);\n}\n#else\n/* MATHACL SQRT */\n/**\n * @brief Calculate square root of an IQ31 input, using MathACL.\n *\n * @param a                 IQ31 type input.\n *\n * @return                  IQ31 type result of the square root operation.\n */\nint32_t _IQ31sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 31);\n}\n/**\n * @brief Calculate square root of an IQ30 input, using MathACL.\n *\n * @param a                 IQ30 type input.\n *\n * @return                  IQ30 type result of the square root operation.\n */\nint32_t _IQ30sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 30);\n}\n/**\n * @brief Calculate square root of an IQ29 input, using MathACL.\n *\n * @param a                 IQ29 type input.\n *\n * @return                  IQ29 type result of the square root operation.\n */\nint32_t _IQ29sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 29);\n}\n/**\n * @brief Calculate square root of an IQ28 input, using MathACL.\n *\n * @param a                 IQ28 type input.\n *\n * @return                  IQ28 type result of the square root operation.\n */\nint32_t _IQ28sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 28);\n}\n/**\n * @brief Calculate square root of an IQ27 input, using MathACL.\n *\n * @param a                 IQ27 type input.\n *\n * @return                  IQ27 type result of the square root operation.\n */\nint32_t _IQ27sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 27);\n}\n/**\n * @brief Calculate square root of an IQ26 input, using MathACL.\n *\n * @param a                 IQ26 type input.\n *\n * @return                  IQ26 type result of the square root operation.\n */\nint32_t _IQ26sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 26);\n}\n/**\n * @brief Calculate square root of an IQ25 input, using MathACL.\n *\n * @param a                 IQ25 type input.\n *\n * @return                  IQ25 type result of the square root operation.\n */\nint32_t _IQ25sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 25);\n}\n/**\n * @brief Calculate square root of an IQ24 input, using MathACL.\n *\n * @param a                 IQ24 type input.\n *\n * @return                  IQ24 type result of the square root operation.\n */\nint32_t _IQ24sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 24);\n}\n/**\n * @brief Calculate square root of an IQ23 input, using MathACL.\n *\n * @param a                 IQ23 type input.\n *\n * @return                  IQ23 type result of the square root operation.\n */\nint32_t _IQ23sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 23);\n}\n/**\n * @brief Calculate square root of an IQ22 input, using MathACL.\n *\n * @param a                 IQ22 type input.\n *\n * @return                  IQ22 type result of the square root operation.\n */\nint32_t _IQ22sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 22);\n}\n/**\n * @brief Calculate square root of an IQ21 input, using MathACL.\n *\n * @param a                 IQ21 type input.\n *\n * @return                  IQ21 type result of the square root operation.\n */\nint32_t _IQ21sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 21);\n}\n/**\n * @brief Calculate square root of an IQ20 input, using MathACL.\n *\n * @param a                 IQ20 type input.\n *\n * @return                  IQ20 type result of the square root operation.\n */\nint32_t _IQ20sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 20);\n}\n/**\n * @brief Calculate square root of an IQ19 input, using MathACL.\n *\n * @param a                 IQ19 type input.\n *\n * @return                  IQ19 type result of the square root operation.\n */\nint32_t _IQ19sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 19);\n}\n/**\n * @brief Calculate square root of an IQ18 input, using MathACL.\n *\n * @param a                 IQ18 type input.\n *\n * @return                  IQ18 type result of the square root operation.\n */\nint32_t _IQ18sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 18);\n}\n/**\n * @brief Calculate square root of an IQ17 input, using MathACL.\n *\n * @param a                 IQ17 type input.\n *\n * @return                  IQ17 type result of the square root operation.\n */\nint32_t _IQ17sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 17);\n}\n/**\n * @brief Calculate square root of an IQ16 input, using MathACL.\n *\n * @param a                 IQ16 type input.\n *\n * @return                  IQ16 type result of the square root operation.\n */\nint32_t _IQ16sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 16);\n}\n/**\n * @brief Calculate square root of an IQ15 input, using MathACL.\n *\n * @param a                 IQ15 type input.\n *\n * @return                  IQ15 type result of the square root operation.\n */\nint32_t _IQ15sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 15);\n}\n/**\n * @brief Calculate square root of an IQ14 input, using MathACL.\n *\n * @param a                 IQ14 type input.\n *\n * @return                  IQ14 type result of the square root operation.\n */\nint32_t _IQ14sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 14);\n}\n/**\n * @brief Calculate square root of an IQ13 input, using MathACL.\n *\n * @param a                 IQ13 type input.\n *\n * @return                  IQ13 type result of the square root operation.\n */\nint32_t _IQ13sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 13);\n}\n/**\n * @brief Calculate square root of an IQ12 input, using MathACL.\n *\n * @param a                 IQ12 type input.\n *\n * @return                  IQ12 type result of the square root operation.\n */\nint32_t _IQ12sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 12);\n}\n/**\n * @brief Calculate square root of an IQ11 input, using MathACL.\n *\n * @param a                 IQ11 type input.\n *\n * @return                  IQ11 type result of the square root operation.\n */\nint32_t _IQ11sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 11);\n}\n/**\n * @brief Calculate square root of an IQ10 input, using MathACL.\n *\n * @param a                 IQ10 type input.\n *\n * @return                  IQ10 type result of the square root operation.\n */\nint32_t _IQ10sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 10);\n}\n/**\n * @brief Calculate square root of an IQ9 input, using MathACL.\n *\n * @param a                 IQ9 type input.\n *\n * @return                  IQ9 type result of the square root operation.\n */\nint32_t _IQ9sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 9);\n}\n/**\n * @brief Calculate square root of an IQ8 input, using MathACL.\n *\n * @param a                 IQ8 type input.\n *\n * @return                  IQ8 type result of the square root operation.\n */\nint32_t _IQ8sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 8);\n}\n/**\n * @brief Calculate square root of an IQ7 input, using MathACL.\n *\n * @param a                 IQ7 type input.\n *\n * @return                  IQ7 type result of the square root operation.\n */\nint32_t _IQ7sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 7);\n}\n/**\n * @brief Calculate square root of an IQ6 input, using MathACL.\n *\n * @param a                 IQ6 type input.\n *\n * @return                  IQ6 type result of the square root operation.\n */\nint32_t _IQ6sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 6);\n}\n/**\n * @brief Calculate square root of an IQ5 input, using MathACL.\n *\n * @param a                 IQ5 type input.\n *\n * @return                  IQ5 type result of the square root operation.\n */\nint32_t _IQ5sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 5);\n}\n/**\n * @brief Calculate square root of an IQ4 input, using MathACL.\n *\n * @param a                 IQ4 type input.\n *\n * @return                  IQ4 type result of the square root operation.\n */\nint32_t _IQ4sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 4);\n}\n/**\n * @brief Calculate square root of an IQ3 input, using MathACL.\n *\n * @param a                 IQ3 type input.\n *\n * @return                  IQ3 type result of the square root operation.\n */\nint32_t _IQ3sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 3);\n}\n/**\n * @brief Calculate square root of an IQ2 input, using MathACL.\n *\n * @param a                 IQ2 type input.\n *\n * @return                  IQ2 type result of the square root operation.\n */\nint32_t _IQ2sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 2);\n}\n/**\n * @brief Calculate square root of an IQ1 input, using MathACL.\n *\n * @param a                 IQ1 type input.\n *\n * @return                  IQ1 type result of the square root operation.\n */\nint32_t _IQ1sqrt(int32_t a)\n{\n    return __IQNsqrt_MathACL(a, 1);\n}\n#endif\n\n/* INVERSE SQRT */\n/**\n * @brief Calculate inverse square root of an IQ30 input.\n *\n * @param a                 IQ30 type input.\n *\n * @return                  IQ30 type result of the inverse square root operation.\n */\nint32_t _IQ30isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 30, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ29 input.\n *\n * @param a                 IQ29 type input.\n *\n * @return                  IQ29 type result of the inverse square root operation.\n */\nint32_t _IQ29isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 29, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ28 input.\n *\n * @param a                 IQ28 type input.\n *\n * @return                  IQ28 type result of the inverse square root operation.\n */\nint32_t _IQ28isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 28, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ27 input.\n *\n * @param a                 IQ27 type input.\n *\n * @return                  IQ27 type result of the inverse square root operation.\n */\nint32_t _IQ27isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 27, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ26 input.\n *\n * @param a                 IQ26 type input.\n *\n * @return                  IQ26 type result of the inverse square root operation.\n */\nint32_t _IQ26isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 26, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ25 input.\n *\n * @param a                 IQ25 type input.\n *\n * @return                  IQ25 type result of the inverse square root operation.\n */\nint32_t _IQ25isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 25, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ24 input.\n *\n * @param a                 IQ24 type input.\n *\n * @return                  IQ24 type result of the inverse square root operation.\n */\nint32_t _IQ24isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 24, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ23 input.\n *\n * @param a                 IQ23 type input.\n *\n * @return                  IQ23 type result of the inverse square root operation.\n */\nint32_t _IQ23isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 23, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ22 input.\n *\n * @param a                 IQ22 type input.\n *\n * @return                  IQ22 type result of the inverse square root operation.\n */\nint32_t _IQ22isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 22, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ21 input.\n *\n * @param a                 IQ21 type input.\n *\n * @return                  IQ21 type result of the inverse square root operation.\n */\nint32_t _IQ21isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 21, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ20 input.\n *\n * @param a                 IQ20 type input.\n *\n * @return                  IQ20 type result of the inverse square root operation.\n */\nint32_t _IQ20isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 20, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ19 input.\n *\n * @param a                 IQ19 type input.\n *\n * @return                  IQ19 type result of the inverse square root operation.\n */\nint32_t _IQ19isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 19, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ18 input.\n *\n * @param a                 IQ18 type input.\n *\n * @return                  IQ18 type result of the inverse square root operation.\n */\nint32_t _IQ18isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 18, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ17 input.\n *\n * @param a                 IQ17 type input.\n *\n * @return                  IQ17 type result of the inverse square root operation.\n */\nint32_t _IQ17isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 17, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ16 input.\n *\n * @param a                 IQ16 type input.\n *\n * @return                  IQ16 type result of the inverse square root operation.\n */\nint32_t _IQ16isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 16, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ15 input.\n *\n * @param a                 IQ15 type input.\n *\n * @return                  IQ15 type result of the inverse square root operation.\n */\nint32_t _IQ15isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 15, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ14 input.\n *\n * @param a                 IQ14 type input.\n *\n * @return                  IQ14 type result of the inverse square root operation.\n */\nint32_t _IQ14isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 14, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ13 input.\n *\n * @param a                 IQ13 type input.\n *\n * @return                  IQ13 type result of the inverse square root operation.\n */\nint32_t _IQ13isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 13, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ12 input.\n *\n * @param a                 IQ12 type input.\n *\n * @return                  IQ12 type result of the inverse square root operation.\n */\nint32_t _IQ12isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 12, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ11 input.\n *\n * @param a                 IQ11 type input.\n *\n * @return                  IQ11 type result of the inverse square root operation.\n */\nint32_t _IQ11isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 11, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ10 input.\n *\n * @param a                 IQ10 type input.\n *\n * @return                  IQ10 type result of the inverse square root operation.\n */\nint32_t _IQ10isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 10, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ9 input.\n *\n * @param a                 IQ9 type input.\n *\n * @return                  IQ9 type result of the inverse square root operation.\n */\nint32_t _IQ9isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 9, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ8 input.\n *\n * @param a                 IQ8 type input.\n *\n * @return                  IQ8 type result of the inverse square root operation.\n */\nint32_t _IQ8isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 8, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ7 input.\n *\n * @param a                 IQ7 type input.\n *\n * @return                  IQ7 type result of the inverse square root operation.\n */\nint32_t _IQ7isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 7, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ6 input.\n *\n * @param a                 IQ6 type input.\n *\n * @return                  IQ6 type result of the inverse square root operation.\n */\nint32_t _IQ6isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 6, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ5 input.\n *\n * @param a                 IQ5 type input.\n *\n * @return                  IQ5 type result of the inverse square root operation.\n */\nint32_t _IQ5isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 5, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ4 input.\n *\n * @param a                 IQ4 type input.\n *\n * @return                  IQ4 type result of the inverse square root operation.\n */\nint32_t _IQ4isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 4, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ3 input.\n *\n * @param a                 IQ3 type input.\n *\n * @return                  IQ3 type result of the inverse square root operation.\n */\nint32_t _IQ3isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 3, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ2 input.\n *\n * @param a                 IQ2 type input.\n *\n * @return                  IQ2 type result of the inverse square root operation.\n */\nint32_t _IQ2isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 2, TYPE_ISQRT);\n}\n/**\n * @brief Calculate inverse square root of an IQ1 input.\n *\n * @param a                 IQ1 type input.\n *\n * @return                  IQ1 type result of the inverse square root operation.\n */\nint32_t _IQ1isqrt(int32_t a)\n{\n    return __IQNsqrt(a, 0, 1, TYPE_ISQRT);\n}\n\n/* MAGNITUDE */\n/**\n * @brief Calculate the magnitude of two  IQ31 inputs.\n *\n * @param a                 IQ31 type input.\n * @param b                 IQ31 type input.\n *\n * @return                  IQ31 type result of the magnitude operation.\n */\nint32_t _IQmag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 31, TYPE_MAG);\n}\n\n/* INVERSE MAGNITUDE */\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ30 type input.\n * @param b                 IQ30 type input.\n *\n * @return                  IQ30 type result of the inverse magnitude operation.\n */\nint32_t _IQ30imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 30, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ29 type input.\n * @param b                 IQ29 type input.\n *\n * @return                  IQ29 type result of the inverse magnitude operation.\n */\nint32_t _IQ29imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 29, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ28 type input.\n * @param b                 IQ28 type input.\n *\n * @return                  IQ28 type result of the inverse magnitude operation.\n */\nint32_t _IQ28imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 28, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ27 type input.\n * @param b                 IQ27 type input.\n *\n * @return                  IQ27 type result of the inverse magnitude operation.\n */\nint32_t _IQ27imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 27, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ26 type input.\n * @param b                 IQ26 type input.\n *\n * @return                  IQ26 type result of the inverse magnitude operation.\n */\nint32_t _IQ26imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 26, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ25 type input.\n * @param b                 IQ25 type input.\n *\n * @return                  IQ25 type result of the inverse magnitude operation.\n */\nint32_t _IQ25imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 25, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ24 type input.\n * @param b                 IQ24 type input.\n *\n * @return                  IQ24 type result of the inverse magnitude operation.\n */\nint32_t _IQ24imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 24, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ23 type input.\n * @param b                 IQ23 type input.\n *\n * @return                  IQ23 type result of the inverse magnitude operation.\n */\nint32_t _IQ23imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 23, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ22 type input.\n * @param b                 IQ22 type input.\n *\n * @return                  IQ22 type result of the inverse magnitude operation.\n */\nint32_t _IQ22imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 22, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ21 type input.\n * @param b                 IQ21 type input.\n *\n * @return                  IQ21 type result of the inverse magnitude operation.\n */\nint32_t _IQ21imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 21, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ20 type input.\n * @param b                 IQ20 type input.\n *\n * @return                  IQ20 type result of the inverse magnitude operation.\n */\nint32_t _IQ20imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 20, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ19 type input.\n * @param b                 IQ19 type input.\n *\n * @return                  IQ19 type result of the inverse magnitude operation.\n */\nint32_t _IQ19imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 19, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ18 type input.\n * @param b                 IQ18 type input.\n *\n * @return                  IQ18 type result of the inverse magnitude operation.\n */\nint32_t _IQ18imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 18, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ17 type input.\n * @param b                 IQ17 type input.\n *\n * @return                  IQ17 type result of the inverse magnitude operation.\n */\nint32_t _IQ17imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 17, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ16 type input.\n * @param b                 IQ16 type input.\n *\n * @return                  IQ16 type result of the inverse magnitude operation.\n */\nint32_t _IQ16imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 16, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ15 type input.\n * @param b                 IQ15 type input.\n *\n * @return                  IQ15 type result of the inverse magnitude operation.\n */\nint32_t _IQ15imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 15, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ14 type input.\n * @param b                 IQ14 type input.\n *\n * @return                  IQ14 type result of the inverse magnitude operation.\n */\nint32_t _IQ14imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 14, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ13 type input.\n * @param b                 IQ13 type input.\n *\n * @return                  IQ13 type result of the inverse magnitude operation.\n */\nint32_t _IQ13imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 13, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ12 type input.\n * @param b                 IQ12 type input.\n *\n * @return                  IQ12 type result of the inverse magnitude operation.\n */\nint32_t _IQ12imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 12, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ11 type input.\n * @param b                 IQ11 type input.\n *\n * @return                  IQ11 type result of the inverse magnitude operation.\n */\nint32_t _IQ11imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 11, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ10 type input.\n * @param b                 IQ10 type input.\n *\n * @return                  IQ10 type result of the inverse magnitude operation.\n */\nint32_t _IQ10imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 10, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ9 type input.\n * @param b                 IQ9 type input.\n *\n * @return                  IQ9 type result of the inverse magnitude operation.\n */\nint32_t _IQ9imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 9, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ8 type input.\n * @param b                 IQ8 type input.\n *\n * @return                  IQ8 type result of the inverse magnitude operation.\n */\nint32_t _IQ8imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 8, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ7 type input.\n * @param b                 IQ7 type input.\n *\n * @return                  IQ7 type result of the inverse magnitude operation.\n */\nint32_t _IQ7imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 7, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ6 type input.\n * @param b                 IQ6 type input.\n *\n * @return                  IQ6 type result of the inverse magnitude operation.\n */\nint32_t _IQ6imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 6, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ5 type input.\n * @param b                 IQ5 type input.\n *\n * @return                  IQ5 type result of the inverse magnitude operation.\n */\nint32_t _IQ5imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 5, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ4 type input.\n * @param b                 IQ4 type input.\n *\n * @return                  IQ4 type result of the inverse magnitude operation.\n */\nint32_t _IQ4imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 4, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ3 type input.\n * @param b                 IQ3 type input.\n *\n * @return                  IQ3 type result of the inverse magnitude operation.\n */\nint32_t _IQ3imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 3, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ2 type input.\n * @param b                 IQ2 type input.\n *\n * @return                  IQ2 type result of the inverse magnitude operation.\n */\nint32_t _IQ2imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 2, TYPE_IMAG);\n}\n/**\n * @brief Calculate inverse magnitude of two inputs.\n *\n * @param a                 IQ1 type input.\n * @param b                 IQ1 type input.\n *\n * @return                  IQ1 type result of the inverse magnitude operation.\n */\nint32_t _IQ1imag(int32_t a, int32_t b)\n{\n    return __IQNsqrt(a, b, 1, TYPE_IMAG);\n}\n"
  },
  {
    "path": "iqmath/_IQNfunctions/_IQNtables.c",
    "content": "#include <stdint.h>\n\n#include \"_IQNtables.h\"\n\n/*\n *  Coefficients, parameters and lookup tables used for CPU approximations\n */\n\n/* cos */\nconst int_fast32_t _IQ31CosLookup[52] = {\n    2147483647, 2147221509, 2146435157, 2145124784,\n    2143290709, 2140933381, 2138053374, 2134651392,\n    2130728266, 2126284953, 2121322538, 2115842232,\n    2109845374, 2103333428, 2096307983, 2088770754,\n    2080723582, 2072168431, 2063107390, 2053542671,\n    2043476608, 2032911661, 2021850407, 2010295547,\n    1998249902, 1985716414, 1972698141, 1959198262,\n    1945220073, 1930766987, 1915842531, 1900450350,\n    1884594201, 1868277956, 1851505597, 1834281220,\n    1816609030, 1798493340, 1779938574, 1760949261,\n    1741530038, 1721685646, 1701420928, 1680740833,\n    1659650409, 1638154806, 1616259270, 1593969148,\n    1571289881, 1548227007, 1524786154, 1500973048\n};\n\n/* sin */\nconst int_fast32_t _IQ31SinLookup[52] = {\n    0,   33553067,   67097942,  100626436,\n    134130364,  167601545,  201031810,  234412995,\n    267736951,  300995544,  334180652,  367284176,\n    400298032,  433214161,  466024527,  498721120,\n    531295957,  563741086,  596048586,  628210568,\n    660219183,  692066614,  723745087,  755246868,\n    786564267,  817689637,  848615380,  879333946,\n    909837834,  940119599,  970171848,  999987242,\n    1029558505, 1058878415, 1087939815, 1116735610,\n    1145258771, 1173502333, 1201459401, 1229123150,\n    1256486826, 1283543749, 1310287313, 1336710990,\n    1362808327, 1388572955, 1413998582, 1439079002,\n    1463808091, 1488179813, 1512188216, 1535827441\n};\n\n/* Asin */\nconst int_fast32_t _IQ29Asin_coeffs[17][5] = {\n    {  3149732,   89392309,       962, 536870908,       0},\n    {  9526495,   88593699,     40416, 536870004,       8},\n    { 16138900,   86937495,    197996, 536863257,     118},\n    { 23156787,   84300941,    571586, 536839597,     683},\n    { 30770290,   80487362,   1290238, 536779215,    2591},\n    { 39200158,   75209531,   2531955, 536649108,    7714},\n    { 48710843,   68064494,   4547783, 536395980,   19650},\n    { 59627725,   58496679,   7695660, 535935197,   44970},\n    { 72359850,   45744506,  12489135, 535133733,   95261},\n    { 87431720,   28762778,  19668817, 533783769,  190507},\n    {105527689,    6109335,  30308851, 531561517,  364646},\n    {127555573,  -24222672,  45978054, 527962405,  674787},\n    {154739551,  -65056242,  68987651, 522197749, 1216568},\n    {188758701, -120414117, 102778528, 513027743, 2150044},\n    {231956922, -196114786, 152538402, 498486871, 3743891},\n    {287669673, -300718733, 226205346, 475423960, 6452123},\n    {287669673, -300718733, 226205346, 475423960, 6452123}    // repeat last set\n};\n\n/* atan */\nconst int_fast32_t _IQ32atan_coeffs[132] = {\n    -227484580, -9261, 683565333, 0,\n        -224831707, -276221, 683574534, -108,\n        -219602897, -1274081, 683638558, -1488,\n        -211947885, -3443234, 683844263, -8015,\n        -202081292, -7157693, 684311451, -27646,\n        -190271590, -12705955, 685181594, -73201,\n        -176827842, -20278271, 686604775, -162452,\n        -162085247, -29960921, 688726164, -317494,\n        -146390502, -41737384, 691673332, -563488,\n        -130087951, -55495711, 695545487, -926914,\n        -113507288, -71040919, 700405423, -1433559,\n        -96953369, -88110970, 706274644, -2106439,\n        -80698479, -106394779, 713131732, -2963878,\n        -64977126, -125550747, 720913749, -4017911,\n        -49983270, -145224548, 729520198, -5273132,\n        -35869738, -165065147, 738818936, -6726059,\n        -22749467, -184738347, 748653357, -8365003,\n        -10698168, -203937495, 758850169, -10170435,\n        241989, -222391214, 769227187, -12115749,\n        10058068, -239868310, 779600651, -14168336,\n        18761768, -256180110, 789791697, -16290870,\n        26384816, -271180628, 799631786, -18442695,\n        32974556, -284764983, 808966944, -20581230,\n        38589896, -296866517, 817660829, -22663305,\n        43297701, -307453021, 825596674, -24646386,\n        47169678, -316522417, 832678225, -26489630,\n        50279770, -324098234, 838829825, -28154764,\n        52702039, -330225080, 843995800, -29606769,\n        54508999, -334964326, 848139312, -30814380,\n        55770360, -338390095, 851240831, -31750408,\n        56552116, -340585675, 853296356, -32391901,\n        56915945, -341640355, 854315504, -32720182,\n        56915945, -341640355, 854315504, -32720182,\n    };\n\n/* exp */\nconst uint_fast32_t _IQ30exp_coeffs[11] = {\n    0x00000127, 0x00000B93, 0x00006806, 0x00034034,\n    0x0016C16C, 0x00888888, 0x02AAAAAA, 0x0AAAAAAA,\n    0x20000000, 0x40000000, 0x40000000\n};\n\nconst uint_fast32_t _IQNexp_min[30] = {\n    0xffffffff, 0xfffffffb, 0xfffffff0, 0xffffffd4, 0xffffff92, 0xfffffef6,\n    0xfffffd93, 0xfffffa75, 0xfffff386, 0xffffe447, 0xffffc301, 0xffff7aeb,\n    0xfffedfa7, 0xfffd92f1, 0xfffacd29, 0xfff4e8df, 0xffe86ed9, 0xffce17ea,\n    0xff96a442, 0xff223163, 0xfe2e3482, 0xfc300c7d, 0xf8075fed, 0xef5d4dc1,\n    0xdd57b752, 0xb7e9a644, 0x80000000, 0x80000000, 0x80000000, 0x80000000\n};\n\nconst uint_fast32_t _IQNexp_max[30] = {\n    0x00000029, 0x00000050, 0x0000009b, 0x0000012b, 0x00000240, 0x00000455,\n    0x00000851, 0x00000ff1, 0x00001e7f, 0x00003a39, 0x00006ee7, 0x0000d2b7,\n    0x00018f40, 0x0002f224, 0x00058b90, 0x000a65af, 0x0013687a, 0x00240b2c,\n    0x00428ac8, 0x0079fe70, 0x00ddce9d, 0x018f40b5, 0x02c5c85f, 0x04da1ea7,\n    0x0851591f, 0x0ddce9df, 0x162e42fe, 0x2145647e, 0x2c5c85fd, 0x2c5c85fd\n};\n\nconst uint_fast16_t _IQNexp_offset[30] = {\n    0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8,\n    9, 9, 10, 11, 11, 12, 13, 13, 14,\n    15, 15, 16, 17, 18, 18, 19, 20, 20\n};\n\nconst uint_fast32_t _IQNexp_lookup1[22] = {\n    0x00000004, 0x0000000A, 0x0000001D, 0x00000050, 0x000000DA, 0x00000251,\n    0x0000064D, 0x00001122, 0x00002E93, 0x00007E9C, 0x00015829, 0x0003A788,\n    0x0009EF0B, 0x001B00B5, 0x004966B1, 0x00C78665, 0x021E5D7A, 0x05C24D23,\n    0x0FA79104, 0x2A8DB1F3, 0x73AC222D, 0x00000000\n};\nconst uint_fast32_t _IQNexp_lookup2[22] = {\n    0x00000002, 0x00000008, 0x00000015, 0x0000003B, 0x000000A0, 0x000001B4,\n    0x000004A3, 0x00000C9B, 0x00002245, 0x00005D27, 0x0000FD38, 0x0002B053,\n    0x00074F11, 0x0013DE16, 0x0036016B, 0x0092CD62, 0x018F0CCA, 0x043CBAF4,\n    0x0B849A46, 0x1F4F2209, 0x551B63E7, 0xE758445B\n};\nconst uint_fast32_t _IQNexp_lookup3[22] = {\n    0x00000002, 0x00000005, 0x00000010, 0x0000002B, 0x00000076, 0x00000141,\n    0x00000369, 0x00000946, 0x00001936, 0x0000448A, 0x0000BA4F, 0x0001FA71,\n    0x000560A7, 0x000E9E22, 0x0027BC2C, 0x006C02D6, 0x01259AC4, 0x031E1995,\n    0x087975E8, 0x1709348C, 0x3E9E4412, 0xAA36C7CF\n};\nconst uint_fast32_t _IQNexp_lookup4[22] = {\n    0x00000004, 0x0000000B, 0x00000020, 0x00000056, 0x000000EC, 0x00000282,\n    0x000006D3, 0x0000128D, 0x0000326D, 0x00008914, 0x0001749E, 0x0003F4E2,\n    0x000AC14E, 0x001D3C44, 0x004F7859, 0x00D805AC, 0x024B3589, 0x063C332B,\n    0x10F2EBD0, 0x2E126918, 0x7D3C8824, 0x00000000\n};\nconst uint_fast32_t _IQNexp_lookup5[22] = {\n    0x00000003, 0x00000008, 0x00000017, 0x00000040, 0x000000AD, 0x000001D8,\n    0x00000505, 0x00000DA6, 0x0000251A, 0x000064DB, 0x00011228, 0x0002E93D,\n    0x0007E9C5, 0x0015829D, 0x003A7889, 0x009EF0B2, 0x01B00B59, 0x04966B12,\n    0x0C786657, 0x21E5D7A1, 0x5C24D230, 0xFA791048\n};\nconst uint_fast32_t _IQNexp_lookup6[22] = {\n    0x00000002, 0x00000006, 0x00000011, 0x0000002F, 0x00000080, 0x0000015B,\n    0x000003B1, 0x00000A0A, 0x00001B4C, 0x00004A34, 0x0000C9B6, 0x00022451,\n    0x0005D27A, 0x000FD38A, 0x002B053B, 0x0074F112, 0x013DE165, 0x036016B2,\n    0x092CD624, 0x18F0CCAF, 0x43CBAF42, 0xB849A460\n};\nconst uint_fast32_t _IQNexp_lookup7[22] = {\n    0x00000004, 0x0000000C, 0x00000022, 0x0000005E, 0x00000100, 0x000002B7,\n    0x00000763, 0x00001415, 0x00003699, 0x00009469, 0x0001936D, 0x000448A2,\n    0x000BA4F5, 0x001FA715, 0x00560A77, 0x00E9E224, 0x027BC2CA, 0x06C02D64,\n    0x1259AC48, 0x31E1995F, 0x87975E85, 0x00000000\n};\nconst uint_fast32_t _IQNexp_lookup8[22] = {\n    0x00000003, 0x00000009, 0x00000019, 0x00000045, 0x000000BC, 0x00000200,\n    0x0000056F, 0x00000EC7, 0x0000282B, 0x00006D32, 0x000128D3, 0x000326DB,\n    0x00089144, 0x001749EA, 0x003F4E2A, 0x00AC14EE, 0x01D3C448, 0x04F78595,\n    0x0D805AC8, 0x24B35891, 0x63C332BE, 0x00000000\n};\nconst uint_fast32_t _IQNexp_lookup9[22] = {\n    0x00000002, 0x00000006, 0x00000012, 0x00000032, 0x0000008A, 0x00000178,\n    0x00000400, 0x00000ADF, 0x00001D8E, 0x00005057, 0x0000DA64, 0x000251A7,\n    0x00064DB7, 0x00112288, 0x002E93D4, 0x007E9C55, 0x015829DC, 0x03A78891,\n    0x09EF0B2A, 0x1B00B591, 0x4966B122, 0xC786657D\n};\nconst uint_fast32_t _IQNexp_lookup10[22] = {\n    0x00000005, 0x0000000D, 0x00000025, 0x00000065, 0x00000115, 0x000002F1,\n    0x00000800, 0x000015BF, 0x00003B1C, 0x0000A0AF, 0x0001B4C9, 0x0004A34E,\n    0x000C9B6E, 0x00224510, 0x005D27A9, 0x00FD38AB, 0x02B053B9, 0x074F1122,\n    0x13DE1654, 0x36016B22, 0x92CD6245, 0x00000000\n};\nconst uint_fast32_t _IQNexp_lookup11[22] = {\n    0x00000003, 0x0000000A, 0x0000001B, 0x0000004B, 0x000000CB, 0x0000022A,\n    0x000005E2, 0x00001000, 0x00002B7E, 0x00007639, 0x0001415E, 0x00036992,\n    0x0009469C, 0x001936DC, 0x00448A21, 0x00BA4F53, 0x01FA7157, 0x0560A773,\n    0x0E9E2244, 0x27BC2CA9, 0x6C02D645, 0x00000000\n};\nconst uint_fast32_t _IQNexp_lookup12[22] = {\n    0x00000002, 0x00000007, 0x00000014, 0x00000037, 0x00000096, 0x00000197,\n    0x00000454, 0x00000BC5, 0x00002000, 0x000056FC, 0x0000EC73, 0x000282BC,\n    0x0006D324, 0x00128D38, 0x00326DB8, 0x00891442, 0x01749EA7, 0x03F4E2AF,\n    0x0AC14EE7, 0x1D3C4488, 0x4F785953, 0xD805AC8B\n};\nconst uint_fast32_t _IQNexp_lookup13[22] = {\n    0x00000002, 0x00000005, 0x0000000E, 0x00000028, 0x0000006E, 0x0000012C,\n    0x0000032F, 0x000008A9, 0x0000178B, 0x00004000, 0x0000ADF8, 0x0001D8E6,\n    0x00050579, 0x000DA648, 0x00251A71, 0x0064DB71, 0x01122885, 0x02E93D4F,\n    0x07E9C55F, 0x15829DCF, 0x3A788911, 0x9EF0B2A6\n};\nconst uint_fast32_t _IQNexp_lookup14[22] = {\n    0x00000004, 0x0000000A, 0x0000001D, 0x00000051, 0x000000DC, 0x00000258,\n    0x0000065F, 0x00001152, 0x00002F16, 0x00008000, 0x00015BF0, 0x0003B1CC,\n    0x000A0AF2, 0x001B4C90, 0x004A34E2, 0x00C9B6E2, 0x0224510B, 0x05D27A9F,\n    0x0FD38ABE, 0x2B053B9F, 0x74F11223, 0x00000000\n};\nconst uint_fast32_t _IQNexp_lookup15[22] = {\n    0x00000002, 0x00000008, 0x00000015, 0x0000003B, 0x000000A2, 0x000001B9,\n    0x000004B0, 0x00000CBE, 0x000022A5, 0x00005E2D, 0x00010000, 0x0002B7E1,\n    0x00076399, 0x001415E5, 0x00369920, 0x009469C4, 0x01936DC5, 0x0448A216,\n    0x0BA4F53E, 0x1FA7157C, 0x560A773E, 0xE9E22447\n};\nconst uint_fast32_t _IQNexp_lookup16[22] = {\n    0x00000002, 0x00000005, 0x00000010, 0x0000002B, 0x00000077, 0x00000144,\n    0x00000373, 0x00000960, 0x0000197D, 0x0000454A, 0x0000BC5A, 0x00020000,\n    0x00056FC2, 0x000EC732, 0x00282BCB, 0x006D3240, 0x0128D389, 0x0326DB8A,\n    0x0891442D, 0x1749EA7D, 0x3F4E2AF8, 0xAC14EE7C\n};\nconst uint_fast32_t _IQNexp_lookup17[22] = {\n    0x00000004, 0x0000000B, 0x00000020, 0x00000057, 0x000000EF, 0x00000289,\n    0x000006E6, 0x000012C1, 0x000032FB, 0x00008A95, 0x000178B5, 0x00040000,\n    0x000ADF85, 0x001D8E64, 0x00505796, 0x00DA6481, 0x0251A713, 0x064DB715,\n    0x1122885A, 0x2E93D4FA, 0x7E9C55F1, 0x00000000\n};\nconst uint_fast32_t _IQNexp_lookup18[22] = {\n    0x00000003, 0x00000008, 0x00000017, 0x00000040, 0x000000AF, 0x000001DE,\n    0x00000513, 0x00000DCC, 0x00002582, 0x000065F6, 0x0001152A, 0x0002F16A,\n    0x00080000, 0x0015BF0A, 0x003B1CC9, 0x00A0AF2D, 0x01B4C902, 0x04A34E26,\n    0x0C9B6E2B, 0x224510B5, 0x5D27A9F5, 0xFD38ABE2\n};\nconst uint_fast32_t _IQNexp_lookup19[22] = {\n    0x00000002, 0x00000006, 0x00000011, 0x0000002F, 0x00000081, 0x0000015F,\n    0x000003BC, 0x00000A27, 0x00001B99, 0x00004B05, 0x0000CBED, 0x00022A55,\n    0x0005E2D5, 0x00100000, 0x002B7E15, 0x00763992, 0x01415E5B, 0x03699205,\n    0x09469C4C, 0x1936DC56, 0x448A216A, 0xBA4F53EA\n};\nconst uint_fast32_t _IQNexp_lookup20[22] = {\n    0x00000004, 0x0000000C, 0x00000023, 0x0000005F, 0x00000102, 0x000002BF,\n    0x00000778, 0x0000144E, 0x00003732, 0x0000960A, 0x000197DB, 0x000454AA,\n    0x000BC5AB, 0x00200000, 0x0056FC2A, 0x00EC7325, 0x0282BCB7, 0x06D3240B,\n    0x128D3899, 0x326DB8AD, 0x891442D5, 0x00000000\n};\nconst uint_fast32_t _IQNexp_lookup21[22] = {\n    0x00000003, 0x00000009, 0x00000019, 0x00000046, 0x000000BE, 0x00000205,\n    0x0000057F, 0x00000EF0, 0x0000289C, 0x00006E64, 0x00012C15, 0x00032FB6,\n    0x0008A955, 0x00178B56, 0x00400000, 0x00ADF854, 0x01D8E64B, 0x0505796F,\n    0x0DA64817, 0x251A7132, 0x64DB715A, 0x00000000\n};\nconst uint_fast32_t _IQNexp_lookup22[22] = {\n    0x00000002, 0x00000006, 0x00000012, 0x00000033, 0x0000008C, 0x0000017C,\n    0x0000040B, 0x00000AFE, 0x00001DE1, 0x00005139, 0x0000DCC9, 0x0002582A,\n    0x00065F6C, 0x001152AA, 0x002F16AC, 0x00800000, 0x015BF0A8, 0x03B1CC97,\n    0x0A0AF2DF, 0x1B4C902E, 0x4A34E265, 0xC9B6E2B4\n};\nconst uint_fast32_t _IQNexp_lookup23[22] = {\n    0x00000005, 0x0000000D, 0x00000025, 0x00000067, 0x00000118, 0x000002F9,\n    0x00000816, 0x000015FC, 0x00003BC2, 0x0000A272, 0x0001B993, 0x0004B055,\n    0x000CBED8, 0x0022A555, 0x005E2D58, 0x01000000, 0x02B7E151, 0x0763992E,\n    0x1415E5BF, 0x3699205C, 0x9469C4CB, 0x00000000\n};\nconst uint_fast32_t _IQNexp_lookup24[22] = {\n    0x00000003, 0x0000000A, 0x0000001B, 0x0000004B, 0x000000CE, 0x00000230,\n    0x000005F3, 0x0000102C, 0x00002BF8, 0x00007785, 0x000144E5, 0x00037327,\n    0x000960AA, 0x00197DB0, 0x00454AAA, 0x00BC5AB1, 0x02000000, 0x056FC2A2,\n    0x0EC7325C, 0x282BCB7E, 0x6D3240B8, 0x00000000\n};\nconst uint_fast32_t _IQNexp_lookup25[22] = {\n    0x00000002, 0x00000007, 0x00000014, 0x00000037, 0x00000097, 0x0000019C,\n    0x00000460, 0x00000BE6, 0x00002059, 0x000057F0, 0x0000EF0B, 0x000289CA,\n    0x0006E64F, 0x0012C155, 0x0032FB61, 0x008A9555, 0x0178B563, 0x04000000,\n    0x0ADF8545, 0x1D8E64B8, 0x505796FD, 0xDA648171\n};\nconst uint_fast32_t _IQNexp_lookup26[22] = {\n    0x00000002, 0x00000005, 0x0000000F, 0x00000029, 0x0000006F, 0x0000012F,\n    0x00000338, 0x000008C1, 0x000017CD, 0x000040B3, 0x0000AFE1, 0x0001DE16,\n    0x00051394, 0x000DCC9F, 0x002582AB, 0x0065F6C3, 0x01152AAA, 0x02F16AC6,\n    0x08000000, 0x15BF0A8B, 0x3B1CC971, 0xA0AF2DFB\n};\nconst uint_fast32_t _IQNexp_lookup27[22] = {\n    0x00000004, 0x0000000B, 0x0000001E, 0x00000052, 0x000000DF, 0x0000025E,\n    0x00000671, 0x00001183, 0x00002F9A, 0x00008167, 0x00015FC2, 0x0003BC2D,\n    0x000A2728, 0x001B993F, 0x004B0556, 0x00CBED86, 0x022A5554, 0x05E2D58D,\n    0x10000000, 0x2B7E1516, 0x763992E3, 0x00000000\n};\nconst uint_fast32_t _IQNexp_lookup28[22] = {\n    0x00000003, 0x00000008, 0x00000016, 0x0000003C, 0x000000A4, 0x000001BE,\n    0x000004BD, 0x00000CE2, 0x00002306, 0x00005F35, 0x000102CF, 0x0002BF84,\n    0x0007785A, 0x00144E51, 0x0037327F, 0x00960AAD, 0x0197DB0C, 0x0454AAA8,\n    0x0BC5AB1B, 0x20000000, 0x56FC2A2C, 0xEC7325C6\n};\nconst uint_fast32_t _IQNexp_lookup29[22] = {\n    0x00000002, 0x00000006, 0x00000010, 0x0000002C, 0x00000078, 0x00000148,\n    0x0000037C, 0x0000097B, 0x000019C5, 0x0000460D, 0x0000BE6B, 0x0002059E,\n    0x00057F08, 0x000EF0B5, 0x00289CA3, 0x006E64FF, 0x012C155B, 0x032FB619,\n    0x08A95551, 0x178B5636, 0x40000000, 0xADF85458\n};\nconst uint_fast32_t _IQNexp_lookup30[22] = {\n    0x00000004, 0x0000000C, 0x00000020, 0x00000058, 0x000000F1, 0x00000290,\n    0x000006F9, 0x000012F6, 0x0000338A, 0x00008C1A, 0x00017CD7, 0x00040B3C,\n    0x000AFE10, 0x001DE16B, 0x00513947, 0x00DCC9FF, 0x02582AB7, 0x065F6C33,\n    0x1152AAA3, 0x2F16AC6C, 0x80000000, 0x00000000\n};\n\n/* log */\nconst uint_fast32_t _IQNlog_min[5] = {\n    0x00000010, 0x00015FC3, 0x00960AAE, 0x08A95552, 0x2F16AC6D\n};\n\nconst uint_fast32_t _IQ30log_coeffs[15] = {\n    0xfb6db6db, 0x04ec4ec4, 0xfaaaaaab, 0x05d1745d, 0xf999999a,\n    0x071c71c7, 0xf8000000, 0x09249249, 0xf5555556, 0x0ccccccc,\n    0xf0000000, 0x15555555, 0xe0000000, 0x40000000, 0x00000000\n};\n\n/* div */\nconst uint8_t _IQ6div_lookup[65] = {\n    0x7F, 0x7D, 0x7B, 0x79, 0x78, 0x76, 0x74, 0x73,\n    0x71, 0x6F, 0x6E, 0x6D, 0x6B, 0x6A, 0x68, 0x67,\n    0x66, 0x65, 0x63, 0x62, 0x61, 0x60, 0x5F, 0x5E,\n    0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, 0x57, 0x56,\n    0x55, 0x54, 0x53, 0x52, 0x52, 0x51, 0x50, 0x4F,\n    0x4E, 0x4E, 0x4D, 0x4C, 0x4C, 0x4B, 0x4A, 0x49,\n    0x49, 0x48, 0x48, 0x47, 0x46, 0x46, 0x45, 0x45,\n    0x44, 0x43, 0x43, 0x42, 0x42, 0x41, 0x41, 0x40, 0x40\n};\n\n\n/* sqrt */\nconst uint_fast16_t _IQ14sqrt_lookup[96] = {\n    0x7f02, 0x7d19, 0x7b46, 0x7986, 0x77d9, 0x763d, 0x74b2, 0x7335,\n    0x71c7, 0x7066, 0x6f11, 0x6dc8, 0x6c8b, 0x6b58, 0x6a2f, 0x690f,\n    0x67f8, 0x66ea, 0x65e4, 0x64e5, 0x63ee, 0x62fe, 0x6214, 0x6131,\n    0x6054, 0x5f7d, 0x5eab, 0x5dde, 0x5d17, 0x5c54, 0x5b96, 0x5add,\n    0x5a28, 0x5977, 0x58ca, 0x5821, 0x577c, 0x56da, 0x563c, 0x55a1,\n    0x5509, 0x5475, 0x53e3, 0x5354, 0x52c9, 0x523f, 0x51b9, 0x5135,\n    0x50b3, 0x5034, 0x4fb7, 0x4f3d, 0x4ec4, 0x4e4e, 0x4dda, 0x4d68,\n    0x4cf7, 0x4c89, 0x4c1d, 0x4bb2, 0x4b49, 0x4ae1, 0x4a7c, 0x4a18,\n    0x49b5, 0x4954, 0x48f4, 0x4896, 0x483a, 0x47de, 0x4784, 0x472c,\n    0x46d4, 0x467e, 0x4629, 0x45d6, 0x4583, 0x4532, 0x44e1, 0x4492,\n    0x4444, 0x43f7, 0x43aa, 0x435f, 0x4315, 0x42cc, 0x4284, 0x423c,\n    0x41f6, 0x41b0, 0x416b, 0x4127, 0x40e4, 0x40a2, 0x4060, 0x4020\n};\n\n/* shift with mpy */\n//const uint_fast32_t _IQNshift32[32] = {\n//    0xffffffff, 0x80000000, 0x40000000, 0x20000000,\n//    0x10000000, 0x08000000, 0x04000000, 0x02000000,\n//    0x01000000, 0x00800000, 0x00400000, 0x00200000,\n//    0x00100000, 0x00080000, 0x00040000, 0x00020000,\n//    0x00010000, 0x00008000, 0x00004000, 0x00002000,\n//    0x00001000, 0x00000800, 0x00000400, 0x00000200,\n//    0x00000100, 0x00000080, 0x00000040, 0x00000020,\n//    0x00000010, 0x00000008, 0x00000004, 0x00000002\n//};\n"
  },
  {
    "path": "iqmath/_IQNfunctions/_IQNtables.h",
    "content": "#ifndef _IQNTABLES_H_\n#define _IQNTABLES_H_\n\n#include <stdint.h>\n\n/* LOG lookup and coefficient tables. */\n#define _IQ30log_order  14\nextern const uint_fast32_t _IQNlog_min[5];\nextern const uint_fast32_t _IQ30log_coeffs[15];\n\n/* asin and acos coefficient table. */\nextern const int_fast32_t _IQ29Asin_coeffs[17][5];\n\n/* sin and cos lookup tables. */\nextern const int_fast32_t _IQ31CosLookup[52];\nextern const int_fast32_t _IQ31SinLookup[52];\n\n/* atan coefficient table. */\nextern const int_fast32_t _IQ32atan_coeffs[132];\n\n/* Tables for exp function. Min/Max and integer lookup for each q type */\n#define _IQ30exp_order  10\nextern const uint_fast32_t _IQNexp_min[30];\nextern const uint_fast32_t _IQNexp_max[30];\nextern const uint_fast16_t _IQNexp_offset[30];\nextern const uint_fast32_t _IQNexp_lookup1[22];\nextern const uint_fast32_t _IQNexp_lookup2[22];\nextern const uint_fast32_t _IQNexp_lookup3[22];\nextern const uint_fast32_t _IQNexp_lookup4[22];\nextern const uint_fast32_t _IQNexp_lookup5[22];\nextern const uint_fast32_t _IQNexp_lookup6[22];\nextern const uint_fast32_t _IQNexp_lookup7[22];\nextern const uint_fast32_t _IQNexp_lookup8[22];\nextern const uint_fast32_t _IQNexp_lookup9[22];\nextern const uint_fast32_t _IQNexp_lookup10[22];\nextern const uint_fast32_t _IQNexp_lookup11[22];\nextern const uint_fast32_t _IQNexp_lookup12[22];\nextern const uint_fast32_t _IQNexp_lookup13[22];\nextern const uint_fast32_t _IQNexp_lookup14[22];\nextern const uint_fast32_t _IQNexp_lookup15[22];\nextern const uint_fast32_t _IQNexp_lookup16[22];\nextern const uint_fast32_t _IQNexp_lookup17[22];\nextern const uint_fast32_t _IQNexp_lookup18[22];\nextern const uint_fast32_t _IQNexp_lookup19[22];\nextern const uint_fast32_t _IQNexp_lookup20[22];\nextern const uint_fast32_t _IQNexp_lookup21[22];\nextern const uint_fast32_t _IQNexp_lookup22[22];\nextern const uint_fast32_t _IQNexp_lookup23[22];\nextern const uint_fast32_t _IQNexp_lookup24[22];\nextern const uint_fast32_t _IQNexp_lookup25[22];\nextern const uint_fast32_t _IQNexp_lookup26[22];\nextern const uint_fast32_t _IQNexp_lookup27[22];\nextern const uint_fast32_t _IQNexp_lookup28[22];\nextern const uint_fast32_t _IQNexp_lookup29[22];\nextern const uint_fast32_t _IQNexp_lookup30[22];\nextern const uint_fast32_t _IQ30exp_coeffs[11];\n\n/*\n *  Q0.15 lookup table for 1/2x best guess.\n */\nextern const uint8_t _IQ6div_lookup[65];\n\n/*\n *  Q0.15 lookup table for 1/(2*sqrt(x)) best guess.\n *  96 entries gives us enough accuracy to only need 2 iterations.\n */\nextern const uint_fast16_t _IQ14sqrt_lookup[96];\n\n/*\n * Lookup table for shifting using the multiplier.\n * Right: Index is the shift count, result is high 32 bits.\n * Left: Index is 32 - count, result is low (and high) 32 bits.\n */\nextern const uint_fast32_t _IQNshift32[32];\n\n#endif\n"
  },
  {
    "path": "iqmath/_IQNfunctions/_IQNtoF.c",
    "content": "/*!****************************************************************************\n *  @file       _IQNtoF.c\n *  @brief      Functions to convert IQN type to floating point.\n *\n *  <hr>\n ******************************************************************************/\n\n#include <stdint.h>\n#include <string.h>\n\n#include \"../support/support.h\"\n\n/**\n * @brief Converts IQN type to floating point.\n *\n * @param iqNInput        IQN type value input to be converted.\n * @param q_value         IQ format.\n *\n * @return                Conversion of iqNInput to floating point.\n */\n#if defined(__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNtoF)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline = forced\n#endif\n__STATIC_INLINE float __IQNtoF(int_fast32_t iqNInput, int8_t q_value)\n{\n    uint_fast16_t ui16Exp;\n    uint_fast32_t uiq23Result;\n    uint_fast32_t uiq31Input;\n\n    /* Initialize exponent to the offset iq value. */\n    ui16Exp = 0x3f80 + ((31 - q_value) * ((uint_fast32_t) 1 << (23 - 16)));\n\n    /* Save the sign of the iqN input to the exponent construction. */\n    if (iqNInput < 0) {\n        ui16Exp |= 0x8000;\n        uiq31Input = -iqNInput;\n    } else if (iqNInput == 0) {\n        return (0);\n    } else {\n        uiq31Input = iqNInput;\n    }\n\n    /* Scale the iqN input to uiq31 by keeping track of the exponent. */\n    while ((uint_fast16_t)(uiq31Input >> 16) < 0x8000) {\n        uiq31Input <<= 1;\n        ui16Exp -= 0x0080;\n    }\n\n    /* Round the uiq31 result and and shift to uiq23 */\n    uiq23Result = (uiq31Input + 0x0080) >> 8;\n\n    /* Remove the implied MSB bit of the mantissa. */\n    uiq23Result &= ~0x00800000;\n\n    /*\n     * Add the constructed exponent and sign bit to the mantissa. We must use\n     * an add in the case where rounding would cause the mantissa to overflow.\n     * When this happens the mantissa result is two where the MSB is zero and\n     * the LSB of the exp is set to 1 instead. Adding one to the exponent is the\n     * correct handling for a mantissa of two. It is not required to scale the\n     * mantissa since it will always be equal to zero in this scenario.\n     */\n    uiq23Result += (uint_fast32_t) ui16Exp << 16;\n\n    /* Return the mantissa + exp + sign result as a floating point type. */\n    /* Use memcpy to avoid strict-aliasing violation */\n    float result;\n    memcpy(&result, &uiq23Result, sizeof(float));\n    return result;\n}\n\n/**\n * @brief Converts input to floating point using IQ30 format.\n *\n * @param a             IQ30 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ30toF(int32_t a)\n{\n    return __IQNtoF(a, 30);\n}\n/**\n * @brief Converts input to floating point using IQ29 format.\n *\n * @param a             IQ29 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ29toF(int32_t a)\n{\n    return __IQNtoF(a, 29);\n}\n/**\n * @brief Converts input to floating point using IQ28 format.\n *\n * @param a             IQ28 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ28toF(int32_t a)\n{\n    return __IQNtoF(a, 28);\n}\n/**\n * @brief Converts input to floating point using IQ27 format.\n *\n * @param a             IQ27 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ27toF(int32_t a)\n{\n    return __IQNtoF(a, 27);\n}\n/**\n * @brief Converts input to floating point using IQ26 format.\n *\n * @param a             IQ26 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ26toF(int32_t a)\n{\n    return __IQNtoF(a, 26);\n}\n/**\n * @brief Converts input to floating point using IQ25 format.\n *\n * @param a             IQ25 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ25toF(int32_t a)\n{\n    return __IQNtoF(a, 25);\n}\n/**\n * @brief Converts input to floating point using IQ24 format.\n *\n * @param a             IQ24 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ24toF(int32_t a)\n{\n    return __IQNtoF(a, 24);\n}\n/**\n * @brief Converts input to floating point using IQ23 format.\n *\n * @param a             IQ23 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ23toF(int32_t a)\n{\n    return __IQNtoF(a, 23);\n}\n/**\n * @brief Converts input to floating point using IQ22 format.\n *\n * @param a             IQ22 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ22toF(int32_t a)\n{\n    return __IQNtoF(a, 22);\n}\n/**\n * @brief Converts input to floating point using IQ21 format.\n *\n * @param a             IQ21 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ21toF(int32_t a)\n{\n    return __IQNtoF(a, 21);\n}\n/**\n * @brief Converts input to floating point using IQ20 format.\n *\n * @param a             IQ20 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ20toF(int32_t a)\n{\n    return __IQNtoF(a, 20);\n}\n/**\n * @brief Converts input to floating point using IQ19 format.\n *\n * @param a             IQ19 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ19toF(int32_t a)\n{\n    return __IQNtoF(a, 19);\n}\n/**\n * @brief Converts input to floating point using IQ18 format.\n *\n * @param a             IQ18 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ18toF(int32_t a)\n{\n    return __IQNtoF(a, 18);\n}\n/**\n * @brief Converts input to floating point using IQ17 format.\n *\n * @param a             IQ17 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ17toF(int32_t a)\n{\n    return __IQNtoF(a, 17);\n}\n/**\n * @brief Converts input to floating point using IQ16 format.\n *\n * @param a             IQ16 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ16toF(int32_t a)\n{\n    return __IQNtoF(a, 16);\n}\n/**\n * @brief Converts input to floating point using IQ15 format.\n *\n * @param a             IQ15 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ15toF(int32_t a)\n{\n    return __IQNtoF(a, 15);\n}\n/**\n * @brief Converts input to floating point using IQ14 format.\n *\n * @param a             IQ14 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ14toF(int32_t a)\n{\n    return __IQNtoF(a, 14);\n}\n/**\n * @brief Converts input to floating point using IQ13 format.\n *\n * @param a             IQ13 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ13toF(int32_t a)\n{\n    return __IQNtoF(a, 13);\n}\n/**\n * @brief Converts input to floating point using IQ12 format.\n *\n * @param a             IQ12 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ12toF(int32_t a)\n{\n    return __IQNtoF(a, 12);\n}\n/**\n * @brief Converts input to floating point using IQ11 format.\n *\n * @param a             IQ11 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ11toF(int32_t a)\n{\n    return __IQNtoF(a, 11);\n}\n/**\n * @brief Converts input to floating point using IQ10 format.\n *\n * @param a             IQ10 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ10toF(int32_t a)\n{\n    return __IQNtoF(a, 10);\n}\n/**\n * @brief Converts input to floating point using IQ9 format.\n *\n * @param a             IQ9 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ9toF(int32_t a)\n{\n    return __IQNtoF(a, 9);\n}\n/**\n * @brief Converts input to floating point using IQ8 format.\n *\n * @param a             IQ8 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ8toF(int32_t a)\n{\n    return __IQNtoF(a, 8);\n}\n/**\n * @brief Converts input to floating point using IQ7 format.\n *\n * @param a             IQ7 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ7toF(int32_t a)\n{\n    return __IQNtoF(a, 7);\n}\n/**\n * @brief Converts input to floating point using IQ6 format.\n *\n * @param a             IQ6 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ6toF(int32_t a)\n{\n    return __IQNtoF(a, 6);\n}\n/**\n * @brief Converts input to floating point using IQ5 format.\n *\n * @param a             IQ5 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ5toF(int32_t a)\n{\n    return __IQNtoF(a, 5);\n}\n/**\n * @brief Converts input to floating point using IQ4 format.\n *\n * @param a             IQ4 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ4toF(int32_t a)\n{\n    return __IQNtoF(a, 4);\n}\n/**\n * @brief Converts input to floating point using IQ3 format.\n *\n * @param a             IQ3 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ3toF(int32_t a)\n{\n    return __IQNtoF(a, 3);\n}\n/**\n * @brief Converts input to floating point using IQ2 format.\n *\n * @param a             IQ2 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ2toF(int32_t a)\n{\n    return __IQNtoF(a, 2);\n}\n/**\n * @brief Converts input to floating point using IQ1 format.\n *\n * @param a             IQ1 type value to be converted.\n *\n * @return              Conversion of input to floating point.\n */\nfloat _IQ1toF(int32_t a)\n{\n    return __IQNtoF(a, 1);\n}\n"
  },
  {
    "path": "iqmath/_IQNfunctions/_IQNtoa.c",
    "content": "/*!****************************************************************************\n *  @file       _IQNtoa.c\n *  @brief      Functions to convert an IQ number to a string.\n *\n *  <hr>\n ******************************************************************************/\n\n#include <stdint.h>\n\n#include \"../support/support.h\"\n\n/*\n * Convert IQN values to string.\n */\n/**\n * @brief Convert an IQ number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQN type input.\n * @param q_value         IQ format.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__IQNtoa)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nint_fast16_t __IQNtoa(char *string, const char *format, int_fast32_t iqNInput, int_fast16_t q_value)\n{\n    char *pcBuf;                    // buffer pointer\n    int_fast16_t count;                  // conversion character counter\n    uint_fast16_t ui16IntWidth;          // integer format width\n    uint_fast16_t ui16FracWidth;         // fractional format width\n    uint_fast16_t ui16IntState;          // save interrupt state\n    uint_fast16_t ui16MPYState;          // save multiplier state\n    uint_fast32_t uiqNInput;             // unsigned input\n    uint_fast32_t uiq32Fractional;       // working variable\n    uint_fast32_t ui32Integer;           // working variable\n    uint_fast32_t ui32IntTemp;           // temp variable\n    uint_fast32_t ui32IntegerTenth;      // uval scaled by 10\n    uint_fast64_t uiiq32FractionalTen;   // fractional input scaled by 10\n\n    /* Check that 1st character is a '%' character. */\n    if (*format++ != '%') {\n        /* Error: format not preceded with '%' character. */\n        return (2);\n    }\n\n    /* Check that an integer is provided and extract the integer width. */\n    if (*format < '0' || *format > '9') {\n        /* Error: integer width is non integer. */\n        return (2);\n    }\n\n    /* Initialize local variables and extract the integer width. */\n    count = 0;\n    ui16IntWidth = 0;\n    while (*format >= '0' && *format <= '9') {\n        __mpy_start(&ui16IntState, &ui16MPYState);\n        ui16IntWidth = __mpy_uw(ui16IntWidth, 10);\n        __mpy_stop(&ui16IntState, &ui16MPYState);\n        ui16IntWidth = ui16IntWidth + (*format++ - '0');\n\n        /* If we don't find the '.' after 2 counts, something is wrong. */\n        if (++count > 2) {\n            /* Error: integer width field too many characters */\n            return (2);\n        }\n    }\n\n    /* Check integer width for errors. */\n    if (ui16IntWidth > 11) {\n        /* Error: integer width too large */\n        return (2);\n    }\n\n    /* Check the next character for '.' and increment over. */\n    if (*format++ != '.') {\n        /* Error: format missing the '.' character. */\n        return (2);\n    }\n\n    /* Re-initialize the local variables and extract the fractional width. */\n    count = 0;\n    ui16FracWidth = 0;\n    while (*format >= '0' && *format <= '9') {\n        __mpy_start(&ui16IntState, &ui16MPYState);\n        ui16FracWidth = __mpy_uw(ui16FracWidth, 10);\n        __mpy_stop(&ui16IntState, &ui16MPYState);\n        ui16FracWidth = ui16FracWidth + (*format++ - '0');\n\n        /* If we don't exit after 2 counts, something is wrong. */\n        if (++count > 2) {\n            /* Error: fractional width field too many characters */\n            return (2);\n        }\n    }\n\n    /* Check the next character for 'f' or 'F'. */\n    if (*format != 'f' && *format != 'F') {\n        /* Error: format missing the format specifying character. */\n        return (2);\n    }\n\n    /* Check that the next character is the NULL string terminator. */\n    if (*++format != 0) {\n        /* Error: missing null terminator. */\n        return (2);\n    }\n\n    /*\n     * Begin constructing the string.\n     */\n    pcBuf = string;\n\n    /* Check for negative value. */\n    if (iqNInput < 0) {\n        iqNInput = -iqNInput;\n        *pcBuf++ = '-';\n    }\n    uiqNInput = (uint_fast32_t)iqNInput;\n\n    /* Construct the integer string in reverse. */\n    pcBuf += ui16IntWidth;\n    ui32Integer = uiqNInput >> q_value;\n\n    for (count = ui16IntWidth; count > 0; count--) {\n        /* Integer position n = ui32Integer - floor(ui32Integer/(10^n))*(10^n) */\n        __mpyf_start(&ui16IntState, &ui16MPYState);\n        ui32IntegerTenth = __mpyf_l(ui32Integer, iq31_oneTenth);\n        __mpy_clear_ctl0();\n        ui32IntTemp = __mpy_ul(ui32IntegerTenth, 10);\n        /* Handle any possible rounding. */\n        if (ui32IntTemp > ui32Integer) {\n            ui32IntTemp -= 10;\n            ui32IntegerTenth -= 1;\n        }\n        ui32Integer -= ui32IntTemp;\n        __mpy_stop(&ui16IntState, &ui16MPYState);\n\n        *--pcBuf = ui32Integer + '0';\n        ui32Integer = ui32IntegerTenth;\n    }\n\n    /* Check if there is any remaining input. */\n    if (ui32Integer) {\n        /* Error: integer format too small. */\n        return (1);\n    }\n\n    /* Construct the fractional string if specified using unsigned iq32. */\n    pcBuf += ui16IntWidth;\n    uiq32Fractional = uiqNInput << (32 - q_value);\n\n    if (ui16FracWidth > 0) {\n        *pcBuf++ = '.';\n\n        while (ui16FracWidth--) {\n            __mpy_start(&ui16IntState, &ui16MPYState);\n            uiiq32FractionalTen = __mpyx_u(uiq32Fractional, 10);\n            __mpy_stop(&ui16IntState, &ui16MPYState);\n\n            uiq32Fractional = (uint_fast32_t)uiiq32FractionalTen;\n            *pcBuf++ = (uint8_t)(uiiq32FractionalTen >> 32) + '0';\n        }\n    }\n\n    /* Add null terminating character and return. */\n    *pcBuf = 0;\n    return (0);\n}\n\n/**\n * @brief Convert an IQ31 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ31 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ31toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 31);\n}\n/**\n * @brief Convert an IQ30 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ30 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ30toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 30);\n}\n/**\n * @brief Convert an IQ29 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ29 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ29toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 29);\n}\n/**\n * @brief Convert an IQ28 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ28 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ28toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 28);\n}\n/**\n * @brief Convert an IQ27 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ27 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ27toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 27);\n}\n/**\n * @brief Convert an IQ26 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ26 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ26toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 26);\n}\n/**\n * @brief Convert an IQ25 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ25 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ25toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 25);\n}\n/**\n * @brief Convert an IQ24 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ24 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ24toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 24);\n}\n/**\n * @brief Convert an IQ23 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ23 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ23toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 23);\n}\n/**\n * @brief Convert an IQ22 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ22 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ22toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 22);\n}\n/**\n * @brief Convert an IQ21 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ21 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ21toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 21);\n}\n/**\n * @brief Convert an IQ20 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ20 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ20toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 20);\n}\n/**\n * @brief Convert an IQ19 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ19 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ19toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 19);\n}\n/**\n * @brief Convert an IQ18 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ18 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ18toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 18);\n}\n/**\n * @brief Convert an IQ17 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ17 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ17toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 17);\n}\n/**\n * @brief Convert an IQ16 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ16 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ16toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 16);\n}\n/**\n * @brief Convert an IQ15 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ15 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ15toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 15);\n}\n/**\n * @brief Convert an IQ14 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ14 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ14toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 14);\n}\n/**\n * @brief Convert an IQ13 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ13 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ13toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 13);\n}\n/**\n * @brief Convert an IQ12 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ12 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ12toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 12);\n}\n/**\n * @brief Convert an IQ11 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ11 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ11toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 11);\n}\n/**\n * @brief Convert an IQ10 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ10 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ10toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 10);\n}\n/**\n * @brief Convert an IQ9 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ9 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ9toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 9);\n}\n/**\n * @brief Convert an IQ8 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ8 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ8toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 8);\n}\n/**\n * @brief Convert an IQ7 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ7 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ7toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 7);\n}\n/**\n * @brief Convert an IQ6 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ6 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ6toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 6);\n}\n/**\n * @brief Convert an IQ5 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ5 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ5toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 5);\n}\n/**\n * @brief Convert an IQ4 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ4 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ4toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 4);\n}\n/**\n * @brief Convert an IQ3 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ3 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ3toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 3);\n}\n/**\n * @brief Convert an IQ2 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ2 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ2toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 2);\n}\n/**\n * @brief Convert an IQ1 number to a string.\n *\n * @param string          Pointer to the buffer to store the converted IQ number.\n * @param format          The format string specifying how to convert the IQ number.\n * @param iqNInput        IQ1 type input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\nint16_t _IQ1toa(char *string, const char *format, int32_t iqNInput)\n{\n    return __IQNtoa(string, format, iqNInput, 1);\n}\n"
  },
  {
    "path": "iqmath/_IQNfunctions/_IQNversion.c",
    "content": "const char IQmathLibVersionString[] = \"IQmathLib version 01_11_00_00\";\n\nconst char *_IQmathLibVersionString(void)\n{\n    return IQmathLibVersionString;\n}\n"
  },
  {
    "path": "iqmath/_IQNfunctions/_atoIQN.c",
    "content": "/*!****************************************************************************\n *  @file       _atoIQN.c\n *  @brief      Functions to convert a string to an IQN number\n *\n *  <hr>\n ******************************************************************************/\n\n#include <stdint.h>\n\n#include \"../support/support.h\"\n\n/**\n * @brief Converts string to an IQN number.\n *\n * @param string          Pointer to the string to be converted.\n * @param q_value         IQ format.\n *\n * @return                Conversion of string to IQN type.\n */\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__atoIQN)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\n__STATIC_INLINE int_fast32_t __atoIQN(const char *string, int_fast32_t q_value)\n{\n    uint8_t sgn;\n    uint_fast16_t ui16IntState;\n    uint_fast16_t ui16MPYState;\n    uint_fast32_t iqNResult;\n    uint_fast32_t uiq0Integer = 0;\n    uint_fast32_t uiq31Fractional = 0;\n    uint_fast32_t max_int = 0x7fffffff >> q_value;\n\n    /* Check for sign */\n    if (*string == '-') {\n        string++;\n        sgn = 1;\n    } else {\n        sgn = 0;\n    }\n\n    /* Setup the device multiplier. */\n    __mpy_start(&ui16IntState, &ui16MPYState);\n\n    /* Process integer portion of string starting from first character. */\n    while ((*string != '.') && (*string != 0)) {\n        /* Check for invalid character */\n        if (*string < '0' || *string > '9') {\n            return 0;\n        }\n\n        /* Check that multiplying by 10 won't cause overflow */\n        if (uiq0Integer > iq31_pointOne) {\n            if (sgn) {\n                return 0x80000000;\n            } else {\n                return 0x7fffffff;\n            }\n        }\n\n        /* Multiply by 10 */\n        uiq0Integer = __mpy_l(uiq0Integer, 10);\n\n        /* Add next integer to result */\n        uiq0Integer += *string++ - '0';\n\n        /* Check to see if integer portion has overflowed */\n        if (uiq0Integer > max_int) {\n            if (sgn) {\n                return 0x80000000;\n            } else {\n                return 0x7fffffff;\n            }\n        }\n    }\n\n    /* Restore multiplier context. */\n    __mpy_stop(&ui16IntState, &ui16MPYState);\n\n    /* Check if previous loop ended with null character and return. */\n    if (*string == 0) {\n        /* Shift integer portion up */\n        iqNResult = uiq0Integer << q_value;\n\n        /* Return the result. */\n        return iqNResult;\n    }\n\n    /* Increment to the null terminating character and back up one character. */\n    while (*++string);\n    string--;\n\n    /* Setup the device multiplier. */\n    __mpy_start(&ui16IntState, &ui16MPYState);\n\n    /* Process fractional portion of string starting at the last character. */\n    while (*string != '.') {\n        /* Check for invalid character */\n        if (*string < '0' || *string > '9') {\n            return 0;\n        }\n\n        /* Multiply fractional piece by 0.1 to setup the next decimal place. */\n        __mpy_set_frac();\n        uiq31Fractional = __mpyf_ul(uiq31Fractional, iq31_pointOne);\n        __mpy_clear_ctl0();\n\n        /*\n         * Add the current decimal place converted to iq31 to the sum and\n         * decrement pointer.\n         */\n        uiq31Fractional += __mpy_ul((*string - '0'), iq31_pointOne);\n        string--;\n    }\n\n    /* Restore multiplier context. */\n    __mpy_stop(&ui16IntState, &ui16MPYState);\n\n    /* Shift integer portion up */\n    uiq0Integer <<= q_value;\n\n    /* Shift fractional portion to match Q type with rounding. */\n    if (q_value != 31) {\n        uiq31Fractional += ((uint_fast32_t)1 << (30 - q_value));\n    }\n    uiq31Fractional >>= (31 - q_value);\n\n    /* Construct the iqN result. */\n    iqNResult = uiq0Integer + uiq31Fractional;\n    if (sgn) {\n        iqNResult = -iqNResult;\n    }\n\n    /* Finished, return the result */\n    return iqNResult;\n}\n\n/**\n * @brief Converts string to IQ31 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ31 type.\n */\nint32_t _atoIQ31(const char *string)\n{\n    return __atoIQN(string, 31);\n}\n/**\n * @brief Converts string to IQ30 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ30 type.\n */\nint32_t _atoIQ30(const char *string)\n{\n    return __atoIQN(string, 30);\n}\n/**\n * @brief Converts string to IQ29 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ29 type.\n */\nint32_t _atoIQ29(const char *string)\n{\n    return __atoIQN(string, 29);\n}\n/**\n * @brief Converts string to IQ28 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ28 type.\n */\nint32_t _atoIQ28(const char *string)\n{\n    return __atoIQN(string, 28);\n}\n/**\n * @brief Converts string to IQ27 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ27 type.\n */\nint32_t _atoIQ27(const char *string)\n{\n    return __atoIQN(string, 27);\n}\n/**\n * @brief Converts string to IQ26 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ26 type.\n */\nint32_t _atoIQ26(const char *string)\n{\n    return __atoIQN(string, 26);\n}\n/**\n * @brief Converts string to IQ25 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ25 type.\n */\nint32_t _atoIQ25(const char *string)\n{\n    return __atoIQN(string, 25);\n}\n/**\n * @brief Converts string to IQ24 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ24 type.\n */\nint32_t _atoIQ24(const char *string)\n{\n    return __atoIQN(string, 24);\n}\n/**\n * @brief Converts string to IQ23 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ23 type.\n */\nint32_t _atoIQ23(const char *string)\n{\n    return __atoIQN(string, 23);\n}\n/**\n * @brief Converts string to IQ22 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ22 type.\n */\nint32_t _atoIQ22(const char *string)\n{\n    return __atoIQN(string, 22);\n}\n/**\n * @brief Converts string to IQ21 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ21 type.\n */\nint32_t _atoIQ21(const char *string)\n{\n    return __atoIQN(string, 21);\n}\n/**\n * @brief Converts string to IQ20 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ20 type.\n */\nint32_t _atoIQ20(const char *string)\n{\n    return __atoIQN(string, 20);\n}\n/**\n * @brief Converts string to IQ19 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ19 type.\n */\nint32_t _atoIQ19(const char *string)\n{\n    return __atoIQN(string, 19);\n}\n/**\n * @brief Converts string to IQ18 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ18 type.\n */\nint32_t _atoIQ18(const char *string)\n{\n    return __atoIQN(string, 18);\n}\n/**\n * @brief Converts string to IQ17 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ17 type.\n */\nint32_t _atoIQ17(const char *string)\n{\n    return __atoIQN(string, 17);\n}\n/**\n * @brief Converts string to IQ16 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ16 type.\n */\nint32_t _atoIQ16(const char *string)\n{\n    return __atoIQN(string, 16);\n}\n/**\n * @brief Converts string to IQ15 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ15 type.\n */\nint32_t _atoIQ15(const char *string)\n{\n    return __atoIQN(string, 15);\n}\n/**\n * @brief Converts string to IQ14 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ14 type.\n */\nint32_t _atoIQ14(const char *string)\n{\n    return __atoIQN(string, 14);\n}\n/**\n * @brief Converts string to IQ13 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ13 type.\n */\nint32_t _atoIQ13(const char *string)\n{\n    return __atoIQN(string, 13);\n}\n/**\n * @brief Converts string to IQ12 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ12 type.\n */\nint32_t _atoIQ12(const char *string)\n{\n    return __atoIQN(string, 12);\n}\n/**\n * @brief Converts string to IQ11 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ11 type.\n */\nint32_t _atoIQ11(const char *string)\n{\n    return __atoIQN(string, 11);\n}\n/**\n * @brief Converts string to IQ10 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ10 type.\n */\nint32_t _atoIQ10(const char *string)\n{\n    return __atoIQN(string, 10);\n}\n/**\n * @brief Converts string to IQ9 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ9 type.\n */\nint32_t _atoIQ9(const char *string)\n{\n    return __atoIQN(string, 9);\n}\n/**\n * @brief Converts string to IQ8 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ8 type.\n */\nint32_t _atoIQ8(const char *string)\n{\n    return __atoIQN(string, 8);\n}\n/**\n * @brief Converts string to IQ7 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ7 type.\n */\nint32_t _atoIQ7(const char *string)\n{\n    return __atoIQN(string, 7);\n}\n/**\n * @brief Converts string to IQ6 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ6 type.\n */\nint32_t _atoIQ6(const char *string)\n{\n    return __atoIQN(string, 6);\n}\n/**\n * @brief Converts string to IQ5 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ5 type.\n */\nint32_t _atoIQ5(const char *string)\n{\n    return __atoIQN(string, 5);\n}\n/**\n * @brief Converts string to IQ4 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ4 type.\n */\nint32_t _atoIQ4(const char *string)\n{\n    return __atoIQN(string, 4);\n}\n/**\n * @brief Converts string to IQ3 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ3 type.\n */\nint32_t _atoIQ3(const char *string)\n{\n    return __atoIQN(string, 3);\n}\n/**\n * @brief Converts string to IQ2 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ2 type.\n */\nint32_t _atoIQ2(const char *string)\n{\n    return __atoIQN(string, 2);\n}\n/**\n * @brief Converts string to IQ1 number.\n *\n * @param string        Pointer to the string to be converted.\n *\n * @return              Conversion of string to IQ1 type.\n */\nint32_t _atoIQ1(const char *string)\n{\n    return __atoIQN(string, 1);\n}\n"
  },
  {
    "path": "iqmath/examples/get_started/CMakeLists.txt",
    "content": "# For more information about build system see\n# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html\n# The following five lines of boilerplate have to be in your project's\n# CMakeLists in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(iqmath_get_started)\n"
  },
  {
    "path": "iqmath/examples/get_started/README.md",
    "content": "# IQMath Get Started\n\nThis example demonstrates how to use the [IQMath](https://components.espressif.com/component/espressif/iqmath) library.\n\n## How to Use Example\n\n### Hardware Required\n\n* A development board with Espressif SoC\n* A USB cable for Power supply and programming\n\n### Configure the Example\n\nBefore project configuration and build, be sure to set the correct chip target using `idf.py set-target <chip_name>`.\n\n### Build and Flash\n\nRun `idf.py -p PORT build flash monitor` to build, flash and monitor the project.\n\n(To exit the serial monitor, type ``Ctrl-]``.)\n\nSee the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.\n\n## Example Output\n\n```text\nI (308) main_task: Started on CPU0\nI (308) main_task: Calling app_main()\nI (308) example: IQMath test passed\nI (318) main_task: Returned from app_main()\n```\n"
  },
  {
    "path": "iqmath/examples/get_started/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"iqmath_example_main.c\"\n                       INCLUDE_DIRS \".\")\n"
  },
  {
    "path": "iqmath/examples/get_started/main/idf_component.yml",
    "content": "## IDF Component Manager Manifest File\ndependencies:\n  espressif/iqmath:\n    version: '^1'\n    override_path: '../../../'\n"
  },
  {
    "path": "iqmath/examples/get_started/main/iqmath_example_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n#include <stdio.h>\n#include <stdbool.h>\n#include <math.h>\n#include \"esp_log.h\"\n#include \"IQmathLib.h\"\n\nstatic const char *TAG = \"example\";\n\n#define ERROR_WITHIN_TOLERANCE(result, expected, tolerance) \\\n    (((result) >= ((expected) - ((expected) * (tolerance)))) && \\\n    ((result) <= ((expected) + ((expected) * (tolerance)))))\n\nvoid app_main(void)\n{\n    const float error_tolerance = 0.01;\n    bool test_failure = false;\n\n    /* floating point variable to verify results */\n    float res;\n    /* IQ variables using global type */\n    _iq qA, qB, qC;\n    /* IQ variables using IQ8 type */\n    _iq8 q8A, q8B, q8C;\n    /* IQ variables using IQ15 type */\n    _iq15 q15A, q15C;\n\n    /* Basic global IQ operations. */\n    qA  = _IQ(1.0);\n    qB  = _IQ(2.5);\n    qC  = qA + qB;\n    /* 3.5 = 1.0 + 2.5 */\n    res = _IQtoF(qC);\n    if (!ERROR_WITHIN_TOLERANCE(res, 3.5, error_tolerance)) {\n        test_failure = true;\n    };\n\n    qC  = qC - _IQmpy2(qA);\n    /* 1.5 = 3.5 - 2*(1.0) */\n    res = _IQtoF(qC);\n    if (!ERROR_WITHIN_TOLERANCE(res, 1.5, error_tolerance)) {\n        test_failure = true;\n    };\n\n    qC  = _IQmpy(qB, qC);\n    /* 3.75 = 2.5 * 1.5 */\n    res = _IQtoF(qC);\n    if (!ERROR_WITHIN_TOLERANCE(res, 3.75, error_tolerance)) {\n        test_failure = true;\n    };\n\n    qC  = _IQdiv(qC, qB);\n    /* 1.5 = 3.75 / 2.5 */\n    res = _IQtoF(qC);\n    if (!ERROR_WITHIN_TOLERANCE(res, 1.5, error_tolerance)) {\n        test_failure = true;\n    };\n\n    qC  = _IQsqrt(qB);\n    /* 1.58113885 = sqrt(2.5) */\n    res = _IQtoF(qC);\n    if (!ERROR_WITHIN_TOLERANCE(res, 1.58113885, error_tolerance)) {\n        test_failure = true;\n    };\n\n    /* Trigonometric global IQ operations. */\n    qA  = _IQ(M_PI / 4.0);\n    qB  = _IQ(0.5);\n    qC  = _IQsin(qA);\n    /* 0.707106709 = sin(PI/4) */\n    res = _IQtoF(qC);\n    if (!ERROR_WITHIN_TOLERANCE(res, 0.707106709, error_tolerance)) {\n        test_failure = true;\n    };\n\n    qC  = _IQcos(qA);\n    /* 0.707106769 = cos(PI/4) */\n    res = _IQtoF(qC);\n    if (!ERROR_WITHIN_TOLERANCE(res, 0.707106769, error_tolerance)) {\n        test_failure = true;\n    };\n\n    qC  = _IQatan(qB);\n    /* 0.463647604 = atan(0.5) */\n    res = _IQtoF(qC);\n    if (!ERROR_WITHIN_TOLERANCE(res, 0.463647604, error_tolerance)) {\n        test_failure = true;\n    };\n\n    /* Exponential global IQ operations. */\n    qA  = _IQ(2.71828);\n    qB  = _IQ(0.5);\n    qC  = _IQlog(qA);\n    /* 0.9999999225 = ln(e) */\n    res = _IQtoF(qC);\n    if (!ERROR_WITHIN_TOLERANCE(res, 0.9999999225, error_tolerance)) {\n        test_failure = true;\n    };\n\n    qC  = _IQexp(qB);\n    /* 1.64872134 = e^0.5 */\n    res = _IQtoF(qC);\n    if (!ERROR_WITHIN_TOLERANCE(res, 1.64872134, error_tolerance)) {\n        test_failure = true;\n    };\n\n    /* Basic explicit type IQ8 operations. */\n    q8A = _IQ8(1.0);\n    q8B = _IQ8(2.5);\n    q8C = q8A + q8B;\n    /* 3.5 = 1.0 + 2.5 */\n    res = _IQ8toF(q8C);\n    if (!ERROR_WITHIN_TOLERANCE(res, 3.5, error_tolerance)) {\n        test_failure = true;\n    };\n\n    q8C = q8C - _IQmpy2(q8A);\n    /* 1.5 = 3.5 - 2*(1.0) */\n    res = _IQ8toF(q8C);\n    if (!ERROR_WITHIN_TOLERANCE(res, 1.5, error_tolerance)) {\n        test_failure = true;\n    };\n\n    q8C = _IQ8mpy(q8B, q8C);\n    /* 3.75 = 2.5 * 1.5 */\n    res = _IQ8toF(q8C);\n    if (!ERROR_WITHIN_TOLERANCE(res, 3.75, error_tolerance)) {\n        test_failure = true;\n    };\n\n    q8C = _IQ8div(q8C, q8B);\n    /* 1.5 = 3.75 / 2.5 */\n    res = _IQ8toF(q8C);\n    if (!ERROR_WITHIN_TOLERANCE(res, 1.5, error_tolerance)) {\n        test_failure = true;\n    };\n\n    q8C = _IQ8sqrt(q8B);\n    /* 1.58203125 = sqrt(2.5) */\n    res = _IQ8toF(q8C);\n    if (!ERROR_WITHIN_TOLERANCE(res, 1.58203125, error_tolerance)) {\n        test_failure = true;\n    };\n\n    /* Trigonometric explicit type IQ15 operations. */\n    q15A = _IQ15(M_PI / 4.0);\n    q15C = _IQ15sin(q15A);\n    /* 0.707061768 = sin(PI/4) */\n    res  = _IQ15toF(q15C);\n    if (!ERROR_WITHIN_TOLERANCE(res, 0.707061768, error_tolerance)) {\n        test_failure = true;\n    };\n\n    q15C = _IQ15cos(q15A);\n    /* 0.707061768 = cos(PI/4) */\n    res  = _IQ15toF(q15C);\n    if (!ERROR_WITHIN_TOLERANCE(res, 0.707061768, error_tolerance)) {\n        test_failure = true;\n    };\n\n    /* Explicit type IQ8 to Global IQ conversion with saturation check. */\n    q8A = _IQ8(1.0);\n    q8B = _IQ8(16.0);\n    qC  = _IQ8toIQ(_IQsat(q8A, _IQtoQ8(MAX_IQ_POS), _IQtoQ8(MAX_IQ_NEG)));\n    /* _IQ8(1.0) -> _IQ(1.0) (q8A does not saturate) */\n    res = _IQtoF(qC);\n    if (!ERROR_WITHIN_TOLERANCE(res, 1.0, error_tolerance)) {\n        test_failure = true;\n    };\n\n    qC  = _IQ8toIQ(_IQsat(q8B, _IQtoQ8(MAX_IQ_POS), _IQtoQ8(MAX_IQ_NEG)));\n    /* _IQ8(16.0) -> ~MAX_IQ_POS (q8A saturates to maximum positive _IQ value) */\n    res = _IQtoF(qC);\n    if (!ERROR_WITHIN_TOLERANCE(res, 16.0, error_tolerance)) {\n        test_failure = true;\n    };\n\n    if (test_failure == true) {\n        ESP_LOGE(TAG, \"IQMath test failed\");\n    } else {\n        ESP_LOGI(TAG, \"IQMath test passed\");\n    }\n}\n"
  },
  {
    "path": "iqmath/examples/get_started/pytest_iqmath_example.py",
    "content": "import pytest\n\n\n@pytest.mark.generic\ndef test_iqmath_example(dut) -> None:\n    dut.expect_exact(\"IQMath test passed\")\n"
  },
  {
    "path": "iqmath/idf_component.yml",
    "content": "version: \"1.11.0~1\"\ndescription: IQMath fixed-point mathematical library\nurl: https://github.com/espressif/idf-extra-components/tree/master/iqmath\ndependencies:\n  idf: \">=4.4\"\n"
  },
  {
    "path": "iqmath/include/IQmathLib.h",
    "content": "/*!****************************************************************************\n *  @file       IQmathLib.h\n *  @brief      Library of IQMath operations.\n *\n *  <hr>\n ******************************************************************************/\n#ifndef __IQMATHLIB_H__\n#define __IQMATHLIB_H__\n\n//*****************************************************************************\n//\n// If building with a C++ compiler, make all of the definitions in this header\n// have a C binding.\n//\n//*****************************************************************************\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\n//*****************************************************************************\n/*!\n * @brief The IQ format to be used when the IQ format is not explicitly specified\n * (such as _IQcos instead of _IQ16cos).  This value must be between 1 and 30,\n * inclusive.\n */\n//*****************************************************************************\n#ifndef GLOBAL_IQ\n#define GLOBAL_IQ                24\n#endif\n\n//*****************************************************************************\n//\n// Include some standard headers.\n//\n//*****************************************************************************\n#include <limits.h>\n#include <stdlib.h>\n#include <stdint.h>\n\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\n//*****************************************************************************\n//\n// Various Useful Constant Definitions:\n//\n//*****************************************************************************\n#define Q30                     30\n#define Q29                     29\n#define Q28                     28\n#define Q27                     27\n#define Q26                     26\n#define Q25                     25\n#define Q24                     24\n#define Q23                     23\n#define Q22                     22\n#define Q21                     21\n#define Q20                     20\n#define Q19                     19\n#define Q18                     18\n#define Q17                     17\n#define Q16                     16\n#define Q15                     15\n#define Q14                     14\n#define Q13                     13\n#define Q12                     12\n#define Q11                     11\n#define Q10                     10\n#define Q9                      9\n#define Q8                      8\n#define Q7                      7\n#define Q6                      6\n#define Q5                      5\n#define Q4                      4\n#define Q3                      3\n#define Q2                      2\n#define Q1                      1\n#ifndef QG\n#define QG                      GLOBAL_IQ\n#endif\n\n#define MAX_IQ_POS              LONG_MAX\n#define MAX_IQ_NEG              LONG_MIN\n#define MIN_IQ_POS              1\n#define MIN_IQ_NEG              -1\n\n//*****************************************************************************\n//\n// The types for the various IQ formats.\n//\n//*****************************************************************************\ntypedef int32_t _iq30;\ntypedef int32_t _iq29;\ntypedef int32_t _iq28;\ntypedef int32_t _iq27;\ntypedef int32_t _iq26;\ntypedef int32_t _iq25;\ntypedef int32_t _iq24;\ntypedef int32_t _iq23;\ntypedef int32_t _iq22;\ntypedef int32_t _iq21;\ntypedef int32_t _iq20;\ntypedef int32_t _iq19;\ntypedef int32_t _iq18;\ntypedef int32_t _iq17;\ntypedef int32_t _iq16;\ntypedef int32_t _iq15;\ntypedef int32_t _iq14;\ntypedef int32_t _iq13;\ntypedef int32_t _iq12;\ntypedef int32_t _iq11;\ntypedef int32_t _iq10;\ntypedef int32_t _iq9;\ntypedef int32_t _iq8;\ntypedef int32_t _iq7;\ntypedef int32_t _iq6;\ntypedef int32_t _iq5;\ntypedef int32_t _iq4;\ntypedef int32_t _iq3;\ntypedef int32_t _iq2;\ntypedef int32_t _iq1;\ntypedef int32_t _iq;\n\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n//*****************************************************************************\n//\n// Simple multiplies or divides, which are accomplished with simple shifts.\n//\n//*****************************************************************************\n\n/**\n * @brief Multiplies an IQ value by 2.\n *\n * @param A               IQ type input.\n *\n * @return                IQ type result of multiplication.\n */\n#define _IQmpy2(A)              ((A) << 1)\n/**\n * @brief Multiplies an IQ value by 4.\n *\n * @param A               IQ type input.\n *\n * @return                IQ type result of multiplication.\n */\n#define _IQmpy4(A)              ((A) << 2)\n/**\n * @brief Multiplies an IQ value by 8.\n *\n * @param A               IQ type input.\n *\n * @return                IQ type result of multiplication.\n */\n#define _IQmpy8(A)              ((A) << 3)\n/**\n * @brief Multiplies an IQ value by 16.\n *\n * @param A               IQ type input.\n *\n * @return                IQ type result of multiplication.\n */\n#define _IQmpy16(A)             ((A) << 4)\n/**\n * @brief Multiplies an IQ value by 32.\n *\n * @param A               IQ type input.\n *\n * @return                IQ type result of multiplication.\n */\n#define _IQmpy32(A)             ((A) << 5)\n/**\n * @brief Multiplies an IQ value by 64.\n *\n * @param A               IQ type input.\n *\n * @return                IQ type result of multiplication.\n */\n#define _IQmpy64(A)             ((A) << 6)\n/**\n * @brief Divides an IQ value by 2.\n *\n * @param A               IQ type input.\n *\n * @return                IQ type result of division.\n */\n#define _IQdiv2(A)              ((A) >> 1)\n/**\n * @brief Divides an IQ value by 4.\n *\n * @param A               IQ type input.\n *\n * @return                IQ type result of division.\n */\n#define _IQdiv4(A)              ((A) >> 2)\n/**\n * @brief Divides an IQ value by 8.\n *\n * @param A               IQ type input.\n *\n * @return                IQ type result of division.\n */\n#define _IQdiv8(A)              ((A) >> 3)\n/**\n * @brief Divides an IQ value by 16.\n *\n * @param A               IQ type input.\n *\n * @return                IQ type result of division.\n */\n#define _IQdiv16(A)             ((A) >> 4)\n/**\n * @brief Divides an IQ value by 32.\n *\n * @param A               IQ type input.\n *\n * @return                IQ type result of division.\n */\n#define _IQdiv32(A)             ((A) >> 5)\n/**\n * @brief Divides an IQ value by 64.\n *\n * @param A               IQ type input.\n *\n * @return                IQ type result of division.\n */\n#define _IQdiv64(A)             ((A) >> 6)\n\n//*****************************************************************************\n//\n// Convert a value into an IQ number.\n//\n//*****************************************************************************\n/**\n * @brief Converts a value into an IQ30 number.\n *\n * @param A               Number input.\n *\n * @return                IQ30 type result.\n */\n#define _IQ30(A)                ((_iq30)((A) * ((_iq30)1 << 30)))\n/**\n * @brief Converts a value into an IQ29 number.\n *\n * @param A               Number input.\n *\n * @return                IQ29 type result.\n */\n#define _IQ29(A)                ((_iq29)((A) * ((_iq29)1 << 29)))\n/**\n * @brief Converts a value into an IQ28 number.\n *\n * @param A               Number input.\n *\n * @return                IQ28 type result.\n */\n#define _IQ28(A)                ((_iq28)((A) * ((_iq28)1 << 28)))\n/**\n * @brief Converts a value into an IQ27 number.\n *\n * @param A               Number input.\n *\n * @return                IQ27 type result.\n */\n#define _IQ27(A)                ((_iq27)((A) * ((_iq27)1 << 27)))\n/**\n * @brief Converts a value into an IQ26 number.\n *\n * @param A               Number input.\n *\n * @return                IQ26 type result.\n */\n#define _IQ26(A)                ((_iq26)((A) * ((_iq26)1 << 26)))\n/**\n * @brief Converts a value into an IQ25 number.\n *\n * @param A               Number input.\n *\n * @return                IQ25 type result.\n */\n#define _IQ25(A)                ((_iq25)((A) * ((_iq25)1 << 25)))\n/**\n * @brief Converts a value into an IQ24 number.\n *\n * @param A               Number input.\n *\n * @return                IQ24 type result.\n */\n#define _IQ24(A)                ((_iq24)((A) * ((_iq24)1 << 24)))\n/**\n * @brief Converts a value into an IQ23 number.\n *\n * @param A               Number input.\n *\n * @return                IQ23 type result.\n */\n#define _IQ23(A)                ((_iq23)((A) * ((_iq23)1 << 23)))\n/**\n * @brief Converts a value into an IQ22 number.\n *\n * @param A               Number input.\n *\n * @return                IQ22 type result.\n */\n#define _IQ22(A)                ((_iq22)((A) * ((_iq22)1 << 22)))\n/**\n * @brief Converts a value into an IQ21 number.\n *\n * @param A               Number input.\n *\n * @return                IQ21 type result.\n */\n#define _IQ21(A)                ((_iq21)((A) * ((_iq21)1 << 21)))\n/**\n * @brief Converts a value into an IQ20 number.\n *\n * @param A               Number input.\n *\n * @return                IQ20 type result.\n */\n#define _IQ20(A)                ((_iq20)((A) * ((_iq20)1 << 20)))\n/**\n * @brief Converts a value into an IQ19 number.\n *\n * @param A               Number input.\n *\n * @return                IQ19 type result.\n */\n#define _IQ19(A)                ((_iq19)((A) * ((_iq19)1 << 19)))\n/**\n * @brief Converts a value into an IQ18 number.\n *\n * @param A               Number input.\n *\n * @return                IQ18 type result.\n */\n#define _IQ18(A)                ((_iq18)((A) * ((_iq18)1 << 18)))\n/**\n * @brief Converts a value into an IQ17 number.\n *\n * @param A               Number input.\n *\n * @return                IQ17 type result.\n */\n#define _IQ17(A)                ((_iq17)((A) * ((_iq17)1 << 17)))\n/**\n * @brief Converts a value into an IQ16 number.\n *\n * @param A               Number input.\n *\n * @return                IQ16 type result.\n */\n#define _IQ16(A)                ((_iq16)((A) * ((_iq16)1 << 16)))\n/**\n * @brief Converts a value into an IQ15 number.\n *\n * @param A               Number input.\n *\n * @return                IQ15 type result.\n */\n#define _IQ15(A)                ((_iq15)((A) * ((_iq15)1 << 15)))\n/**\n * @brief Converts a value into an IQ14 number.\n *\n * @param A               Number input.\n *\n * @return                IQ14 type result.\n */\n#define _IQ14(A)                ((_iq14)((A) * ((_iq14)1 << 14)))\n/**\n * @brief Converts a value into an IQ13 number.\n *\n * @param A               Number input.\n *\n * @return                IQ13 type result.\n */\n#define _IQ13(A)                ((_iq13)((A) * ((_iq13)1 << 13)))\n/**\n * @brief Converts a value into an IQ12 number.\n *\n * @param A               Number input.\n *\n * @return                IQ12 type result.\n */\n#define _IQ12(A)                ((_iq12)((A) * ((_iq12)1 << 12)))\n/**\n * @brief Converts a value into an IQ11 number.\n *\n * @param A               Number input.\n *\n * @return                IQ11 type result.\n */\n#define _IQ11(A)                ((_iq11)((A) * ((_iq11)1 << 11)))\n/**\n * @brief Converts a value into an IQ10 number.\n *\n * @param A               Number input.\n *\n * @return                IQ10 type result.\n */\n#define _IQ10(A)                ((_iq10)((A) * ((_iq10)1 << 10)))\n/**\n * @brief Converts a value into an IQ9 number.\n *\n * @param A               Number input.\n *\n * @return                IQ9 type result.\n */\n#define _IQ9(A)                 ((_iq9)((A) * ((_iq9)1 << 9)))\n/**\n * @brief Converts a value into an IQ8 number.\n *\n * @param A               Number input.\n *\n * @return                IQ8 type result.\n */\n#define _IQ8(A)                 ((_iq8)((A) * ((_iq8)1 << 8)))\n/**\n * @brief Converts a value into an IQ7 number.\n *\n * @param A               Number input.\n *\n * @return                IQ7 type result.\n */\n#define _IQ7(A)                 ((_iq7)((A) * ((_iq7)1 << 7)))\n/**\n * @brief Converts a value into an IQ6 number.\n *\n * @param A               Number input.\n *\n * @return                IQ6 type result.\n */\n#define _IQ6(A)                 ((_iq6)((A) * ((_iq6)1 << 6)))\n/**\n * @brief Converts a value into an IQ5 number.\n *\n * @param A               Number input.\n *\n * @return                IQ5 type result.\n */\n#define _IQ5(A)                 ((_iq5)((A) * ((_iq5)1 << 5)))\n/**\n * @brief Converts a value into an IQ4 number.\n *\n * @param A               Number input.\n *\n * @return                IQ4 type result.\n */\n#define _IQ4(A)                 ((_iq4)((A) * ((_iq4)1 << 4)))\n/**\n * @brief Converts a value into an IQ3 number.\n *\n * @param A               Number input.\n *\n * @return                IQ3 type result.\n */\n#define _IQ3(A)                 ((_iq3)((A) * ((_iq3)1 << 3)))\n/**\n * @brief Converts a value into an IQ2 number.\n *\n * @param A               Number input.\n *\n * @return                IQ2 type result.\n */\n#define _IQ2(A)                 ((_iq2)((A) * ((_iq2)1 << 2)))\n/**\n * @brief Converts a value into an IQ1 number.\n *\n * @param A               Number input.\n *\n * @return                IQ1 type result.\n */\n#define _IQ1(A)                 ((_iq1)((A) * ((_iq1)1 << 1)))\n\n/**\n * @brief Converts a value into an the global IQ  format.\n *\n * @param A               Number input.\n *\n * @return                Global IQ type result.\n */\n#if GLOBAL_IQ == 30\n#define _IQ(A)                  _IQ30(A)\n#endif\n#if GLOBAL_IQ == 29\n#define _IQ(A)                  _IQ29(A)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQ(A)                  _IQ28(A)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQ(A)                  _IQ27(A)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQ(A)                  _IQ26(A)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQ(A)                  _IQ25(A)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQ(A)                  _IQ24(A)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQ(A)                  _IQ23(A)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQ(A)                  _IQ22(A)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQ(A)                  _IQ21(A)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQ(A)                  _IQ20(A)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQ(A)                  _IQ19(A)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQ(A)                  _IQ18(A)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQ(A)                  _IQ17(A)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQ(A)                  _IQ16(A)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQ(A)                  _IQ15(A)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQ(A)                  _IQ14(A)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQ(A)                  _IQ13(A)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQ(A)                  _IQ12(A)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQ(A)                  _IQ11(A)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQ(A)                  _IQ10(A)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQ(A)                  _IQ9(A)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQ(A)                  _IQ8(A)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQ(A)                  _IQ7(A)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQ(A)                  _IQ6(A)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQ(A)                  _IQ5(A)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQ(A)                  _IQ4(A)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQ(A)                  _IQ3(A)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQ(A)                  _IQ2(A)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQ(A)                  _IQ1(A)\n#endif\n\n//*****************************************************************************\n//\n// Convert an IQ number to a floating point value.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern float _IQ30toF(_iq30 A);\nextern float _IQ29toF(_iq29 A);\nextern float _IQ28toF(_iq28 A);\nextern float _IQ27toF(_iq27 A);\nextern float _IQ26toF(_iq26 A);\nextern float _IQ25toF(_iq25 A);\nextern float _IQ24toF(_iq24 A);\nextern float _IQ23toF(_iq23 A);\nextern float _IQ22toF(_iq22 A);\nextern float _IQ21toF(_iq21 A);\nextern float _IQ20toF(_iq20 A);\nextern float _IQ19toF(_iq19 A);\nextern float _IQ18toF(_iq18 A);\nextern float _IQ17toF(_iq17 A);\nextern float _IQ16toF(_iq16 A);\nextern float _IQ15toF(_iq15 A);\nextern float _IQ14toF(_iq14 A);\nextern float _IQ13toF(_iq13 A);\nextern float _IQ12toF(_iq12 A);\nextern float _IQ11toF(_iq11 A);\nextern float _IQ10toF(_iq10 A);\nextern float _IQ9toF(_iq9 A);\nextern float _IQ8toF(_iq8 A);\nextern float _IQ7toF(_iq7 A);\nextern float _IQ6toF(_iq6 A);\nextern float _IQ5toF(_iq5 A);\nextern float _IQ4toF(_iq4 A);\nextern float _IQ3toF(_iq3 A);\nextern float _IQ2toF(_iq2 A);\nextern float _IQ1toF(_iq1 A);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Convert a global IQ format number to a floating point value.\n *\n * @param A               Number input.\n *\n * @return                Global IQ type result.\n */\n#if GLOBAL_IQ == 30\n#define _IQtoF(A)               _IQ30toF(A)\n#endif\n#if GLOBAL_IQ == 29\n#define _IQtoF(A)               _IQ29toF(A)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQtoF(A)               _IQ28toF(A)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQtoF(A)               _IQ27toF(A)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQtoF(A)               _IQ26toF(A)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQtoF(A)               _IQ25toF(A)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQtoF(A)               _IQ24toF(A)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQtoF(A)               _IQ23toF(A)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQtoF(A)               _IQ22toF(A)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQtoF(A)               _IQ21toF(A)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQtoF(A)               _IQ20toF(A)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQtoF(A)               _IQ19toF(A)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQtoF(A)               _IQ18toF(A)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQtoF(A)               _IQ17toF(A)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQtoF(A)               _IQ16toF(A)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQtoF(A)               _IQ15toF(A)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQtoF(A)               _IQ14toF(A)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQtoF(A)               _IQ13toF(A)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQtoF(A)               _IQ12toF(A)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQtoF(A)               _IQ11toF(A)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQtoF(A)               _IQ10toF(A)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQtoF(A)               _IQ9toF(A)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQtoF(A)               _IQ8toF(A)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQtoF(A)               _IQ7toF(A)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQtoF(A)               _IQ6toF(A)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQtoF(A)               _IQ5toF(A)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQtoF(A)               _IQ4toF(A)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQtoF(A)               _IQ3toF(A)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQtoF(A)               _IQ2toF(A)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQtoF(A)               _IQ1toF(A)\n#endif\n\n//*****************************************************************************\n//\n// Saturates an IQ number in a given range.\n//\n//*****************************************************************************\n/**\n * @brief Saturates an IQ number in a given range.\n *\n * @param A               IQ number to be saturated.\n * @param Pos             Maximum positive value.\n * @param Neg             Minimum negative Value.\n *\n * @return                Saturated IQ type result.\n */\n#define _IQsat(A, Pos, Neg)     (((A) > (Pos)) ?                              \\\n                                 (Pos) :                                      \\\n                                 (((A) < (Neg)) ? (Neg) : (A)))\n\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\n//*****************************************************************************\n//\n// Converts an IQ number between the global IQ format and a specified IQ\n// format.\n//\n//*****************************************************************************\n#define _IQtoIQ30(A)            ((_iq30)(A) << (30 - GLOBAL_IQ))\n#define _IQ30toIQ(A)            ((_iq30)(A) >> (30 - GLOBAL_IQ))\n\n#if (GLOBAL_IQ >= 29)\n#define _IQtoIQ29(A)            ((_iq29)(A) >> (GLOBAL_IQ - 29))\n#define _IQ29toIQ(A)            ((_iq29)(A) << (GLOBAL_IQ - 29))\n#else\n#define _IQtoIQ29(A)            ((_iq29)(A) << (29 - GLOBAL_IQ))\n#define _IQ29toIQ(A)            ((_iq29)(A) >> (29 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 28)\n#define _IQtoIQ28(A)            ((_iq28)(A) >> (GLOBAL_IQ - 28))\n#define _IQ28toIQ(A)            ((_iq28)(A) << (GLOBAL_IQ - 28))\n#else\n#define _IQtoIQ28(A)            ((_iq28)(A) << (28 - GLOBAL_IQ))\n#define _IQ28toIQ(A)            ((_iq28)(A) >> (28 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 27)\n#define _IQtoIQ27(A)            ((_iq27)(A) >> (GLOBAL_IQ - 27))\n#define _IQ27toIQ(A)            ((_iq27)(A) << (GLOBAL_IQ - 27))\n#else\n#define _IQtoIQ27(A)            ((_iq27)(A) << (27 - GLOBAL_IQ))\n#define _IQ27toIQ(A)            ((_iq27)(A) >> (27 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 26)\n#define _IQtoIQ26(A)            ((_iq26)(A) >> (GLOBAL_IQ - 26))\n#define _IQ26toIQ(A)            ((_iq26)(A) << (GLOBAL_IQ - 26))\n#else\n#define _IQtoIQ26(A)            ((_iq26)(A) << (26 - GLOBAL_IQ))\n#define _IQ26toIQ(A)            ((_iq26)(A) >> (26 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 25)\n#define _IQtoIQ25(A)            ((_iq25)(A) >> (GLOBAL_IQ - 25))\n#define _IQ25toIQ(A)            ((_iq25)(A) << (GLOBAL_IQ - 25))\n#else\n#define _IQtoIQ25(A)            ((_iq25)(A) << (25 - GLOBAL_IQ))\n#define _IQ25toIQ(A)            ((_iq25)(A) >> (25 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 24)\n#define _IQtoIQ24(A)            ((_iq24)(A) >> (GLOBAL_IQ - 24))\n#define _IQ24toIQ(A)            ((_iq24)(A) << (GLOBAL_IQ - 24))\n#else\n#define _IQtoIQ24(A)            ((_iq24)(A) << (24 - GLOBAL_IQ))\n#define _IQ24toIQ(A)            ((_iq24)(A) >> (24 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 23)\n#define _IQtoIQ23(A)            ((_iq23)(A) >> (GLOBAL_IQ - 23))\n#define _IQ23toIQ(A)            ((_iq23)(A) << (GLOBAL_IQ - 23))\n#else\n#define _IQtoIQ23(A)            ((_iq23)(A) << (23 - GLOBAL_IQ))\n#define _IQ23toIQ(A)            ((_iq23)(A) >> (23 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 22)\n#define _IQtoIQ22(A)            ((_iq22)(A) >> (GLOBAL_IQ - 22))\n#define _IQ22toIQ(A)            ((_iq22)(A) << (GLOBAL_IQ - 22))\n#else\n#define _IQtoIQ22(A)            ((_iq22)(A) << (22 - GLOBAL_IQ))\n#define _IQ22toIQ(A)            ((_iq22)(A) >> (22 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 21)\n#define _IQtoIQ21(A)            ((_iq21)(A) >> (GLOBAL_IQ - 21))\n#define _IQ21toIQ(A)            ((_iq21)(A) << (GLOBAL_IQ - 21))\n#else\n#define _IQtoIQ21(A)            ((_iq21)(A) << (21 - GLOBAL_IQ))\n#define _IQ21toIQ(A)            ((_iq21)(A) >> (21 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 20)\n#define _IQtoIQ20(A)            ((_iq20)(A) >> (GLOBAL_IQ - 20))\n#define _IQ20toIQ(A)            ((_iq20)(A) << (GLOBAL_IQ - 20))\n#else\n#define _IQtoIQ20(A)            ((_iq20)(A) << (20 - GLOBAL_IQ))\n#define _IQ20toIQ(A)            ((_iq20)(A) >> (20 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 19)\n#define _IQtoIQ19(A)            ((_iq19)(A) >> (GLOBAL_IQ - 19))\n#define _IQ19toIQ(A)            ((_iq19)(A) << (GLOBAL_IQ - 19))\n#else\n#define _IQtoIQ19(A)            ((_iq19)(A) << (19 - GLOBAL_IQ))\n#define _IQ19toIQ(A)            ((_iq19)(A) >> (19 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 18)\n#define _IQtoIQ18(A)            ((_iq18)(A) >> (GLOBAL_IQ - 18))\n#define _IQ18toIQ(A)            ((_iq18)(A) << (GLOBAL_IQ - 18))\n#else\n#define _IQtoIQ18(A)            ((_iq18)(A) << (18 - GLOBAL_IQ))\n#define _IQ18toIQ(A)            ((_iq18)(A) >> (18 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 17)\n#define _IQtoIQ17(A)            ((_iq17)(A) >> (GLOBAL_IQ - 17))\n#define _IQ17toIQ(A)            ((_iq17)(A) << (GLOBAL_IQ - 17))\n#else\n#define _IQtoIQ17(A)            ((_iq17)(A) << (17 - GLOBAL_IQ))\n#define _IQ17toIQ(A)            ((_iq17)(A) >> (17 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 16)\n#define _IQtoIQ16(A)            ((_iq16)(A) >> (GLOBAL_IQ - 16))\n#define _IQ16toIQ(A)            ((_iq16)(A) << (GLOBAL_IQ - 16))\n#else\n#define _IQtoIQ16(A)            ((_iq16)(A) << (16 - GLOBAL_IQ))\n#define _IQ16toIQ(A)            ((_iq16)(A) >> (16 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 15)\n#define _IQtoIQ15(A)            ((_iq15)(A) >> (GLOBAL_IQ - 15))\n#define _IQ15toIQ(A)            ((_iq15)(A) << (GLOBAL_IQ - 15))\n#else\n#define _IQtoIQ15(A)            ((_iq15)(A) << (15 - GLOBAL_IQ))\n#define _IQ15toIQ(A)            ((_iq15)(A) >> (15 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 14)\n#define _IQtoIQ14(A)            ((_iq14)(A) >> (GLOBAL_IQ - 14))\n#define _IQ14toIQ(A)            ((_iq14)(A) << (GLOBAL_IQ - 14))\n#else\n#define _IQtoIQ14(A)            ((_iq14)(A) << (14 - GLOBAL_IQ))\n#define _IQ14toIQ(A)            ((_iq14)(A) >> (14 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 13)\n#define _IQtoIQ13(A)            ((_iq13)(A) >> (GLOBAL_IQ - 13))\n#define _IQ13toIQ(A)            ((_iq13)(A) << (GLOBAL_IQ - 13))\n#else\n#define _IQtoIQ13(A)            ((_iq13)(A) << (13 - GLOBAL_IQ))\n#define _IQ13toIQ(A)            ((_iq13)(A) >> (13 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 12)\n#define _IQtoIQ12(A)            ((_iq12)(A) >> (GLOBAL_IQ - 12))\n#define _IQ12toIQ(A)            ((_iq12)(A) << (GLOBAL_IQ - 12))\n#else\n#define _IQtoIQ12(A)            ((_iq12)(A) << (12 - GLOBAL_IQ))\n#define _IQ12toIQ(A)            ((_iq12)(A) >> (12 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 11)\n#define _IQtoIQ11(A)            ((_iq11)(A) >> (GLOBAL_IQ - 11))\n#define _IQ11toIQ(A)            ((_iq11)(A) << (GLOBAL_IQ - 11))\n#else\n#define _IQtoIQ11(A)            ((_iq11)(A) << (11 - GLOBAL_IQ))\n#define _IQ11toIQ(A)            ((_iq11)(A) >> (11 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 10)\n#define _IQtoIQ10(A)            ((_iq10)(A) >> (GLOBAL_IQ - 10))\n#define _IQ10toIQ(A)            ((_iq10)(A) << (GLOBAL_IQ - 10))\n#else\n#define _IQtoIQ10(A)            ((_iq10)(A) << (10 - GLOBAL_IQ))\n#define _IQ10toIQ(A)            ((_iq10)(A) >> (10 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 9)\n#define _IQtoIQ9(A)             ((_iq9)(A) >> (GLOBAL_IQ - 9))\n#define _IQ9toIQ(A)             ((_iq9)(A) << (GLOBAL_IQ - 9))\n#else\n#define _IQtoIQ9(A)             ((_iq9)(A) << (9 - GLOBAL_IQ))\n#define _IQ9toIQ(A)             ((_iq9)(A) >> (9 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 8)\n#define _IQtoIQ8(A)             ((_iq8)(A) >> (GLOBAL_IQ - 8))\n#define _IQ8toIQ(A)             ((_iq8)(A) << (GLOBAL_IQ - 8))\n#else\n#define _IQtoIQ8(A)             ((_iq8)(A) << (8 - GLOBAL_IQ))\n#define _IQ8toIQ(A)             ((_iq8)(A) >> (8 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 7)\n#define _IQtoIQ7(A)             ((_iq7)(A) >> (GLOBAL_IQ - 7))\n#define _IQ7toIQ(A)             ((_iq7)(A) << (GLOBAL_IQ - 7))\n#else\n#define _IQtoIQ7(A)             ((_iq7)(A) << (7 - GLOBAL_IQ))\n#define _IQ7toIQ(A)             ((_iq7)(A) >> (7 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 6)\n#define _IQtoIQ6(A)             ((_iq6)(A) >> (GLOBAL_IQ - 6))\n#define _IQ6toIQ(A)             ((_iq6)(A) << (GLOBAL_IQ - 6))\n#else\n#define _IQtoIQ6(A)             ((_iq6)(A) << (6 - GLOBAL_IQ))\n#define _IQ6toIQ(A)             ((_iq6)(A) >> (6 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 5)\n#define _IQtoIQ5(A)             ((_iq5)(A) >> (GLOBAL_IQ - 5))\n#define _IQ5toIQ(A)             ((_iq5)(A) << (GLOBAL_IQ - 5))\n#else\n#define _IQtoIQ5(A)             ((_iq5)(A) << (5 - GLOBAL_IQ))\n#define _IQ5toIQ(A)             ((_iq5)(A) >> (5 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 4)\n#define _IQtoIQ4(A)             ((_iq4)(A) >> (GLOBAL_IQ - 4))\n#define _IQ4toIQ(A)             ((_iq4)(A) << (GLOBAL_IQ - 4))\n#else\n#define _IQtoIQ4(A)             ((_iq4)(A) << (4 - GLOBAL_IQ))\n#define _IQ4toIQ(A)             ((_iq4)(A) >> (4 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 3)\n#define _IQtoIQ3(A)             ((_iq3)(A) >> (GLOBAL_IQ - 3))\n#define _IQ3toIQ(A)             ((_iq3)(A) << (GLOBAL_IQ - 3))\n#else\n#define _IQtoIQ3(A)             ((_iq3)(A) << (3 - GLOBAL_IQ))\n#define _IQ3toIQ(A)             ((_iq3)(A) >> (3 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 2)\n#define _IQtoIQ2(A)             ((_iq2)(A) >> (GLOBAL_IQ - 2))\n#define _IQ2toIQ(A)             ((_iq2)(A) << (GLOBAL_IQ - 2))\n#else\n#define _IQtoIQ2(A)             ((_iq2)(A) << (2 - GLOBAL_IQ))\n#define _IQ2toIQ(A)             ((_iq2)(A) >> (2 - GLOBAL_IQ))\n#endif\n\n#define _IQtoIQ1(A)             ((_iq1)(A) >> (GLOBAL_IQ - 1))\n#define _IQ1toIQ(A)             ((_iq1)(A) << (GLOBAL_IQ - 1))\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\n//*****************************************************************************\n//\n// Converts an IQ number between a specified IQ format and another\n// specified IQ format.\n//\n// For the functions of type _IQXtoIQY, the values are shifted by the\n// difference of X and Y, depending on which one is larger. The definition is\n// as follows:\n//\n//    #define _IQXtoIQY(A)\n//      If X < Y\n//          ((_iqY) (A) << (Y-X)\n//      else\n//          ((_iqY) (A) >> (X-Y)\n//\n//*****************************************************************************\n/* IQ1 to IQN */\n#define _IQ1toIQ30(A)            ((_iq30)(A) << (29))\n#define _IQ1toIQ29(A)            ((_iq29)(A) << (28))\n#define _IQ1toIQ28(A)            ((_iq28)(A) << (27))\n#define _IQ1toIQ27(A)            ((_iq27)(A) << (26))\n#define _IQ1toIQ26(A)            ((_iq26)(A) << (25))\n#define _IQ1toIQ25(A)            ((_iq25)(A) << (24))\n#define _IQ1toIQ24(A)            ((_iq24)(A) << (23))\n#define _IQ1toIQ23(A)            ((_iq23)(A) << (22))\n#define _IQ1toIQ22(A)            ((_iq22)(A) << (21))\n#define _IQ1toIQ21(A)            ((_iq21)(A) << (20))\n#define _IQ1toIQ20(A)            ((_iq20)(A) << (19))\n#define _IQ1toIQ19(A)            ((_iq19)(A) << (18))\n#define _IQ1toIQ18(A)            ((_iq18)(A) << (17))\n#define _IQ1toIQ17(A)            ((_iq17)(A) << (16))\n#define _IQ1toIQ16(A)            ((_iq16)(A) << (15))\n#define _IQ1toIQ15(A)            ((_iq15)(A) << (14))\n#define _IQ1toIQ14(A)            ((_iq14)(A) << (13))\n#define _IQ1toIQ13(A)            ((_iq13)(A) << (12))\n#define _IQ1toIQ12(A)            ((_iq12)(A) << (11))\n#define _IQ1toIQ11(A)            ((_iq11)(A) << (10))\n#define _IQ1toIQ10(A)            ((_iq10)(A) << (9))\n#define  _IQ1toIQ9(A)            ((_iq9 )(A) << (8))\n#define  _IQ1toIQ8(A)            ((_iq8 )(A) << (7))\n#define  _IQ1toIQ7(A)            ((_iq7 )(A) << (6))\n#define  _IQ1toIQ6(A)            ((_iq6 )(A) << (5))\n#define  _IQ1toIQ5(A)            ((_iq5 )(A) << (4))\n#define  _IQ1toIQ4(A)            ((_iq4 )(A) << (3))\n#define  _IQ1toIQ3(A)            ((_iq3 )(A) << (2))\n#define  _IQ1toIQ2(A)            ((_iq2 )(A) << (1))\n\n/* IQ2 to IQN */\n#define _IQ2toIQ30(A)            ((_iq30)(A) << (28))\n#define _IQ2toIQ29(A)            ((_iq29)(A) << (27))\n#define _IQ2toIQ28(A)            ((_iq28)(A) << (26))\n#define _IQ2toIQ27(A)            ((_iq27)(A) << (25))\n#define _IQ2toIQ26(A)            ((_iq26)(A) << (24))\n#define _IQ2toIQ25(A)            ((_iq25)(A) << (23))\n#define _IQ2toIQ24(A)            ((_iq24)(A) << (22))\n#define _IQ2toIQ23(A)            ((_iq23)(A) << (21))\n#define _IQ2toIQ22(A)            ((_iq22)(A) << (20))\n#define _IQ2toIQ21(A)            ((_iq21)(A) << (19))\n#define _IQ2toIQ20(A)            ((_iq20)(A) << (18))\n#define _IQ2toIQ19(A)            ((_iq19)(A) << (17))\n#define _IQ2toIQ18(A)            ((_iq18)(A) << (16))\n#define _IQ2toIQ17(A)            ((_iq17)(A) << (15))\n#define _IQ2toIQ16(A)            ((_iq16)(A) << (14))\n#define _IQ2toIQ15(A)            ((_iq15)(A) << (13))\n#define _IQ2toIQ14(A)            ((_iq14)(A) << (12))\n#define _IQ2toIQ13(A)            ((_iq13)(A) << (11))\n#define _IQ2toIQ12(A)            ((_iq12)(A) << (10))\n#define _IQ2toIQ11(A)            ((_iq11)(A) << (9))\n#define _IQ2toIQ10(A)            ((_iq10)(A) << (8))\n#define  _IQ2toIQ9(A)            ((_iq9 )(A) << (7))\n#define  _IQ2toIQ8(A)            ((_iq8 )(A) << (6))\n#define  _IQ2toIQ7(A)            ((_iq7 )(A) << (5))\n#define  _IQ2toIQ6(A)            ((_iq6 )(A) << (4))\n#define  _IQ2toIQ5(A)            ((_iq5 )(A) << (3))\n#define  _IQ2toIQ4(A)            ((_iq4 )(A) << (2))\n#define  _IQ2toIQ3(A)            ((_iq3 )(A) << (1))\n#define  _IQ2toIQ1(A)            ((_iq1 )(A) >> (1))\n\n/* IQ3 to IQN */\n#define _IQ3toIQ30(A)            ((_iq30)(A) << (27))\n#define _IQ3toIQ29(A)            ((_iq29)(A) << (26))\n#define _IQ3toIQ28(A)            ((_iq28)(A) << (25))\n#define _IQ3toIQ27(A)            ((_iq27)(A) << (24))\n#define _IQ3toIQ26(A)            ((_iq26)(A) << (23))\n#define _IQ3toIQ25(A)            ((_iq25)(A) << (22))\n#define _IQ3toIQ24(A)            ((_iq24)(A) << (21))\n#define _IQ3toIQ23(A)            ((_iq23)(A) << (20))\n#define _IQ3toIQ22(A)            ((_iq22)(A) << (19))\n#define _IQ3toIQ21(A)            ((_iq21)(A) << (18))\n#define _IQ3toIQ20(A)            ((_iq20)(A) << (17))\n#define _IQ3toIQ19(A)            ((_iq19)(A) << (16))\n#define _IQ3toIQ18(A)            ((_iq18)(A) << (15))\n#define _IQ3toIQ17(A)            ((_iq17)(A) << (14))\n#define _IQ3toIQ16(A)            ((_iq16)(A) << (13))\n#define _IQ3toIQ15(A)            ((_iq15)(A) << (12))\n#define _IQ3toIQ14(A)            ((_iq14)(A) << (11))\n#define _IQ3toIQ13(A)            ((_iq13)(A) << (10))\n#define _IQ3toIQ12(A)            ((_iq12)(A) << (9))\n#define _IQ3toIQ11(A)            ((_iq11)(A) << (8))\n#define _IQ3toIQ10(A)            ((_iq10)(A) << (7))\n#define  _IQ3toIQ9(A)            ((_iq9 )(A) << (6))\n#define  _IQ3toIQ8(A)            ((_iq8 )(A) << (5))\n#define  _IQ3toIQ7(A)            ((_iq7 )(A) << (4))\n#define  _IQ3toIQ6(A)            ((_iq6 )(A) << (3))\n#define  _IQ3toIQ5(A)            ((_iq5 )(A) << (2))\n#define  _IQ3toIQ4(A)            ((_iq4 )(A) << (1))\n#define  _IQ3toIQ2(A)            ((_iq2 )(A) >> (1))\n#define  _IQ3toIQ1(A)            ((_iq1 )(A) >> (2))\n\n/* IQ4 to IQN */\n#define _IQ4toIQ30(A)            ((_iq30)(A) << (26))\n#define _IQ4toIQ29(A)            ((_iq29)(A) << (25))\n#define _IQ4toIQ28(A)            ((_iq28)(A) << (24))\n#define _IQ4toIQ27(A)            ((_iq27)(A) << (23))\n#define _IQ4toIQ26(A)            ((_iq26)(A) << (22))\n#define _IQ4toIQ25(A)            ((_iq25)(A) << (21))\n#define _IQ4toIQ24(A)            ((_iq24)(A) << (20))\n#define _IQ4toIQ23(A)            ((_iq23)(A) << (19))\n#define _IQ4toIQ22(A)            ((_iq22)(A) << (18))\n#define _IQ4toIQ21(A)            ((_iq21)(A) << (17))\n#define _IQ4toIQ20(A)            ((_iq20)(A) << (16))\n#define _IQ4toIQ19(A)            ((_iq19)(A) << (15))\n#define _IQ4toIQ18(A)            ((_iq18)(A) << (14))\n#define _IQ4toIQ17(A)            ((_iq17)(A) << (13))\n#define _IQ4toIQ16(A)            ((_iq16)(A) << (12))\n#define _IQ4toIQ15(A)            ((_iq15)(A) << (11))\n#define _IQ4toIQ14(A)            ((_iq14)(A) << (10))\n#define _IQ4toIQ13(A)            ((_iq13)(A) << (9))\n#define _IQ4toIQ12(A)            ((_iq12)(A) << (8))\n#define _IQ4toIQ11(A)            ((_iq11)(A) << (7))\n#define _IQ4toIQ10(A)            ((_iq10)(A) << (6))\n#define  _IQ4toIQ9(A)            ((_iq9 )(A) << (5))\n#define  _IQ4toIQ8(A)            ((_iq8 )(A) << (4))\n#define  _IQ4toIQ7(A)            ((_iq7 )(A) << (3))\n#define  _IQ4toIQ6(A)            ((_iq6 )(A) << (2))\n#define  _IQ4toIQ5(A)            ((_iq5 )(A) << (1))\n#define  _IQ4toIQ3(A)            ((_iq3 )(A) >> (1))\n#define  _IQ4toIQ2(A)            ((_iq2 )(A) >> (2))\n#define  _IQ4toIQ1(A)            ((_iq1 )(A) >> (3))\n\n/* IQ5 to IQN */\n#define _IQ5toIQ30(A)            ((_iq30)(A) << (25))\n#define _IQ5toIQ29(A)            ((_iq29)(A) << (24))\n#define _IQ5toIQ28(A)            ((_iq28)(A) << (23))\n#define _IQ5toIQ27(A)            ((_iq27)(A) << (22))\n#define _IQ5toIQ26(A)            ((_iq26)(A) << (21))\n#define _IQ5toIQ25(A)            ((_iq25)(A) << (20))\n#define _IQ5toIQ24(A)            ((_iq24)(A) << (19))\n#define _IQ5toIQ23(A)            ((_iq23)(A) << (18))\n#define _IQ5toIQ22(A)            ((_iq22)(A) << (17))\n#define _IQ5toIQ21(A)            ((_iq21)(A) << (16))\n#define _IQ5toIQ20(A)            ((_iq20)(A) << (15))\n#define _IQ5toIQ19(A)            ((_iq19)(A) << (14))\n#define _IQ5toIQ18(A)            ((_iq18)(A) << (13))\n#define _IQ5toIQ17(A)            ((_iq17)(A) << (12))\n#define _IQ5toIQ16(A)            ((_iq16)(A) << (11))\n#define _IQ5toIQ15(A)            ((_iq15)(A) << (10))\n#define _IQ5toIQ14(A)            ((_iq14)(A) << (9))\n#define _IQ5toIQ13(A)            ((_iq13)(A) << (8))\n#define _IQ5toIQ12(A)            ((_iq12)(A) << (7))\n#define _IQ5toIQ11(A)            ((_iq11)(A) << (6))\n#define _IQ5toIQ10(A)            ((_iq10)(A) << (5))\n#define  _IQ5toIQ9(A)            ((_iq9 )(A) << (4))\n#define  _IQ5toIQ8(A)            ((_iq8 )(A) << (3))\n#define  _IQ5toIQ7(A)            ((_iq7 )(A) << (2))\n#define  _IQ5toIQ6(A)            ((_iq6 )(A) << (1))\n#define  _IQ5toIQ4(A)            ((_iq4 )(A) >> (1))\n#define  _IQ5toIQ3(A)            ((_iq3 )(A) >> (2))\n#define  _IQ5toIQ2(A)            ((_iq2 )(A) >> (3))\n#define  _IQ5toIQ1(A)            ((_iq1 )(A) >> (4))\n\n/* IQ6 to IQN */\n#define _IQ6toIQ30(A)            ((_iq30)(A) << (24))\n#define _IQ6toIQ29(A)            ((_iq29)(A) << (23))\n#define _IQ6toIQ28(A)            ((_iq28)(A) << (22))\n#define _IQ6toIQ27(A)            ((_iq27)(A) << (21))\n#define _IQ6toIQ26(A)            ((_iq26)(A) << (20))\n#define _IQ6toIQ25(A)            ((_iq25)(A) << (19))\n#define _IQ6toIQ24(A)            ((_iq24)(A) << (18))\n#define _IQ6toIQ23(A)            ((_iq23)(A) << (17))\n#define _IQ6toIQ22(A)            ((_iq22)(A) << (16))\n#define _IQ6toIQ21(A)            ((_iq21)(A) << (15))\n#define _IQ6toIQ20(A)            ((_iq20)(A) << (14))\n#define _IQ6toIQ19(A)            ((_iq19)(A) << (13))\n#define _IQ6toIQ18(A)            ((_iq18)(A) << (12))\n#define _IQ6toIQ17(A)            ((_iq17)(A) << (11))\n#define _IQ6toIQ16(A)            ((_iq16)(A) << (10))\n#define _IQ6toIQ15(A)            ((_iq15)(A) << (9))\n#define _IQ6toIQ14(A)            ((_iq14)(A) << (8))\n#define _IQ6toIQ13(A)            ((_iq13)(A) << (7))\n#define _IQ6toIQ12(A)            ((_iq12)(A) << (6))\n#define _IQ6toIQ11(A)            ((_iq11)(A) << (5))\n#define _IQ6toIQ10(A)            ((_iq10)(A) << (4))\n#define  _IQ6toIQ9(A)            ((_iq9 )(A) << (3))\n#define  _IQ6toIQ8(A)            ((_iq8 )(A) << (2))\n#define  _IQ6toIQ7(A)            ((_iq7 )(A) << (1))\n#define  _IQ6toIQ5(A)            ((_iq5 )(A) >> (1))\n#define  _IQ6toIQ4(A)            ((_iq4 )(A) >> (2))\n#define  _IQ6toIQ3(A)            ((_iq3 )(A) >> (3))\n#define  _IQ6toIQ2(A)            ((_iq2 )(A) >> (4))\n#define  _IQ6toIQ1(A)            ((_iq1 )(A) >> (5))\n\n/* IQ7 to IQN */\n#define _IQ7toIQ30(A)            ((_iq30)(A) << (23))\n#define _IQ7toIQ29(A)            ((_iq29)(A) << (22))\n#define _IQ7toIQ28(A)            ((_iq28)(A) << (21))\n#define _IQ7toIQ27(A)            ((_iq27)(A) << (20))\n#define _IQ7toIQ26(A)            ((_iq26)(A) << (19))\n#define _IQ7toIQ25(A)            ((_iq25)(A) << (18))\n#define _IQ7toIQ24(A)            ((_iq24)(A) << (17))\n#define _IQ7toIQ23(A)            ((_iq23)(A) << (16))\n#define _IQ7toIQ22(A)            ((_iq22)(A) << (15))\n#define _IQ7toIQ21(A)            ((_iq21)(A) << (14))\n#define _IQ7toIQ20(A)            ((_iq20)(A) << (13))\n#define _IQ7toIQ19(A)            ((_iq19)(A) << (12))\n#define _IQ7toIQ18(A)            ((_iq18)(A) << (11))\n#define _IQ7toIQ17(A)            ((_iq17)(A) << (10))\n#define _IQ7toIQ16(A)            ((_iq16)(A) << (9))\n#define _IQ7toIQ15(A)            ((_iq15)(A) << (8))\n#define _IQ7toIQ14(A)            ((_iq14)(A) << (7))\n#define _IQ7toIQ13(A)            ((_iq13)(A) << (6))\n#define _IQ7toIQ12(A)            ((_iq12)(A) << (5))\n#define _IQ7toIQ11(A)            ((_iq11)(A) << (4))\n#define _IQ7toIQ10(A)            ((_iq10)(A) << (3))\n#define  _IQ7toIQ9(A)            ((_iq9 )(A) << (2))\n#define  _IQ7toIQ8(A)            ((_iq8 )(A) << (1))\n#define  _IQ7toIQ6(A)            ((_iq6 )(A) >> (1))\n#define  _IQ7toIQ5(A)            ((_iq5 )(A) >> (2))\n#define  _IQ7toIQ4(A)            ((_iq4 )(A) >> (3))\n#define  _IQ7toIQ3(A)            ((_iq3 )(A) >> (4))\n#define  _IQ7toIQ2(A)            ((_iq2 )(A) >> (5))\n#define  _IQ7toIQ1(A)            ((_iq1 )(A) >> (6))\n\n/* IQ8 to IQN */\n#define _IQ8toIQ30(A)            ((_iq30)(A) << (22))\n#define _IQ8toIQ29(A)            ((_iq29)(A) << (21))\n#define _IQ8toIQ28(A)            ((_iq28)(A) << (20))\n#define _IQ8toIQ27(A)            ((_iq27)(A) << (19))\n#define _IQ8toIQ26(A)            ((_iq26)(A) << (18))\n#define _IQ8toIQ25(A)            ((_iq25)(A) << (17))\n#define _IQ8toIQ24(A)            ((_iq24)(A) << (16))\n#define _IQ8toIQ23(A)            ((_iq23)(A) << (15))\n#define _IQ8toIQ22(A)            ((_iq22)(A) << (14))\n#define _IQ8toIQ21(A)            ((_iq21)(A) << (13))\n#define _IQ8toIQ20(A)            ((_iq20)(A) << (12))\n#define _IQ8toIQ19(A)            ((_iq19)(A) << (11))\n#define _IQ8toIQ18(A)            ((_iq18)(A) << (10))\n#define _IQ8toIQ17(A)            ((_iq17)(A) << (9))\n#define _IQ8toIQ16(A)            ((_iq16)(A) << (8))\n#define _IQ8toIQ15(A)            ((_iq15)(A) << (7))\n#define _IQ8toIQ14(A)            ((_iq14)(A) << (6))\n#define _IQ8toIQ13(A)            ((_iq13)(A) << (5))\n#define _IQ8toIQ12(A)            ((_iq12)(A) << (4))\n#define _IQ8toIQ11(A)            ((_iq11)(A) << (3))\n#define _IQ8toIQ10(A)            ((_iq10)(A) << (2))\n#define  _IQ8toIQ9(A)            ((_iq9 )(A) << (1))\n#define  _IQ8toIQ7(A)            ((_iq7 )(A) >> (1))\n#define  _IQ8toIQ6(A)            ((_iq6 )(A) >> (2))\n#define  _IQ8toIQ5(A)            ((_iq5 )(A) >> (3))\n#define  _IQ8toIQ4(A)            ((_iq4 )(A) >> (4))\n#define  _IQ8toIQ3(A)            ((_iq3 )(A) >> (5))\n#define  _IQ8toIQ2(A)            ((_iq2 )(A) >> (6))\n#define  _IQ8toIQ1(A)            ((_iq1 )(A) >> (7))\n\n/* IQ9 to IQN */\n#define _IQ9toIQ30(A)            ((_iq30)(A) << (21))\n#define _IQ9toIQ29(A)            ((_iq29)(A) << (20))\n#define _IQ9toIQ28(A)            ((_iq28)(A) << (19))\n#define _IQ9toIQ27(A)            ((_iq27)(A) << (18))\n#define _IQ9toIQ26(A)            ((_iq26)(A) << (17))\n#define _IQ9toIQ25(A)            ((_iq25)(A) << (16))\n#define _IQ9toIQ24(A)            ((_iq24)(A) << (15))\n#define _IQ9toIQ23(A)            ((_iq23)(A) << (14))\n#define _IQ9toIQ22(A)            ((_iq22)(A) << (13))\n#define _IQ9toIQ21(A)            ((_iq21)(A) << (12))\n#define _IQ9toIQ20(A)            ((_iq20)(A) << (11))\n#define _IQ9toIQ19(A)            ((_iq19)(A) << (10))\n#define _IQ9toIQ18(A)            ((_iq18)(A) << (9))\n#define _IQ9toIQ17(A)            ((_iq17)(A) << (8))\n#define _IQ9toIQ16(A)            ((_iq16)(A) << (7))\n#define _IQ9toIQ15(A)            ((_iq15)(A) << (6))\n#define _IQ9toIQ14(A)            ((_iq14)(A) << (5))\n#define _IQ9toIQ13(A)            ((_iq13)(A) << (4))\n#define _IQ9toIQ12(A)            ((_iq12)(A) << (3))\n#define _IQ9toIQ11(A)            ((_iq11)(A) << (2))\n#define _IQ9toIQ10(A)            ((_iq10)(A) << (1))\n#define  _IQ9toIQ8(A)            ((_iq8 )(A) >> (1))\n#define  _IQ9toIQ7(A)            ((_iq7 )(A) >> (2))\n#define  _IQ9toIQ6(A)            ((_iq6 )(A) >> (3))\n#define  _IQ9toIQ5(A)            ((_iq5 )(A) >> (4))\n#define  _IQ9toIQ4(A)            ((_iq4 )(A) >> (5))\n#define  _IQ9toIQ3(A)            ((_iq3 )(A) >> (6))\n#define  _IQ9toIQ2(A)            ((_iq2 )(A) >> (7))\n#define  _IQ9toIQ1(A)            ((_iq1 )(A) >> (8))\n\n/* IQ10 to IQN */\n#define _IQ10toIQ30(A)            ((_iq30)(A) << (20))\n#define _IQ10toIQ29(A)            ((_iq29)(A) << (19))\n#define _IQ10toIQ28(A)            ((_iq28)(A) << (18))\n#define _IQ10toIQ27(A)            ((_iq27)(A) << (17))\n#define _IQ10toIQ26(A)            ((_iq26)(A) << (16))\n#define _IQ10toIQ25(A)            ((_iq25)(A) << (15))\n#define _IQ10toIQ24(A)            ((_iq24)(A) << (14))\n#define _IQ10toIQ23(A)            ((_iq23)(A) << (13))\n#define _IQ10toIQ22(A)            ((_iq22)(A) << (12))\n#define _IQ10toIQ21(A)            ((_iq21)(A) << (11))\n#define _IQ10toIQ20(A)            ((_iq20)(A) << (10))\n#define _IQ10toIQ19(A)            ((_iq19)(A) << (9))\n#define _IQ10toIQ18(A)            ((_iq18)(A) << (8))\n#define _IQ10toIQ17(A)            ((_iq17)(A) << (7))\n#define _IQ10toIQ16(A)            ((_iq16)(A) << (6))\n#define _IQ10toIQ15(A)            ((_iq15)(A) << (5))\n#define _IQ10toIQ14(A)            ((_iq14)(A) << (4))\n#define _IQ10toIQ13(A)            ((_iq13)(A) << (3))\n#define _IQ10toIQ12(A)            ((_iq12)(A) << (2))\n#define _IQ10toIQ11(A)            ((_iq11)(A) << (1))\n#define  _IQ10toIQ9(A)            ((_iq9 )(A) >> (1))\n#define  _IQ10toIQ8(A)            ((_iq8 )(A) >> (2))\n#define  _IQ10toIQ7(A)            ((_iq7 )(A) >> (3))\n#define  _IQ10toIQ6(A)            ((_iq6 )(A) >> (4))\n#define  _IQ10toIQ5(A)            ((_iq5 )(A) >> (5))\n#define  _IQ10toIQ4(A)            ((_iq4 )(A) >> (6))\n#define  _IQ10toIQ3(A)            ((_iq3 )(A) >> (7))\n#define  _IQ10toIQ2(A)            ((_iq2 )(A) >> (8))\n#define  _IQ10toIQ1(A)            ((_iq1 )(A) >> (9))\n\n/* IQ11 to IQN */\n#define _IQ11toIQ30(A)            ((_iq30)(A) << (19))\n#define _IQ11toIQ29(A)            ((_iq29)(A) << (18))\n#define _IQ11toIQ28(A)            ((_iq28)(A) << (17))\n#define _IQ11toIQ27(A)            ((_iq27)(A) << (16))\n#define _IQ11toIQ26(A)            ((_iq26)(A) << (15))\n#define _IQ11toIQ25(A)            ((_iq25)(A) << (14))\n#define _IQ11toIQ24(A)            ((_iq24)(A) << (13))\n#define _IQ11toIQ23(A)            ((_iq23)(A) << (12))\n#define _IQ11toIQ22(A)            ((_iq22)(A) << (11))\n#define _IQ11toIQ21(A)            ((_iq21)(A) << (10))\n#define _IQ11toIQ20(A)            ((_iq20)(A) << (9))\n#define _IQ11toIQ19(A)            ((_iq19)(A) << (8))\n#define _IQ11toIQ18(A)            ((_iq18)(A) << (7))\n#define _IQ11toIQ17(A)            ((_iq17)(A) << (6))\n#define _IQ11toIQ16(A)            ((_iq16)(A) << (5))\n#define _IQ11toIQ15(A)            ((_iq15)(A) << (4))\n#define _IQ11toIQ14(A)            ((_iq14)(A) << (3))\n#define _IQ11toIQ13(A)            ((_iq13)(A) << (2))\n#define _IQ11toIQ12(A)            ((_iq12)(A) << (1))\n#define _IQ11toIQ10(A)            ((_iq10)(A) >> (1))\n#define  _IQ11toIQ9(A)            ((_iq9 )(A) >> (2))\n#define  _IQ11toIQ8(A)            ((_iq8 )(A) >> (3))\n#define  _IQ11toIQ7(A)            ((_iq7 )(A) >> (4))\n#define  _IQ11toIQ6(A)            ((_iq6 )(A) >> (5))\n#define  _IQ11toIQ5(A)            ((_iq5 )(A) >> (6))\n#define  _IQ11toIQ4(A)            ((_iq4 )(A) >> (7))\n#define  _IQ11toIQ3(A)            ((_iq3 )(A) >> (8))\n#define  _IQ11toIQ2(A)            ((_iq2 )(A) >> (9))\n#define  _IQ11toIQ1(A)            ((_iq1 )(A) >> (10))\n\n/* IQ12 to IQN */\n#define _IQ12toIQ30(A)            ((_iq30)(A) << (18))\n#define _IQ12toIQ29(A)            ((_iq29)(A) << (17))\n#define _IQ12toIQ28(A)            ((_iq28)(A) << (16))\n#define _IQ12toIQ27(A)            ((_iq27)(A) << (15))\n#define _IQ12toIQ26(A)            ((_iq26)(A) << (14))\n#define _IQ12toIQ25(A)            ((_iq25)(A) << (13))\n#define _IQ12toIQ24(A)            ((_iq24)(A) << (12))\n#define _IQ12toIQ23(A)            ((_iq23)(A) << (11))\n#define _IQ12toIQ22(A)            ((_iq22)(A) << (10))\n#define _IQ12toIQ21(A)            ((_iq21)(A) << (9))\n#define _IQ12toIQ20(A)            ((_iq20)(A) << (8))\n#define _IQ12toIQ19(A)            ((_iq19)(A) << (7))\n#define _IQ12toIQ18(A)            ((_iq18)(A) << (6))\n#define _IQ12toIQ17(A)            ((_iq17)(A) << (5))\n#define _IQ12toIQ16(A)            ((_iq16)(A) << (4))\n#define _IQ12toIQ15(A)            ((_iq15)(A) << (3))\n#define _IQ12toIQ14(A)            ((_iq14)(A) << (2))\n#define _IQ12toIQ13(A)            ((_iq13)(A) << (1))\n#define _IQ12toIQ11(A)            ((_iq11)(A) >> (1))\n#define _IQ12toIQ10(A)            ((_iq10)(A) >> (2))\n#define  _IQ12toIQ9(A)            ((_iq9 )(A) >> (3))\n#define  _IQ12toIQ8(A)            ((_iq8 )(A) >> (4))\n#define  _IQ12toIQ7(A)            ((_iq7 )(A) >> (5))\n#define  _IQ12toIQ6(A)            ((_iq6 )(A) >> (6))\n#define  _IQ12toIQ5(A)            ((_iq5 )(A) >> (7))\n#define  _IQ12toIQ4(A)            ((_iq4 )(A) >> (8))\n#define  _IQ12toIQ3(A)            ((_iq3 )(A) >> (9))\n#define  _IQ12toIQ2(A)            ((_iq2 )(A) >> (10))\n#define  _IQ12toIQ1(A)            ((_iq1 )(A) >> (11))\n\n/* IQ13 to IQN */\n#define _IQ13toIQ30(A)            ((_iq30)(A) << (17))\n#define _IQ13toIQ29(A)            ((_iq29)(A) << (16))\n#define _IQ13toIQ28(A)            ((_iq28)(A) << (15))\n#define _IQ13toIQ27(A)            ((_iq27)(A) << (14))\n#define _IQ13toIQ26(A)            ((_iq26)(A) << (13))\n#define _IQ13toIQ25(A)            ((_iq25)(A) << (12))\n#define _IQ13toIQ24(A)            ((_iq24)(A) << (11))\n#define _IQ13toIQ23(A)            ((_iq23)(A) << (10))\n#define _IQ13toIQ22(A)            ((_iq22)(A) << (9))\n#define _IQ13toIQ21(A)            ((_iq21)(A) << (8))\n#define _IQ13toIQ20(A)            ((_iq20)(A) << (7))\n#define _IQ13toIQ19(A)            ((_iq19)(A) << (6))\n#define _IQ13toIQ18(A)            ((_iq18)(A) << (5))\n#define _IQ13toIQ17(A)            ((_iq17)(A) << (4))\n#define _IQ13toIQ16(A)            ((_iq16)(A) << (3))\n#define _IQ13toIQ15(A)            ((_iq15)(A) << (2))\n#define _IQ13toIQ14(A)            ((_iq14)(A) << (1))\n#define _IQ13toIQ12(A)            ((_iq12)(A) >> (1))\n#define _IQ13toIQ11(A)            ((_iq11)(A) >> (2))\n#define _IQ13toIQ10(A)            ((_iq10)(A) >> (3))\n#define  _IQ13toIQ9(A)            ((_iq9 )(A) >> (4))\n#define  _IQ13toIQ8(A)            ((_iq8 )(A) >> (5))\n#define  _IQ13toIQ7(A)            ((_iq7 )(A) >> (6))\n#define  _IQ13toIQ6(A)            ((_iq6 )(A) >> (7))\n#define  _IQ13toIQ5(A)            ((_iq5 )(A) >> (8))\n#define  _IQ13toIQ4(A)            ((_iq4 )(A) >> (9))\n#define  _IQ13toIQ3(A)            ((_iq3 )(A) >> (10))\n#define  _IQ13toIQ2(A)            ((_iq2 )(A) >> (11))\n#define  _IQ13toIQ1(A)            ((_iq1 )(A) >> (12))\n\n/* IQ14 to IQN */\n#define _IQ14toIQ30(A)            ((_iq30)(A) << (16))\n#define _IQ14toIQ29(A)            ((_iq29)(A) << (15))\n#define _IQ14toIQ28(A)            ((_iq28)(A) << (14))\n#define _IQ14toIQ27(A)            ((_iq27)(A) << (13))\n#define _IQ14toIQ26(A)            ((_iq26)(A) << (12))\n#define _IQ14toIQ25(A)            ((_iq25)(A) << (11))\n#define _IQ14toIQ24(A)            ((_iq24)(A) << (10))\n#define _IQ14toIQ23(A)            ((_iq23)(A) << (9))\n#define _IQ14toIQ22(A)            ((_iq22)(A) << (8))\n#define _IQ14toIQ21(A)            ((_iq21)(A) << (7))\n#define _IQ14toIQ20(A)            ((_iq20)(A) << (6))\n#define _IQ14toIQ19(A)            ((_iq19)(A) << (5))\n#define _IQ14toIQ18(A)            ((_iq18)(A) << (4))\n#define _IQ14toIQ17(A)            ((_iq17)(A) << (3))\n#define _IQ14toIQ16(A)            ((_iq16)(A) << (2))\n#define _IQ14toIQ15(A)            ((_iq15)(A) << (1))\n#define _IQ14toIQ13(A)            ((_iq13)(A) >> (1))\n#define _IQ14toIQ12(A)            ((_iq12)(A) >> (2))\n#define _IQ14toIQ11(A)            ((_iq11)(A) >> (3))\n#define _IQ14toIQ10(A)            ((_iq10)(A) >> (4))\n#define  _IQ14toIQ9(A)            ((_iq9 )(A) >> (5))\n#define  _IQ14toIQ8(A)            ((_iq8 )(A) >> (6))\n#define  _IQ14toIQ7(A)            ((_iq7 )(A) >> (7))\n#define  _IQ14toIQ6(A)            ((_iq6 )(A) >> (8))\n#define  _IQ14toIQ5(A)            ((_iq5 )(A) >> (9))\n#define  _IQ14toIQ4(A)            ((_iq4 )(A) >> (10))\n#define  _IQ14toIQ3(A)            ((_iq3 )(A) >> (11))\n#define  _IQ14toIQ2(A)            ((_iq2 )(A) >> (12))\n#define  _IQ14toIQ1(A)            ((_iq1 )(A) >> (13))\n\n/* IQ15 to IQN */\n#define _IQ15toIQ30(A)            ((_iq30)(A) << (15))\n#define _IQ15toIQ29(A)            ((_iq29)(A) << (14))\n#define _IQ15toIQ28(A)            ((_iq28)(A) << (13))\n#define _IQ15toIQ27(A)            ((_iq27)(A) << (12))\n#define _IQ15toIQ26(A)            ((_iq26)(A) << (11))\n#define _IQ15toIQ25(A)            ((_iq25)(A) << (10))\n#define _IQ15toIQ24(A)            ((_iq24)(A) << (9))\n#define _IQ15toIQ23(A)            ((_iq23)(A) << (8))\n#define _IQ15toIQ22(A)            ((_iq22)(A) << (7))\n#define _IQ15toIQ21(A)            ((_iq21)(A) << (6))\n#define _IQ15toIQ20(A)            ((_iq20)(A) << (5))\n#define _IQ15toIQ19(A)            ((_iq19)(A) << (4))\n#define _IQ15toIQ18(A)            ((_iq18)(A) << (3))\n#define _IQ15toIQ17(A)            ((_iq17)(A) << (2))\n#define _IQ15toIQ16(A)            ((_iq16)(A) << (1))\n#define _IQ15toIQ14(A)            ((_iq14)(A) >> (1))\n#define _IQ15toIQ13(A)            ((_iq13)(A) >> (2))\n#define _IQ15toIQ12(A)            ((_iq12)(A) >> (3))\n#define _IQ15toIQ11(A)            ((_iq11)(A) >> (4))\n#define _IQ15toIQ10(A)            ((_iq10)(A) >> (5))\n#define  _IQ15toIQ9(A)            ((_iq9 )(A) >> (6))\n#define  _IQ15toIQ8(A)            ((_iq8 )(A) >> (7))\n#define  _IQ15toIQ7(A)            ((_iq7 )(A) >> (8))\n#define  _IQ15toIQ6(A)            ((_iq6 )(A) >> (9))\n#define  _IQ15toIQ5(A)            ((_iq5 )(A) >> (10))\n#define  _IQ15toIQ4(A)            ((_iq4 )(A) >> (11))\n#define  _IQ15toIQ3(A)            ((_iq3 )(A) >> (12))\n#define  _IQ15toIQ2(A)            ((_iq2 )(A) >> (13))\n#define  _IQ15toIQ1(A)            ((_iq1 )(A) >> (14))\n\n/* IQ16 to IQN */\n#define _IQ16toIQ30(A)            ((_iq30)(A) << (14))\n#define _IQ16toIQ29(A)            ((_iq29)(A) << (13))\n#define _IQ16toIQ28(A)            ((_iq28)(A) << (12))\n#define _IQ16toIQ27(A)            ((_iq27)(A) << (11))\n#define _IQ16toIQ26(A)            ((_iq26)(A) << (10))\n#define _IQ16toIQ25(A)            ((_iq25)(A) << (9))\n#define _IQ16toIQ24(A)            ((_iq24)(A) << (8))\n#define _IQ16toIQ23(A)            ((_iq23)(A) << (7))\n#define _IQ16toIQ22(A)            ((_iq22)(A) << (6))\n#define _IQ16toIQ21(A)            ((_iq21)(A) << (5))\n#define _IQ16toIQ20(A)            ((_iq20)(A) << (4))\n#define _IQ16toIQ19(A)            ((_iq19)(A) << (3))\n#define _IQ16toIQ18(A)            ((_iq18)(A) << (2))\n#define _IQ16toIQ17(A)            ((_iq17)(A) << (1))\n#define _IQ16toIQ15(A)            ((_iq15)(A) >> (1))\n#define _IQ16toIQ14(A)            ((_iq14)(A) >> (2))\n#define _IQ16toIQ13(A)            ((_iq13)(A) >> (3))\n#define _IQ16toIQ12(A)            ((_iq12)(A) >> (4))\n#define _IQ16toIQ11(A)            ((_iq11)(A) >> (5))\n#define _IQ16toIQ10(A)            ((_iq10)(A) >> (6))\n#define  _IQ16toIQ9(A)            ((_iq9 )(A) >> (7))\n#define  _IQ16toIQ8(A)            ((_iq8 )(A) >> (8))\n#define  _IQ16toIQ7(A)            ((_iq7 )(A) >> (9))\n#define  _IQ16toIQ6(A)            ((_iq6 )(A) >> (10))\n#define  _IQ16toIQ5(A)            ((_iq5 )(A) >> (11))\n#define  _IQ16toIQ4(A)            ((_iq4 )(A) >> (12))\n#define  _IQ16toIQ3(A)            ((_iq3 )(A) >> (13))\n#define  _IQ16toIQ2(A)            ((_iq2 )(A) >> (14))\n#define  _IQ16toIQ1(A)            ((_iq1 )(A) >> (15))\n\n/* IQ17 to IQN */\n#define _IQ17toIQ30(A)            ((_iq30)(A) << (13))\n#define _IQ17toIQ29(A)            ((_iq29)(A) << (12))\n#define _IQ17toIQ28(A)            ((_iq28)(A) << (11))\n#define _IQ17toIQ27(A)            ((_iq27)(A) << (10))\n#define _IQ17toIQ26(A)            ((_iq26)(A) << (9))\n#define _IQ17toIQ25(A)            ((_iq25)(A) << (8))\n#define _IQ17toIQ24(A)            ((_iq24)(A) << (7))\n#define _IQ17toIQ23(A)            ((_iq23)(A) << (6))\n#define _IQ17toIQ22(A)            ((_iq22)(A) << (5))\n#define _IQ17toIQ21(A)            ((_iq21)(A) << (4))\n#define _IQ17toIQ20(A)            ((_iq20)(A) << (3))\n#define _IQ17toIQ19(A)            ((_iq19)(A) << (2))\n#define _IQ17toIQ18(A)            ((_iq18)(A) << (1))\n#define _IQ17toIQ16(A)            ((_iq16)(A) >> (1))\n#define _IQ17toIQ15(A)            ((_iq15)(A) >> (2))\n#define _IQ17toIQ14(A)            ((_iq14)(A) >> (3))\n#define _IQ17toIQ13(A)            ((_iq13)(A) >> (4))\n#define _IQ17toIQ12(A)            ((_iq12)(A) >> (5))\n#define _IQ17toIQ11(A)            ((_iq11)(A) >> (6))\n#define _IQ17toIQ10(A)            ((_iq10)(A) >> (7))\n#define  _IQ17toIQ9(A)            ((_iq9 )(A) >> (8))\n#define  _IQ17toIQ8(A)            ((_iq8 )(A) >> (9))\n#define  _IQ17toIQ7(A)            ((_iq7 )(A) >> (10))\n#define  _IQ17toIQ6(A)            ((_iq6 )(A) >> (11))\n#define  _IQ17toIQ5(A)            ((_iq5 )(A) >> (12))\n#define  _IQ17toIQ4(A)            ((_iq4 )(A) >> (13))\n#define  _IQ17toIQ3(A)            ((_iq3 )(A) >> (14))\n#define  _IQ17toIQ2(A)            ((_iq2 )(A) >> (15))\n#define  _IQ17toIQ1(A)            ((_iq1 )(A) >> (16))\n\n/* IQ18 to IQN */\n#define _IQ18toIQ30(A)            ((_iq30)(A) << (12))\n#define _IQ18toIQ29(A)            ((_iq29)(A) << (11))\n#define _IQ18toIQ28(A)            ((_iq28)(A) << (10))\n#define _IQ18toIQ27(A)            ((_iq27)(A) << (9))\n#define _IQ18toIQ26(A)            ((_iq26)(A) << (8))\n#define _IQ18toIQ25(A)            ((_iq25)(A) << (7))\n#define _IQ18toIQ24(A)            ((_iq24)(A) << (6))\n#define _IQ18toIQ23(A)            ((_iq23)(A) << (5))\n#define _IQ18toIQ22(A)            ((_iq22)(A) << (4))\n#define _IQ18toIQ21(A)            ((_iq21)(A) << (3))\n#define _IQ18toIQ20(A)            ((_iq20)(A) << (2))\n#define _IQ18toIQ19(A)            ((_iq19)(A) << (1))\n#define _IQ18toIQ17(A)            ((_iq17)(A) >> (1))\n#define _IQ18toIQ16(A)            ((_iq16)(A) >> (2))\n#define _IQ18toIQ15(A)            ((_iq15)(A) >> (3))\n#define _IQ18toIQ14(A)            ((_iq14)(A) >> (4))\n#define _IQ18toIQ13(A)            ((_iq13)(A) >> (5))\n#define _IQ18toIQ12(A)            ((_iq12)(A) >> (6))\n#define _IQ18toIQ11(A)            ((_iq11)(A) >> (7))\n#define _IQ18toIQ10(A)            ((_iq10)(A) >> (8))\n#define  _IQ18toIQ9(A)            ((_iq9 )(A) >> (9))\n#define  _IQ18toIQ8(A)            ((_iq8 )(A) >> (10))\n#define  _IQ18toIQ7(A)            ((_iq7 )(A) >> (11))\n#define  _IQ18toIQ6(A)            ((_iq6 )(A) >> (12))\n#define  _IQ18toIQ5(A)            ((_iq5 )(A) >> (13))\n#define  _IQ18toIQ4(A)            ((_iq4 )(A) >> (14))\n#define  _IQ18toIQ3(A)            ((_iq3 )(A) >> (15))\n#define  _IQ18toIQ2(A)            ((_iq2 )(A) >> (16))\n#define  _IQ18toIQ1(A)            ((_iq1 )(A) >> (17))\n\n/* IQ19 to IQN */\n#define _IQ19toIQ30(A)            ((_iq30)(A) << (11))\n#define _IQ19toIQ29(A)            ((_iq29)(A) << (10))\n#define _IQ19toIQ28(A)            ((_iq28)(A) << (9))\n#define _IQ19toIQ27(A)            ((_iq27)(A) << (8))\n#define _IQ19toIQ26(A)            ((_iq26)(A) << (7))\n#define _IQ19toIQ25(A)            ((_iq25)(A) << (6))\n#define _IQ19toIQ24(A)            ((_iq24)(A) << (5))\n#define _IQ19toIQ23(A)            ((_iq23)(A) << (4))\n#define _IQ19toIQ22(A)            ((_iq22)(A) << (3))\n#define _IQ19toIQ21(A)            ((_iq21)(A) << (2))\n#define _IQ19toIQ20(A)            ((_iq20)(A) << (1))\n#define _IQ19toIQ18(A)            ((_iq18)(A) >> (1))\n#define _IQ19toIQ17(A)            ((_iq17)(A) >> (2))\n#define _IQ19toIQ16(A)            ((_iq16)(A) >> (3))\n#define _IQ19toIQ15(A)            ((_iq15)(A) >> (4))\n#define _IQ19toIQ14(A)            ((_iq14)(A) >> (5))\n#define _IQ19toIQ13(A)            ((_iq13)(A) >> (6))\n#define _IQ19toIQ12(A)            ((_iq12)(A) >> (7))\n#define _IQ19toIQ11(A)            ((_iq11)(A) >> (8))\n#define _IQ19toIQ10(A)            ((_iq10)(A) >> (9))\n#define  _IQ19toIQ9(A)            ((_iq9 )(A) >> (10))\n#define  _IQ19toIQ8(A)            ((_iq8 )(A) >> (11))\n#define  _IQ19toIQ7(A)            ((_iq7 )(A) >> (12))\n#define  _IQ19toIQ6(A)            ((_iq6 )(A) >> (13))\n#define  _IQ19toIQ5(A)            ((_iq5 )(A) >> (14))\n#define  _IQ19toIQ4(A)            ((_iq4 )(A) >> (15))\n#define  _IQ19toIQ3(A)            ((_iq3 )(A) >> (16))\n#define  _IQ19toIQ2(A)            ((_iq2 )(A) >> (17))\n#define  _IQ19toIQ1(A)            ((_iq1 )(A) >> (18))\n\n/* IQ20 to IQN */\n#define _IQ20toIQ30(A)            ((_iq30)(A) << (10))\n#define _IQ20toIQ29(A)            ((_iq29)(A) << (9))\n#define _IQ20toIQ28(A)            ((_iq28)(A) << (8))\n#define _IQ20toIQ27(A)            ((_iq27)(A) << (7))\n#define _IQ20toIQ26(A)            ((_iq26)(A) << (6))\n#define _IQ20toIQ25(A)            ((_iq25)(A) << (5))\n#define _IQ20toIQ24(A)            ((_iq24)(A) << (4))\n#define _IQ20toIQ23(A)            ((_iq23)(A) << (3))\n#define _IQ20toIQ22(A)            ((_iq22)(A) << (2))\n#define _IQ20toIQ21(A)            ((_iq21)(A) << (1))\n#define _IQ20toIQ19(A)            ((_iq19)(A) >> (1))\n#define _IQ20toIQ18(A)            ((_iq18)(A) >> (2))\n#define _IQ20toIQ17(A)            ((_iq17)(A) >> (3))\n#define _IQ20toIQ16(A)            ((_iq16)(A) >> (4))\n#define _IQ20toIQ15(A)            ((_iq15)(A) >> (5))\n#define _IQ20toIQ14(A)            ((_iq14)(A) >> (6))\n#define _IQ20toIQ13(A)            ((_iq13)(A) >> (7))\n#define _IQ20toIQ12(A)            ((_iq12)(A) >> (8))\n#define _IQ20toIQ11(A)            ((_iq11)(A) >> (9))\n#define _IQ20toIQ10(A)            ((_iq10)(A) >> (10))\n#define  _IQ20toIQ9(A)            ((_iq9 )(A) >> (11))\n#define  _IQ20toIQ8(A)            ((_iq8 )(A) >> (12))\n#define  _IQ20toIQ7(A)            ((_iq7 )(A) >> (13))\n#define  _IQ20toIQ6(A)            ((_iq6 )(A) >> (14))\n#define  _IQ20toIQ5(A)            ((_iq5 )(A) >> (15))\n#define  _IQ20toIQ4(A)            ((_iq4 )(A) >> (16))\n#define  _IQ20toIQ3(A)            ((_iq3 )(A) >> (17))\n#define  _IQ20toIQ2(A)            ((_iq2 )(A) >> (18))\n#define  _IQ20toIQ1(A)            ((_iq1 )(A) >> (19))\n\n/* IQ21 to IQN */\n#define _IQ21toIQ30(A)            ((_iq30)(A) << (9))\n#define _IQ21toIQ29(A)            ((_iq29)(A) << (8))\n#define _IQ21toIQ28(A)            ((_iq28)(A) << (7))\n#define _IQ21toIQ27(A)            ((_iq27)(A) << (6))\n#define _IQ21toIQ26(A)            ((_iq26)(A) << (5))\n#define _IQ21toIQ25(A)            ((_iq25)(A) << (4))\n#define _IQ21toIQ24(A)            ((_iq24)(A) << (3))\n#define _IQ21toIQ23(A)            ((_iq23)(A) << (2))\n#define _IQ21toIQ22(A)            ((_iq22)(A) << (1))\n#define _IQ21toIQ20(A)            ((_iq20)(A) >> (1))\n#define _IQ21toIQ19(A)            ((_iq19)(A) >> (2))\n#define _IQ21toIQ18(A)            ((_iq18)(A) >> (3))\n#define _IQ21toIQ17(A)            ((_iq17)(A) >> (4))\n#define _IQ21toIQ16(A)            ((_iq16)(A) >> (5))\n#define _IQ21toIQ15(A)            ((_iq15)(A) >> (6))\n#define _IQ21toIQ14(A)            ((_iq14)(A) >> (7))\n#define _IQ21toIQ13(A)            ((_iq13)(A) >> (8))\n#define _IQ21toIQ12(A)            ((_iq12)(A) >> (9))\n#define _IQ21toIQ11(A)            ((_iq11)(A) >> (10))\n#define _IQ21toIQ10(A)            ((_iq10)(A) >> (11))\n#define  _IQ21toIQ9(A)            ((_iq9 )(A) >> (12))\n#define  _IQ21toIQ8(A)            ((_iq8 )(A) >> (13))\n#define  _IQ21toIQ7(A)            ((_iq7 )(A) >> (14))\n#define  _IQ21toIQ6(A)            ((_iq6 )(A) >> (15))\n#define  _IQ21toIQ5(A)            ((_iq5 )(A) >> (16))\n#define  _IQ21toIQ4(A)            ((_iq4 )(A) >> (17))\n#define  _IQ21toIQ3(A)            ((_iq3 )(A) >> (18))\n#define  _IQ21toIQ2(A)            ((_iq2 )(A) >> (19))\n#define  _IQ21toIQ1(A)            ((_iq1 )(A) >> (20))\n\n/* IQ22 to IQN */\n#define _IQ22toIQ30(A)            ((_iq30)(A) << (8))\n#define _IQ22toIQ29(A)            ((_iq29)(A) << (7))\n#define _IQ22toIQ28(A)            ((_iq28)(A) << (6))\n#define _IQ22toIQ27(A)            ((_iq27)(A) << (5))\n#define _IQ22toIQ26(A)            ((_iq26)(A) << (4))\n#define _IQ22toIQ25(A)            ((_iq25)(A) << (3))\n#define _IQ22toIQ24(A)            ((_iq24)(A) << (2))\n#define _IQ22toIQ23(A)            ((_iq23)(A) << (1))\n#define _IQ22toIQ21(A)            ((_iq21)(A) >> (1))\n#define _IQ22toIQ20(A)            ((_iq20)(A) >> (2))\n#define _IQ22toIQ19(A)            ((_iq19)(A) >> (3))\n#define _IQ22toIQ18(A)            ((_iq18)(A) >> (4))\n#define _IQ22toIQ17(A)            ((_iq17)(A) >> (5))\n#define _IQ22toIQ16(A)            ((_iq16)(A) >> (6))\n#define _IQ22toIQ15(A)            ((_iq15)(A) >> (7))\n#define _IQ22toIQ14(A)            ((_iq14)(A) >> (8))\n#define _IQ22toIQ13(A)            ((_iq13)(A) >> (9))\n#define _IQ22toIQ12(A)            ((_iq12)(A) >> (10))\n#define _IQ22toIQ11(A)            ((_iq11)(A) >> (11))\n#define _IQ22toIQ10(A)            ((_iq10)(A) >> (12))\n#define  _IQ22toIQ9(A)            ((_iq9 )(A) >> (13))\n#define  _IQ22toIQ8(A)            ((_iq8 )(A) >> (14))\n#define  _IQ22toIQ7(A)            ((_iq7 )(A) >> (15))\n#define  _IQ22toIQ6(A)            ((_iq6 )(A) >> (16))\n#define  _IQ22toIQ5(A)            ((_iq5 )(A) >> (17))\n#define  _IQ22toIQ4(A)            ((_iq4 )(A) >> (18))\n#define  _IQ22toIQ3(A)            ((_iq3 )(A) >> (19))\n#define  _IQ22toIQ2(A)            ((_iq2 )(A) >> (20))\n#define  _IQ22toIQ1(A)            ((_iq1 )(A) >> (21))\n\n/* IQ23 to IQN */\n#define _IQ23toIQ30(A)            ((_iq30)(A) << (7))\n#define _IQ23toIQ29(A)            ((_iq29)(A) << (6))\n#define _IQ23toIQ28(A)            ((_iq28)(A) << (5))\n#define _IQ23toIQ27(A)            ((_iq27)(A) << (4))\n#define _IQ23toIQ26(A)            ((_iq26)(A) << (3))\n#define _IQ23toIQ25(A)            ((_iq25)(A) << (2))\n#define _IQ23toIQ24(A)            ((_iq24)(A) << (1))\n#define _IQ23toIQ22(A)            ((_iq22)(A) >> (1))\n#define _IQ23toIQ21(A)            ((_iq21)(A) >> (2))\n#define _IQ23toIQ20(A)            ((_iq20)(A) >> (3))\n#define _IQ23toIQ19(A)            ((_iq19)(A) >> (4))\n#define _IQ23toIQ18(A)            ((_iq18)(A) >> (5))\n#define _IQ23toIQ17(A)            ((_iq17)(A) >> (6))\n#define _IQ23toIQ16(A)            ((_iq16)(A) >> (7))\n#define _IQ23toIQ15(A)            ((_iq15)(A) >> (8))\n#define _IQ23toIQ14(A)            ((_iq14)(A) >> (9))\n#define _IQ23toIQ13(A)            ((_iq13)(A) >> (10))\n#define _IQ23toIQ12(A)            ((_iq12)(A) >> (11))\n#define _IQ23toIQ11(A)            ((_iq11)(A) >> (12))\n#define _IQ23toIQ10(A)            ((_iq10)(A) >> (13))\n#define  _IQ23toIQ9(A)            ((_iq9 )(A) >> (14))\n#define  _IQ23toIQ8(A)            ((_iq8 )(A) >> (15))\n#define  _IQ23toIQ7(A)            ((_iq7 )(A) >> (16))\n#define  _IQ23toIQ6(A)            ((_iq6 )(A) >> (17))\n#define  _IQ23toIQ5(A)            ((_iq5 )(A) >> (18))\n#define  _IQ23toIQ4(A)            ((_iq4 )(A) >> (19))\n#define  _IQ23toIQ3(A)            ((_iq3 )(A) >> (20))\n#define  _IQ23toIQ2(A)            ((_iq2 )(A) >> (21))\n#define  _IQ23toIQ1(A)            ((_iq1 )(A) >> (22))\n\n/* IQ24 to IQN */\n#define _IQ24toIQ30(A)            ((_iq30)(A) << (6))\n#define _IQ24toIQ29(A)            ((_iq29)(A) << (5))\n#define _IQ24toIQ28(A)            ((_iq28)(A) << (4))\n#define _IQ24toIQ27(A)            ((_iq27)(A) << (3))\n#define _IQ24toIQ26(A)            ((_iq26)(A) << (2))\n#define _IQ24toIQ25(A)            ((_iq25)(A) << (1))\n#define _IQ24toIQ23(A)            ((_iq23)(A) >> (1))\n#define _IQ24toIQ22(A)            ((_iq22)(A) >> (2))\n#define _IQ24toIQ21(A)            ((_iq21)(A) >> (3))\n#define _IQ24toIQ20(A)            ((_iq20)(A) >> (4))\n#define _IQ24toIQ19(A)            ((_iq19)(A) >> (5))\n#define _IQ24toIQ18(A)            ((_iq18)(A) >> (6))\n#define _IQ24toIQ17(A)            ((_iq17)(A) >> (7))\n#define _IQ24toIQ16(A)            ((_iq16)(A) >> (8))\n#define _IQ24toIQ15(A)            ((_iq15)(A) >> (9))\n#define _IQ24toIQ14(A)            ((_iq14)(A) >> (10))\n#define _IQ24toIQ13(A)            ((_iq13)(A) >> (11))\n#define _IQ24toIQ12(A)            ((_iq12)(A) >> (12))\n#define _IQ24toIQ11(A)            ((_iq11)(A) >> (13))\n#define _IQ24toIQ10(A)            ((_iq10)(A) >> (14))\n#define  _IQ24toIQ9(A)            ((_iq9 )(A) >> (15))\n#define  _IQ24toIQ8(A)            ((_iq8 )(A) >> (16))\n#define  _IQ24toIQ7(A)            ((_iq7 )(A) >> (17))\n#define  _IQ24toIQ6(A)            ((_iq6 )(A) >> (18))\n#define  _IQ24toIQ5(A)            ((_iq5 )(A) >> (19))\n#define  _IQ24toIQ4(A)            ((_iq4 )(A) >> (20))\n#define  _IQ24toIQ3(A)            ((_iq3 )(A) >> (21))\n#define  _IQ24toIQ2(A)            ((_iq2 )(A) >> (22))\n#define  _IQ24toIQ1(A)            ((_iq1 )(A) >> (23))\n\n/* IQ25 to IQN */\n#define _IQ25toIQ30(A)            ((_iq30)(A) << (5))\n#define _IQ25toIQ29(A)            ((_iq29)(A) << (4))\n#define _IQ25toIQ28(A)            ((_iq28)(A) << (3))\n#define _IQ25toIQ27(A)            ((_iq27)(A) << (2))\n#define _IQ25toIQ26(A)            ((_iq26)(A) << (1))\n#define _IQ25toIQ24(A)            ((_iq24)(A) >> (1))\n#define _IQ25toIQ23(A)            ((_iq23)(A) >> (2))\n#define _IQ25toIQ22(A)            ((_iq22)(A) >> (3))\n#define _IQ25toIQ21(A)            ((_iq21)(A) >> (4))\n#define _IQ25toIQ20(A)            ((_iq20)(A) >> (5))\n#define _IQ25toIQ19(A)            ((_iq19)(A) >> (6))\n#define _IQ25toIQ18(A)            ((_iq18)(A) >> (7))\n#define _IQ25toIQ17(A)            ((_iq17)(A) >> (8))\n#define _IQ25toIQ16(A)            ((_iq16)(A) >> (9))\n#define _IQ25toIQ15(A)            ((_iq15)(A) >> (10))\n#define _IQ25toIQ14(A)            ((_iq14)(A) >> (11))\n#define _IQ25toIQ13(A)            ((_iq13)(A) >> (12))\n#define _IQ25toIQ12(A)            ((_iq12)(A) >> (13))\n#define _IQ25toIQ11(A)            ((_iq11)(A) >> (14))\n#define _IQ25toIQ10(A)            ((_iq10)(A) >> (15))\n#define  _IQ25toIQ9(A)            ((_iq9 )(A) >> (16))\n#define  _IQ25toIQ8(A)            ((_iq8 )(A) >> (17))\n#define  _IQ25toIQ7(A)            ((_iq7 )(A) >> (18))\n#define  _IQ25toIQ6(A)            ((_iq6 )(A) >> (19))\n#define  _IQ25toIQ5(A)            ((_iq5 )(A) >> (20))\n#define  _IQ25toIQ4(A)            ((_iq4 )(A) >> (21))\n#define  _IQ25toIQ3(A)            ((_iq3 )(A) >> (22))\n#define  _IQ25toIQ2(A)            ((_iq2 )(A) >> (23))\n#define  _IQ25toIQ1(A)            ((_iq1 )(A) >> (24))\n\n/* IQ26 to IQN */\n#define _IQ26toIQ30(A)            ((_iq30)(A) << (4))\n#define _IQ26toIQ29(A)            ((_iq29)(A) << (3))\n#define _IQ26toIQ28(A)            ((_iq28)(A) << (2))\n#define _IQ26toIQ27(A)            ((_iq27)(A) << (1))\n#define _IQ26toIQ25(A)            ((_iq25)(A) >> (1))\n#define _IQ26toIQ24(A)            ((_iq24)(A) >> (2))\n#define _IQ26toIQ23(A)            ((_iq23)(A) >> (3))\n#define _IQ26toIQ22(A)            ((_iq22)(A) >> (4))\n#define _IQ26toIQ21(A)            ((_iq21)(A) >> (5))\n#define _IQ26toIQ20(A)            ((_iq20)(A) >> (6))\n#define _IQ26toIQ19(A)            ((_iq19)(A) >> (7))\n#define _IQ26toIQ18(A)            ((_iq18)(A) >> (8))\n#define _IQ26toIQ17(A)            ((_iq17)(A) >> (9))\n#define _IQ26toIQ16(A)            ((_iq16)(A) >> (10))\n#define _IQ26toIQ15(A)            ((_iq15)(A) >> (11))\n#define _IQ26toIQ14(A)            ((_iq14)(A) >> (12))\n#define _IQ26toIQ13(A)            ((_iq13)(A) >> (13))\n#define _IQ26toIQ12(A)            ((_iq12)(A) >> (14))\n#define _IQ26toIQ11(A)            ((_iq11)(A) >> (15))\n#define _IQ26toIQ10(A)            ((_iq10)(A) >> (16))\n#define  _IQ26toIQ9(A)            ((_iq9 )(A) >> (17))\n#define  _IQ26toIQ8(A)            ((_iq8 )(A) >> (18))\n#define  _IQ26toIQ7(A)            ((_iq7 )(A) >> (19))\n#define  _IQ26toIQ6(A)            ((_iq6 )(A) >> (20))\n#define  _IQ26toIQ5(A)            ((_iq5 )(A) >> (21))\n#define  _IQ26toIQ4(A)            ((_iq4 )(A) >> (22))\n#define  _IQ26toIQ3(A)            ((_iq3 )(A) >> (23))\n#define  _IQ26toIQ2(A)            ((_iq2 )(A) >> (24))\n#define  _IQ26toIQ1(A)            ((_iq1 )(A) >> (25))\n\n/* IQ27 to IQN */\n#define _IQ27toIQ30(A)            ((_iq30)(A) << (3))\n#define _IQ27toIQ29(A)            ((_iq29)(A) << (2))\n#define _IQ27toIQ28(A)            ((_iq28)(A) << (1))\n#define _IQ27toIQ26(A)            ((_iq26)(A) >> (1))\n#define _IQ27toIQ25(A)            ((_iq25)(A) >> (2))\n#define _IQ27toIQ24(A)            ((_iq24)(A) >> (3))\n#define _IQ27toIQ23(A)            ((_iq23)(A) >> (4))\n#define _IQ27toIQ22(A)            ((_iq22)(A) >> (5))\n#define _IQ27toIQ21(A)            ((_iq21)(A) >> (6))\n#define _IQ27toIQ20(A)            ((_iq20)(A) >> (7))\n#define _IQ27toIQ19(A)            ((_iq19)(A) >> (8))\n#define _IQ27toIQ18(A)            ((_iq18)(A) >> (9))\n#define _IQ27toIQ17(A)            ((_iq17)(A) >> (10))\n#define _IQ27toIQ16(A)            ((_iq16)(A) >> (11))\n#define _IQ27toIQ15(A)            ((_iq15)(A) >> (12))\n#define _IQ27toIQ14(A)            ((_iq14)(A) >> (13))\n#define _IQ27toIQ13(A)            ((_iq13)(A) >> (14))\n#define _IQ27toIQ12(A)            ((_iq12)(A) >> (15))\n#define _IQ27toIQ11(A)            ((_iq11)(A) >> (16))\n#define _IQ27toIQ10(A)            ((_iq10)(A) >> (17))\n#define  _IQ27toIQ9(A)            ((_iq9 )(A) >> (18))\n#define  _IQ27toIQ8(A)            ((_iq8 )(A) >> (19))\n#define  _IQ27toIQ7(A)            ((_iq7 )(A) >> (20))\n#define  _IQ27toIQ6(A)            ((_iq6 )(A) >> (21))\n#define  _IQ27toIQ5(A)            ((_iq5 )(A) >> (22))\n#define  _IQ27toIQ4(A)            ((_iq4 )(A) >> (23))\n#define  _IQ27toIQ3(A)            ((_iq3 )(A) >> (24))\n#define  _IQ27toIQ2(A)            ((_iq2 )(A) >> (25))\n#define  _IQ27toIQ1(A)            ((_iq1 )(A) >> (26))\n\n/* IQ28 to IQN */\n#define _IQ28toIQ30(A)            ((_iq30)(A) << (2))\n#define _IQ28toIQ29(A)            ((_iq29)(A) << (1))\n#define _IQ28toIQ27(A)            ((_iq27)(A) >> (1))\n#define _IQ28toIQ26(A)            ((_iq26)(A) >> (2))\n#define _IQ28toIQ25(A)            ((_iq25)(A) >> (3))\n#define _IQ28toIQ24(A)            ((_iq24)(A) >> (4))\n#define _IQ28toIQ23(A)            ((_iq23)(A) >> (5))\n#define _IQ28toIQ22(A)            ((_iq22)(A) >> (6))\n#define _IQ28toIQ21(A)            ((_iq21)(A) >> (7))\n#define _IQ28toIQ20(A)            ((_iq20)(A) >> (8))\n#define _IQ28toIQ19(A)            ((_iq19)(A) >> (9))\n#define _IQ28toIQ18(A)            ((_iq18)(A) >> (10))\n#define _IQ28toIQ17(A)            ((_iq17)(A) >> (11))\n#define _IQ28toIQ16(A)            ((_iq16)(A) >> (12))\n#define _IQ28toIQ15(A)            ((_iq15)(A) >> (13))\n#define _IQ28toIQ14(A)            ((_iq14)(A) >> (14))\n#define _IQ28toIQ13(A)            ((_iq13)(A) >> (15))\n#define _IQ28toIQ12(A)            ((_iq12)(A) >> (16))\n#define _IQ28toIQ11(A)            ((_iq11)(A) >> (17))\n#define _IQ28toIQ10(A)            ((_iq10)(A) >> (18))\n#define  _IQ28toIQ9(A)            ((_iq9 )(A) >> (19))\n#define  _IQ28toIQ8(A)            ((_iq8 )(A) >> (20))\n#define  _IQ28toIQ7(A)            ((_iq7 )(A) >> (21))\n#define  _IQ28toIQ6(A)            ((_iq6 )(A) >> (22))\n#define  _IQ28toIQ5(A)            ((_iq5 )(A) >> (23))\n#define  _IQ28toIQ4(A)            ((_iq4 )(A) >> (24))\n#define  _IQ28toIQ3(A)            ((_iq3 )(A) >> (25))\n#define  _IQ28toIQ2(A)            ((_iq2 )(A) >> (26))\n#define  _IQ28toIQ1(A)            ((_iq1 )(A) >> (27))\n\n/* IQ29 to IQN */\n#define _IQ29toIQ30(A)            ((_iq30)(A) << (1))\n#define _IQ29toIQ28(A)            ((_iq28)(A) >> (1))\n#define _IQ29toIQ27(A)            ((_iq27)(A) >> (2))\n#define _IQ29toIQ26(A)            ((_iq26)(A) >> (3))\n#define _IQ29toIQ25(A)            ((_iq25)(A) >> (4))\n#define _IQ29toIQ24(A)            ((_iq24)(A) >> (5))\n#define _IQ29toIQ23(A)            ((_iq23)(A) >> (6))\n#define _IQ29toIQ22(A)            ((_iq22)(A) >> (7))\n#define _IQ29toIQ21(A)            ((_iq21)(A) >> (8))\n#define _IQ29toIQ20(A)            ((_iq20)(A) >> (9))\n#define _IQ29toIQ19(A)            ((_iq19)(A) >> (10))\n#define _IQ29toIQ18(A)            ((_iq18)(A) >> (11))\n#define _IQ29toIQ17(A)            ((_iq17)(A) >> (12))\n#define _IQ29toIQ16(A)            ((_iq16)(A) >> (13))\n#define _IQ29toIQ15(A)            ((_iq15)(A) >> (14))\n#define _IQ29toIQ14(A)            ((_iq14)(A) >> (15))\n#define _IQ29toIQ13(A)            ((_iq13)(A) >> (16))\n#define _IQ29toIQ12(A)            ((_iq12)(A) >> (17))\n#define _IQ29toIQ11(A)            ((_iq11)(A) >> (18))\n#define _IQ29toIQ10(A)            ((_iq10)(A) >> (19))\n#define  _IQ29toIQ9(A)            ((_iq9 )(A) >> (20))\n#define  _IQ29toIQ8(A)            ((_iq8 )(A) >> (21))\n#define  _IQ29toIQ7(A)            ((_iq7 )(A) >> (22))\n#define  _IQ29toIQ6(A)            ((_iq6 )(A) >> (23))\n#define  _IQ29toIQ5(A)            ((_iq5 )(A) >> (24))\n#define  _IQ29toIQ4(A)            ((_iq4 )(A) >> (25))\n#define  _IQ29toIQ3(A)            ((_iq3 )(A) >> (26))\n#define  _IQ29toIQ2(A)            ((_iq2 )(A) >> (27))\n#define  _IQ29toIQ1(A)            ((_iq1 )(A) >> (28))\n\n/* IQ30 to IQN */\n#define _IQ30toIQ29(A)            ((_iq29)(A) >> (1))\n#define _IQ30toIQ28(A)            ((_iq28)(A) >> (2))\n#define _IQ30toIQ27(A)            ((_iq27)(A) >> (3))\n#define _IQ30toIQ26(A)            ((_iq26)(A) >> (4))\n#define _IQ30toIQ25(A)            ((_iq25)(A) >> (5))\n#define _IQ30toIQ24(A)            ((_iq24)(A) >> (6))\n#define _IQ30toIQ23(A)            ((_iq23)(A) >> (7))\n#define _IQ30toIQ22(A)            ((_iq22)(A) >> (8))\n#define _IQ30toIQ21(A)            ((_iq21)(A) >> (9))\n#define _IQ30toIQ20(A)            ((_iq20)(A) >> (10))\n#define _IQ30toIQ19(A)            ((_iq19)(A) >> (11))\n#define _IQ30toIQ18(A)            ((_iq18)(A) >> (12))\n#define _IQ30toIQ17(A)            ((_iq17)(A) >> (13))\n#define _IQ30toIQ16(A)            ((_iq16)(A) >> (14))\n#define _IQ30toIQ15(A)            ((_iq15)(A) >> (15))\n#define _IQ30toIQ14(A)            ((_iq14)(A) >> (16))\n#define _IQ30toIQ13(A)            ((_iq13)(A) >> (17))\n#define _IQ30toIQ12(A)            ((_iq12)(A) >> (18))\n#define _IQ30toIQ11(A)            ((_iq11)(A) >> (19))\n#define _IQ30toIQ10(A)            ((_iq10)(A) >> (20))\n#define  _IQ30toIQ9(A)            ((_iq9 )(A) >> (21))\n#define  _IQ30toIQ8(A)            ((_iq8 )(A) >> (22))\n#define  _IQ30toIQ7(A)            ((_iq7 )(A) >> (23))\n#define  _IQ30toIQ6(A)            ((_iq6 )(A) >> (24))\n#define  _IQ30toIQ5(A)            ((_iq5 )(A) >> (25))\n#define  _IQ30toIQ4(A)            ((_iq4 )(A) >> (26))\n#define  _IQ30toIQ3(A)            ((_iq3 )(A) >> (27))\n#define  _IQ30toIQ2(A)            ((_iq2 )(A) >> (28))\n#define  _IQ30toIQ1(A)            ((_iq1 )(A) >> (29))\n\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\n//*****************************************************************************\n//\n// Converts a number between IQ format and 16-bit Qn format.\n//\n//*****************************************************************************\n#if (GLOBAL_IQ >= 15)\n#define _IQtoQ15(A)             ((int32_t)(A) >> (GLOBAL_IQ - 15))\n#define _Q15toIQ(A)             ((_iq15)(A) << (GLOBAL_IQ - 15))\n#else\n#define _IQtoQ15(A)             ((int32_t)(A) << (15 - GLOBAL_IQ))\n#define _Q15toIQ(A)             ((_iq15)(A) >> (15 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 14)\n#define _IQtoQ14(A)             ((int32_t)(A) >> (GLOBAL_IQ - 14))\n#define _Q14toIQ(A)             ((_iq14)(A) << (GLOBAL_IQ - 14))\n#else\n#define _IQtoQ14(A)             ((int32_t)(A) << (14 - GLOBAL_IQ))\n#define _Q14toIQ(A)             ((_iq14)(A) >> (14 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 13)\n#define _IQtoQ13(A)             ((int32_t)(A) >> (GLOBAL_IQ - 13))\n#define _Q13toIQ(A)             ((_iq13)(A) << (GLOBAL_IQ - 13))\n#else\n#define _IQtoQ13(A)             ((int32_t)(A) << (13 - GLOBAL_IQ))\n#define _Q13toIQ(A)             ((_iq13)(A) >> (13 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 12)\n#define _IQtoQ12(A)             ((int32_t)(A) >> (GLOBAL_IQ - 12))\n#define _Q12toIQ(A)             ((_iq12)(A) << (GLOBAL_IQ - 12))\n#else\n#define _IQtoQ12(A)             ((int32_t)(A) << (12 - GLOBAL_IQ))\n#define _Q12toIQ(A)             ((_iq12)(A) >> (12 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 11)\n#define _IQtoQ11(A)             ((int32_t)(A) >> (GLOBAL_IQ - 11))\n#define _Q11toIQ(A)             ((_iq11)(A) << (GLOBAL_IQ - 11))\n#else\n#define _IQtoQ11(A)             ((int32_t)(A) << (11 - GLOBAL_IQ))\n#define _Q11toIQ(A)             ((_iq11)(A) >> (11 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 10)\n#define _IQtoQ10(A)             ((int32_t)(A) >> (GLOBAL_IQ - 10))\n#define _Q10toIQ(A)             ((_iq10)(A) << (GLOBAL_IQ - 10))\n#else\n#define _IQtoQ10(A)             ((int32_t)(A) << (10 - GLOBAL_IQ))\n#define _Q10toIQ(A)             ((_iq10)(A) >> (10 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 9)\n#define _IQtoQ9(A)              ((int32_t)(A) >> (GLOBAL_IQ - 9))\n#define _Q9toIQ(A)              ((_iq9)(A) << (GLOBAL_IQ - 9))\n#else\n#define _IQtoQ9(A)              ((int32_t)(A) << (9 - GLOBAL_IQ))\n#define _Q9toIQ(A)              ((_iq9)(A) >> (9 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 8)\n#define _IQtoQ8(A)              ((int32_t)(A) >> (GLOBAL_IQ - 8))\n#define _Q8toIQ(A)              ((_iq8)(A) << (GLOBAL_IQ - 8))\n#else\n#define _IQtoQ8(A)              ((int32_t)(A) << (8 - GLOBAL_IQ))\n#define _Q8toIQ(A)              ((_iq8)(A) >> (8 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 7)\n#define _IQtoQ7(A)              ((int32_t)(A) >> (GLOBAL_IQ - 7))\n#define _Q7toIQ(A)              ((_iq7)(A) << (GLOBAL_IQ - 7))\n#else\n#define _IQtoQ7(A)              ((int32_t)(A) << (7 - GLOBAL_IQ))\n#define _Q7toIQ(A)              ((_iq7)(A) >> (7 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 6)\n#define _IQtoQ6(A)              ((int32_t)(A) >> (GLOBAL_IQ - 6))\n#define _Q6toIQ(A)              ((_iq6)(A) << (GLOBAL_IQ - 6))\n#else\n#define _IQtoQ6(A)              ((int32_t)(A) << (6 - GLOBAL_IQ))\n#define _Q6toIQ(A)              ((_iq6)(A) >> (6 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 5)\n#define _IQtoQ5(A)              ((int32_t)(A) >> (GLOBAL_IQ - 5))\n#define _Q5toIQ(A)              ((_iq5)(A) << (GLOBAL_IQ - 5))\n#else\n#define _IQtoQ5(A)              ((int32_t)(A) << (5 - GLOBAL_IQ))\n#define _Q5toIQ(A)              ((_iq5)(A) >> (5 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 4)\n#define _IQtoQ4(A)              ((int32_t)(A) >> (GLOBAL_IQ - 4))\n#define _Q4toIQ(A)              ((_iq4)(A) << (GLOBAL_IQ - 4))\n#else\n#define _IQtoQ4(A)              ((int32_t)(A) << (4 - GLOBAL_IQ))\n#define _Q4toIQ(A)              ((_iq4)(A) >> (4 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 3)\n#define _IQtoQ3(A)              ((int32_t)(A) >> (GLOBAL_IQ - 3))\n#define _Q3toIQ(A)              ((_iq3)(A) << (GLOBAL_IQ - 3))\n#else\n#define _IQtoQ3(A)              ((int32_t)(A) << (3 - GLOBAL_IQ))\n#define _Q3toIQ(A)              ((_iq3)(A) >> (3 - GLOBAL_IQ))\n#endif\n\n#if (GLOBAL_IQ >= 2)\n#define _IQtoQ2(A)              ((int32_t)(A) >> (GLOBAL_IQ - 2))\n#define _Q2toIQ(A)              ((_iq2)(A) << (GLOBAL_IQ - 2))\n#else\n#define _IQtoQ2(A)              ((int32_t)(A) << (2 - GLOBAL_IQ))\n#define _Q2toIQ(A)              ((_iq2)(A) >> (2 - GLOBAL_IQ))\n#endif\n\n#define _IQtoQ1(A)              ((int32_t)(A) >> (GLOBAL_IQ - 1))\n#define _Q1toIQ(A)              ((_iq1)(A) << (GLOBAL_IQ - 1))\n\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n//*****************************************************************************\n//\n// Multiplies two IQ numbers.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern _iq30 _IQ30mpy(_iq30 A, _iq30 B);\nextern _iq29 _IQ29mpy(_iq29 A, _iq29 B);\nextern _iq28 _IQ28mpy(_iq28 A, _iq28 B);\nextern _iq27 _IQ27mpy(_iq27 A, _iq27 B);\nextern _iq26 _IQ26mpy(_iq26 A, _iq26 B);\nextern _iq25 _IQ25mpy(_iq25 A, _iq25 B);\nextern _iq24 _IQ24mpy(_iq24 A, _iq24 B);\nextern _iq23 _IQ23mpy(_iq23 A, _iq23 B);\nextern _iq22 _IQ22mpy(_iq22 A, _iq22 B);\nextern _iq21 _IQ21mpy(_iq21 A, _iq21 B);\nextern _iq20 _IQ20mpy(_iq20 A, _iq20 B);\nextern _iq19 _IQ19mpy(_iq19 A, _iq19 B);\nextern _iq18 _IQ18mpy(_iq18 A, _iq18 B);\nextern _iq17 _IQ17mpy(_iq17 A, _iq17 B);\nextern _iq16 _IQ16mpy(_iq16 A, _iq16 B);\nextern _iq15 _IQ15mpy(_iq15 A, _iq15 B);\nextern _iq14 _IQ14mpy(_iq14 A, _iq14 B);\nextern _iq13 _IQ13mpy(_iq13 A, _iq13 B);\nextern _iq12 _IQ12mpy(_iq12 A, _iq12 B);\nextern _iq11 _IQ11mpy(_iq11 A, _iq11 B);\nextern _iq10 _IQ10mpy(_iq10 A, _iq10 B);\nextern _iq9 _IQ9mpy(_iq9 A, _iq9 B);\nextern _iq8 _IQ8mpy(_iq8 A, _iq8 B);\nextern _iq7 _IQ7mpy(_iq7 A, _iq7 B);\nextern _iq6 _IQ6mpy(_iq6 A, _iq6 B);\nextern _iq5 _IQ5mpy(_iq5 A, _iq5 B);\nextern _iq4 _IQ4mpy(_iq4 A, _iq4 B);\nextern _iq3 _IQ3mpy(_iq3 A, _iq3 B);\nextern _iq2 _IQ2mpy(_iq2 A, _iq2 B);\nextern _iq1 _IQ1mpy(_iq1 A, _iq1 B);\n\n//*****************************************************************************\n//\n// MathACL Repeat Operation: repeats same settings as last call (same IQ value, same operation).\n// This version is only compatible with IQmpy and IQdiv.\n//\n//*****************************************************************************\n#if ((defined (__IQMATH_USE_MATHACL__)) && (defined (__MSPM0_HAS_MATHACL__)))\nextern int32_t _IQrepeat(int32_t A, int32_t B);\n#endif\n\n\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Multiplies two global IQ format numbers.\n *\n * @param A               Global IQ format number to be multiplied.\n * @param B               Global IQ format number to be multiplied.\n *\n * @return                Global IQ type result of multiplication.\n */\n#if GLOBAL_IQ == 30\n#define _IQmpy(A, B)            _IQ30mpy(A, B)\n#endif\n#if GLOBAL_IQ == 29\n#define _IQmpy(A, B)            _IQ29mpy(A, B)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQmpy(A, B)            _IQ28mpy(A, B)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQmpy(A, B)            _IQ27mpy(A, B)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQmpy(A, B)            _IQ26mpy(A, B)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQmpy(A, B)            _IQ25mpy(A, B)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQmpy(A, B)            _IQ24mpy(A, B)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQmpy(A, B)            _IQ23mpy(A, B)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQmpy(A, B)            _IQ22mpy(A, B)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQmpy(A, B)            _IQ21mpy(A, B)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQmpy(A, B)            _IQ20mpy(A, B)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQmpy(A, B)            _IQ19mpy(A, B)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQmpy(A, B)            _IQ18mpy(A, B)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQmpy(A, B)            _IQ17mpy(A, B)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQmpy(A, B)            _IQ16mpy(A, B)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQmpy(A, B)            _IQ15mpy(A, B)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQmpy(A, B)            _IQ14mpy(A, B)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQmpy(A, B)            _IQ13mpy(A, B)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQmpy(A, B)            _IQ12mpy(A, B)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQmpy(A, B)            _IQ11mpy(A, B)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQmpy(A, B)            _IQ10mpy(A, B)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQmpy(A, B)            _IQ9mpy(A, B)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQmpy(A, B)            _IQ8mpy(A, B)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQmpy(A, B)            _IQ7mpy(A, B)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQmpy(A, B)            _IQ6mpy(A, B)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQmpy(A, B)            _IQ5mpy(A, B)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQmpy(A, B)            _IQ4mpy(A, B)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQmpy(A, B)            _IQ3mpy(A, B)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQmpy(A, B)            _IQ2mpy(A, B)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQmpy(A, B)            _IQ1mpy(A, B)\n#endif\n\n//*****************************************************************************\n//\n// Multiplies two IQ numbers, with rounding.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern _iq30 _IQ30rmpy(_iq30 A, _iq30 B);\nextern _iq29 _IQ29rmpy(_iq29 A, _iq29 B);\nextern _iq28 _IQ28rmpy(_iq28 A, _iq28 B);\nextern _iq27 _IQ27rmpy(_iq27 A, _iq27 B);\nextern _iq26 _IQ26rmpy(_iq26 A, _iq26 B);\nextern _iq25 _IQ25rmpy(_iq25 A, _iq25 B);\nextern _iq24 _IQ24rmpy(_iq24 A, _iq24 B);\nextern _iq23 _IQ23rmpy(_iq23 A, _iq23 B);\nextern _iq22 _IQ22rmpy(_iq22 A, _iq22 B);\nextern _iq21 _IQ21rmpy(_iq21 A, _iq21 B);\nextern _iq20 _IQ20rmpy(_iq20 A, _iq20 B);\nextern _iq19 _IQ19rmpy(_iq19 A, _iq19 B);\nextern _iq18 _IQ18rmpy(_iq18 A, _iq18 B);\nextern _iq17 _IQ17rmpy(_iq17 A, _iq17 B);\nextern _iq16 _IQ16rmpy(_iq16 A, _iq16 B);\nextern _iq15 _IQ15rmpy(_iq15 A, _iq15 B);\nextern _iq14 _IQ14rmpy(_iq14 A, _iq14 B);\nextern _iq13 _IQ13rmpy(_iq13 A, _iq13 B);\nextern _iq12 _IQ12rmpy(_iq12 A, _iq12 B);\nextern _iq11 _IQ11rmpy(_iq11 A, _iq11 B);\nextern _iq10 _IQ10rmpy(_iq10 A, _iq10 B);\nextern _iq9 _IQ9rmpy(_iq9 A, _iq9 B);\nextern _iq8 _IQ8rmpy(_iq8 A, _iq8 B);\nextern _iq7 _IQ7rmpy(_iq7 A, _iq7 B);\nextern _iq6 _IQ6rmpy(_iq6 A, _iq6 B);\nextern _iq5 _IQ5rmpy(_iq5 A, _iq5 B);\nextern _iq4 _IQ4rmpy(_iq4 A, _iq4 B);\nextern _iq3 _IQ3rmpy(_iq3 A, _iq3 B);\nextern _iq2 _IQ2rmpy(_iq2 A, _iq2 B);\nextern _iq1 _IQ1rmpy(_iq1 A, _iq1 B);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Multiplies two global IQ format numbers, with rounding\n *\n * @param A               Global IQ format number to be multiplied.\n * @param B               Global IQ format number to be multiplied.\n *\n * @return                Global IQ type result of multiplication.\n */\n#if GLOBAL_IQ == 30\n#define _IQrmpy(A, B)           _IQ30rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 29\n#define _IQrmpy(A, B)           _IQ29rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQrmpy(A, B)           _IQ28rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQrmpy(A, B)           _IQ27rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQrmpy(A, B)           _IQ26rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQrmpy(A, B)           _IQ25rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQrmpy(A, B)           _IQ24rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQrmpy(A, B)           _IQ23rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQrmpy(A, B)           _IQ22rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQrmpy(A, B)           _IQ21rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQrmpy(A, B)           _IQ20rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQrmpy(A, B)           _IQ19rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQrmpy(A, B)           _IQ18rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQrmpy(A, B)           _IQ17rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQrmpy(A, B)           _IQ16rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQrmpy(A, B)           _IQ15rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQrmpy(A, B)           _IQ14rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQrmpy(A, B)           _IQ13rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQrmpy(A, B)           _IQ12rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQrmpy(A, B)           _IQ11rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQrmpy(A, B)           _IQ10rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQrmpy(A, B)           _IQ9rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQrmpy(A, B)           _IQ8rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQrmpy(A, B)           _IQ7rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQrmpy(A, B)           _IQ6rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQrmpy(A, B)           _IQ5rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQrmpy(A, B)           _IQ4rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQrmpy(A, B)           _IQ3rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQrmpy(A, B)           _IQ2rmpy(A, B)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQrmpy(A, B)           _IQ1rmpy(A, B)\n#endif\n\n//*****************************************************************************\n//\n// Multiplies two IQ numbers, with rounding and saturation.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern _iq30 _IQ30rsmpy(_iq30 A, _iq30 B);\nextern _iq29 _IQ29rsmpy(_iq29 A, _iq29 B);\nextern _iq28 _IQ28rsmpy(_iq28 A, _iq28 B);\nextern _iq27 _IQ27rsmpy(_iq27 A, _iq27 B);\nextern _iq26 _IQ26rsmpy(_iq26 A, _iq26 B);\nextern _iq25 _IQ25rsmpy(_iq25 A, _iq25 B);\nextern _iq24 _IQ24rsmpy(_iq24 A, _iq24 B);\nextern _iq23 _IQ23rsmpy(_iq23 A, _iq23 B);\nextern _iq22 _IQ22rsmpy(_iq22 A, _iq22 B);\nextern _iq21 _IQ21rsmpy(_iq21 A, _iq21 B);\nextern _iq20 _IQ20rsmpy(_iq20 A, _iq20 B);\nextern _iq19 _IQ19rsmpy(_iq19 A, _iq19 B);\nextern _iq18 _IQ18rsmpy(_iq18 A, _iq18 B);\nextern _iq17 _IQ17rsmpy(_iq17 A, _iq17 B);\nextern _iq16 _IQ16rsmpy(_iq16 A, _iq16 B);\nextern _iq15 _IQ15rsmpy(_iq15 A, _iq15 B);\nextern _iq14 _IQ14rsmpy(_iq14 A, _iq14 B);\nextern _iq13 _IQ13rsmpy(_iq13 A, _iq13 B);\nextern _iq12 _IQ12rsmpy(_iq12 A, _iq12 B);\nextern _iq11 _IQ11rsmpy(_iq11 A, _iq11 B);\nextern _iq10 _IQ10rsmpy(_iq10 A, _iq10 B);\nextern _iq9 _IQ9rsmpy(_iq9 A, _iq9 B);\nextern _iq8 _IQ8rsmpy(_iq8 A, _iq8 B);\nextern _iq7 _IQ7rsmpy(_iq7 A, _iq7 B);\nextern _iq6 _IQ6rsmpy(_iq6 A, _iq6 B);\nextern _iq5 _IQ5rsmpy(_iq5 A, _iq5 B);\nextern _iq4 _IQ4rsmpy(_iq4 A, _iq4 B);\nextern _iq3 _IQ3rsmpy(_iq3 A, _iq3 B);\nextern _iq2 _IQ2rsmpy(_iq2 A, _iq2 B);\nextern _iq1 _IQ1rsmpy(_iq1 A, _iq1 B);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Multiplies two global IQ format numbers, with rounding and saturation.\n *\n * @param A               Global IQ format number to be multiplied.\n * @param B               Global IQ format number to be multiplied.\n *\n * @return                Global IQ type result of multiplication.\n */\n#if GLOBAL_IQ == 30\n#define _IQrsmpy(A, B)          _IQ30rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 29\n#define _IQrsmpy(A, B)          _IQ29rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQrsmpy(A, B)          _IQ28rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQrsmpy(A, B)          _IQ27rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQrsmpy(A, B)          _IQ26rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQrsmpy(A, B)          _IQ25rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQrsmpy(A, B)          _IQ24rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQrsmpy(A, B)          _IQ23rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQrsmpy(A, B)          _IQ22rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQrsmpy(A, B)          _IQ21rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQrsmpy(A, B)          _IQ20rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQrsmpy(A, B)          _IQ19rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQrsmpy(A, B)          _IQ18rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQrsmpy(A, B)          _IQ17rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQrsmpy(A, B)          _IQ16rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQrsmpy(A, B)          _IQ15rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQrsmpy(A, B)          _IQ14rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQrsmpy(A, B)          _IQ13rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQrsmpy(A, B)          _IQ12rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQrsmpy(A, B)          _IQ11rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQrsmpy(A, B)          _IQ10rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQrsmpy(A, B)          _IQ9rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQrsmpy(A, B)          _IQ8rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQrsmpy(A, B)          _IQ7rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQrsmpy(A, B)          _IQ6rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQrsmpy(A, B)          _IQ5rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQrsmpy(A, B)          _IQ4rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQrsmpy(A, B)          _IQ3rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQrsmpy(A, B)          _IQ2rsmpy(A, B)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQrsmpy(A, B)          _IQ1rsmpy(A, B)\n#endif\n\n//*****************************************************************************\n//\n// Divides two IQ numbers.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern _iq30 _IQ30div(_iq30 A, _iq30 B);\nextern _iq29 _IQ29div(_iq29 A, _iq29 B);\nextern _iq28 _IQ28div(_iq28 A, _iq28 B);\nextern _iq27 _IQ27div(_iq27 A, _iq27 B);\nextern _iq26 _IQ26div(_iq26 A, _iq26 B);\nextern _iq25 _IQ25div(_iq25 A, _iq25 B);\nextern _iq24 _IQ24div(_iq24 A, _iq24 B);\nextern _iq23 _IQ23div(_iq23 A, _iq23 B);\nextern _iq22 _IQ22div(_iq22 A, _iq22 B);\nextern _iq21 _IQ21div(_iq21 A, _iq21 B);\nextern _iq20 _IQ20div(_iq20 A, _iq20 B);\nextern _iq19 _IQ19div(_iq19 A, _iq19 B);\nextern _iq18 _IQ18div(_iq18 A, _iq18 B);\nextern _iq17 _IQ17div(_iq17 A, _iq17 B);\nextern _iq16 _IQ16div(_iq16 A, _iq16 B);\nextern _iq15 _IQ15div(_iq15 A, _iq15 B);\nextern _iq14 _IQ14div(_iq14 A, _iq14 B);\nextern _iq13 _IQ13div(_iq13 A, _iq13 B);\nextern _iq12 _IQ12div(_iq12 A, _iq12 B);\nextern _iq11 _IQ11div(_iq11 A, _iq11 B);\nextern _iq10 _IQ10div(_iq10 A, _iq10 B);\nextern _iq9 _IQ9div(_iq9 A, _iq9 B);\nextern _iq8 _IQ8div(_iq8 A, _iq8 B);\nextern _iq7 _IQ7div(_iq7 A, _iq7 B);\nextern _iq6 _IQ6div(_iq6 A, _iq6 B);\nextern _iq5 _IQ5div(_iq5 A, _iq5 B);\nextern _iq4 _IQ4div(_iq4 A, _iq4 B);\nextern _iq3 _IQ3div(_iq3 A, _iq3 B);\nextern _iq2 _IQ2div(_iq2 A, _iq2 B);\nextern _iq1 _IQ1div(_iq1 A, _iq1 B);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Divides two global IQ format numbers.\n *\n * @param A               Global IQ format numerator to be divided.\n * @param B               Global IQ format denominator to divide by.\n *\n * @return                Global IQ type result of division.\n */\n#if GLOBAL_IQ == 30\n#define _IQdiv(A, B)            _IQ30div(A, B)\n#endif\n#if GLOBAL_IQ == 29\n#define _IQdiv(A, B)            _IQ29div(A, B)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQdiv(A, B)            _IQ28div(A, B)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQdiv(A, B)            _IQ27div(A, B)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQdiv(A, B)            _IQ26div(A, B)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQdiv(A, B)            _IQ25div(A, B)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQdiv(A, B)            _IQ24div(A, B)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQdiv(A, B)            _IQ23div(A, B)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQdiv(A, B)            _IQ22div(A, B)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQdiv(A, B)            _IQ21div(A, B)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQdiv(A, B)            _IQ20div(A, B)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQdiv(A, B)            _IQ19div(A, B)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQdiv(A, B)            _IQ18div(A, B)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQdiv(A, B)            _IQ17div(A, B)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQdiv(A, B)            _IQ16div(A, B)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQdiv(A, B)            _IQ15div(A, B)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQdiv(A, B)            _IQ14div(A, B)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQdiv(A, B)            _IQ13div(A, B)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQdiv(A, B)            _IQ12div(A, B)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQdiv(A, B)            _IQ11div(A, B)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQdiv(A, B)            _IQ10div(A, B)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQdiv(A, B)            _IQ9div(A, B)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQdiv(A, B)            _IQ8div(A, B)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQdiv(A, B)            _IQ7div(A, B)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQdiv(A, B)            _IQ6div(A, B)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQdiv(A, B)            _IQ5div(A, B)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQdiv(A, B)            _IQ4div(A, B)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQdiv(A, B)            _IQ3div(A, B)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQdiv(A, B)            _IQ2div(A, B)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQdiv(A, B)            _IQ1div(A, B)\n#endif\n\n//*****************************************************************************\n//\n// Computes the sin of an IQ number.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern _iq29 _IQ29sin(_iq29 A);\nextern _iq28 _IQ28sin(_iq28 A);\nextern _iq27 _IQ27sin(_iq27 A);\nextern _iq26 _IQ26sin(_iq26 A);\nextern _iq25 _IQ25sin(_iq25 A);\nextern _iq24 _IQ24sin(_iq24 A);\nextern _iq23 _IQ23sin(_iq23 A);\nextern _iq22 _IQ22sin(_iq22 A);\nextern _iq21 _IQ21sin(_iq21 A);\nextern _iq20 _IQ20sin(_iq20 A);\nextern _iq19 _IQ19sin(_iq19 A);\nextern _iq18 _IQ18sin(_iq18 A);\nextern _iq17 _IQ17sin(_iq17 A);\nextern _iq16 _IQ16sin(_iq16 A);\nextern _iq15 _IQ15sin(_iq15 A);\nextern _iq14 _IQ14sin(_iq14 A);\nextern _iq13 _IQ13sin(_iq13 A);\nextern _iq12 _IQ12sin(_iq12 A);\nextern _iq11 _IQ11sin(_iq11 A);\nextern _iq10 _IQ10sin(_iq10 A);\nextern _iq9 _IQ9sin(_iq9 A);\nextern _iq8 _IQ8sin(_iq8 A);\nextern _iq7 _IQ7sin(_iq7 A);\nextern _iq6 _IQ6sin(_iq6 A);\nextern _iq5 _IQ5sin(_iq5 A);\nextern _iq4 _IQ4sin(_iq4 A);\nextern _iq3 _IQ3sin(_iq3 A);\nextern _iq2 _IQ2sin(_iq2 A);\nextern _iq1 _IQ1sin(_iq1 A);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Computes the sine of a global IQ format input, in radians.\n *\n * @param A               Global IQ format input.\n *\n * @return                Global IQ type result of sine operation.\n */\n#if GLOBAL_IQ == 29\n#define _IQsin(A)               _IQ29sin(A)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQsin(A)               _IQ28sin(A)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQsin(A)               _IQ27sin(A)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQsin(A)               _IQ26sin(A)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQsin(A)               _IQ25sin(A)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQsin(A)               _IQ24sin(A)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQsin(A)               _IQ23sin(A)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQsin(A)               _IQ22sin(A)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQsin(A)               _IQ21sin(A)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQsin(A)               _IQ20sin(A)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQsin(A)               _IQ19sin(A)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQsin(A)               _IQ18sin(A)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQsin(A)               _IQ17sin(A)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQsin(A)               _IQ16sin(A)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQsin(A)               _IQ15sin(A)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQsin(A)               _IQ14sin(A)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQsin(A)               _IQ13sin(A)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQsin(A)               _IQ12sin(A)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQsin(A)               _IQ11sin(A)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQsin(A)               _IQ10sin(A)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQsin(A)               _IQ9sin(A)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQsin(A)               _IQ8sin(A)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQsin(A)               _IQ7sin(A)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQsin(A)               _IQ6sin(A)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQsin(A)               _IQ5sin(A)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQsin(A)               _IQ4sin(A)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQsin(A)               _IQ3sin(A)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQsin(A)               _IQ2sin(A)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQsin(A)               _IQ1sin(A)\n#endif\n\n//*****************************************************************************\n//\n// Computes the sin of an IQ number, using cycles per unit instead of radians.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern _iq30 _IQ30sinPU(_iq30 A);\nextern _iq29 _IQ29sinPU(_iq29 A);\nextern _iq28 _IQ28sinPU(_iq28 A);\nextern _iq27 _IQ27sinPU(_iq27 A);\nextern _iq26 _IQ26sinPU(_iq26 A);\nextern _iq25 _IQ25sinPU(_iq25 A);\nextern _iq24 _IQ24sinPU(_iq24 A);\nextern _iq23 _IQ23sinPU(_iq23 A);\nextern _iq22 _IQ22sinPU(_iq22 A);\nextern _iq21 _IQ21sinPU(_iq21 A);\nextern _iq20 _IQ20sinPU(_iq20 A);\nextern _iq19 _IQ19sinPU(_iq19 A);\nextern _iq18 _IQ18sinPU(_iq18 A);\nextern _iq17 _IQ17sinPU(_iq17 A);\nextern _iq16 _IQ16sinPU(_iq16 A);\nextern _iq15 _IQ15sinPU(_iq15 A);\nextern _iq14 _IQ14sinPU(_iq14 A);\nextern _iq13 _IQ13sinPU(_iq13 A);\nextern _iq12 _IQ12sinPU(_iq12 A);\nextern _iq11 _IQ11sinPU(_iq11 A);\nextern _iq10 _IQ10sinPU(_iq10 A);\nextern _iq9 _IQ9sinPU(_iq9 A);\nextern _iq8 _IQ8sinPU(_iq8 A);\nextern _iq7 _IQ7sinPU(_iq7 A);\nextern _iq6 _IQ6sinPU(_iq6 A);\nextern _iq5 _IQ5sinPU(_iq5 A);\nextern _iq4 _IQ4sinPU(_iq4 A);\nextern _iq3 _IQ3sinPU(_iq3 A);\nextern _iq2 _IQ2sinPU(_iq2 A);\nextern _iq1 _IQ1sinPU(_iq1 A);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Computes the sine of a global IQ format input.\n *\n * @param A               Global IQ format input.\n *\n * @return                Global IQ type per-unit result of sine operation.\n */\n#if GLOBAL_IQ == 30\n#define _IQsinPU(A)             _IQ30sinPU(A)\n#endif\n#if GLOBAL_IQ == 29\n#define _IQsinPU(A)             _IQ29sinPU(A)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQsinPU(A)             _IQ28sinPU(A)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQsinPU(A)             _IQ27sinPU(A)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQsinPU(A)             _IQ26sinPU(A)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQsinPU(A)             _IQ25sinPU(A)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQsinPU(A)             _IQ24sinPU(A)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQsinPU(A)             _IQ23sinPU(A)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQsinPU(A)             _IQ22sinPU(A)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQsinPU(A)             _IQ21sinPU(A)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQsinPU(A)             _IQ20sinPU(A)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQsinPU(A)             _IQ19sinPU(A)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQsinPU(A)             _IQ18sinPU(A)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQsinPU(A)             _IQ17sinPU(A)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQsinPU(A)             _IQ16sinPU(A)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQsinPU(A)             _IQ15sinPU(A)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQsinPU(A)             _IQ14sinPU(A)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQsinPU(A)             _IQ13sinPU(A)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQsinPU(A)             _IQ12sinPU(A)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQsinPU(A)             _IQ11sinPU(A)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQsinPU(A)             _IQ10sinPU(A)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQsinPU(A)             _IQ9sinPU(A)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQsinPU(A)             _IQ8sinPU(A)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQsinPU(A)             _IQ7sinPU(A)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQsinPU(A)             _IQ6sinPU(A)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQsinPU(A)             _IQ5sinPU(A)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQsinPU(A)             _IQ4sinPU(A)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQsinPU(A)             _IQ3sinPU(A)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQsinPU(A)             _IQ2sinPU(A)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQsinPU(A)             _IQ1sinPU(A)\n#endif\n\n//*****************************************************************************\n//\n// Computes the arcsin of an IQ number.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern _iq29 _IQ29asin(_iq29 A);\nextern _iq28 _IQ28asin(_iq28 A);\nextern _iq27 _IQ27asin(_iq27 A);\nextern _iq26 _IQ26asin(_iq26 A);\nextern _iq25 _IQ25asin(_iq25 A);\nextern _iq24 _IQ24asin(_iq24 A);\nextern _iq23 _IQ23asin(_iq23 A);\nextern _iq22 _IQ22asin(_iq22 A);\nextern _iq21 _IQ21asin(_iq21 A);\nextern _iq20 _IQ20asin(_iq20 A);\nextern _iq19 _IQ19asin(_iq19 A);\nextern _iq18 _IQ18asin(_iq18 A);\nextern _iq17 _IQ17asin(_iq17 A);\nextern _iq16 _IQ16asin(_iq16 A);\nextern _iq15 _IQ15asin(_iq15 A);\nextern _iq14 _IQ14asin(_iq14 A);\nextern _iq13 _IQ13asin(_iq13 A);\nextern _iq12 _IQ12asin(_iq12 A);\nextern _iq11 _IQ11asin(_iq11 A);\nextern _iq10 _IQ10asin(_iq10 A);\nextern _iq9 _IQ9asin(_iq9 A);\nextern _iq8 _IQ8asin(_iq8 A);\nextern _iq7 _IQ7asin(_iq7 A);\nextern _iq6 _IQ6asin(_iq6 A);\nextern _iq5 _IQ5asin(_iq5 A);\nextern _iq4 _IQ4asin(_iq4 A);\nextern _iq3 _IQ3asin(_iq3 A);\nextern _iq2 _IQ2asin(_iq2 A);\nextern _iq1 _IQ1asin(_iq1 A);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Computes the inverse sine of a global IQ format input.\n *\n * @param A               Global IQ format input.\n *\n * @return                Global IQ type result of inverse sine operation.\n */\n#if GLOBAL_IQ == 29\n#define _IQasin(A)              _IQ29asin(A)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQasin(A)              _IQ28asin(A)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQasin(A)              _IQ27asin(A)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQasin(A)              _IQ26asin(A)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQasin(A)              _IQ25asin(A)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQasin(A)              _IQ24asin(A)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQasin(A)              _IQ23asin(A)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQasin(A)              _IQ22asin(A)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQasin(A)              _IQ21asin(A)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQasin(A)              _IQ20asin(A)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQasin(A)              _IQ19asin(A)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQasin(A)              _IQ18asin(A)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQasin(A)              _IQ17asin(A)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQasin(A)              _IQ16asin(A)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQasin(A)              _IQ15asin(A)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQasin(A)              _IQ14asin(A)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQasin(A)              _IQ13asin(A)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQasin(A)              _IQ12asin(A)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQasin(A)              _IQ11asin(A)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQasin(A)              _IQ10asin(A)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQasin(A)              _IQ9asin(A)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQasin(A)              _IQ8asin(A)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQasin(A)              _IQ7asin(A)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQasin(A)              _IQ6asin(A)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQasin(A)              _IQ5asin(A)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQasin(A)              _IQ4asin(A)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQasin(A)              _IQ3asin(A)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQasin(A)              _IQ2asin(A)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQasin(A)              _IQ1asin(A)\n#endif\n\n//*****************************************************************************\n//\n// Computes the cos of an IQ number.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern _iq29 _IQ29cos(_iq29 A);\nextern _iq28 _IQ28cos(_iq28 A);\nextern _iq27 _IQ27cos(_iq27 A);\nextern _iq26 _IQ26cos(_iq26 A);\nextern _iq25 _IQ25cos(_iq25 A);\nextern _iq24 _IQ24cos(_iq24 A);\nextern _iq23 _IQ23cos(_iq23 A);\nextern _iq22 _IQ22cos(_iq22 A);\nextern _iq21 _IQ21cos(_iq21 A);\nextern _iq20 _IQ20cos(_iq20 A);\nextern _iq19 _IQ19cos(_iq19 A);\nextern _iq18 _IQ18cos(_iq18 A);\nextern _iq17 _IQ17cos(_iq17 A);\nextern _iq16 _IQ16cos(_iq16 A);\nextern _iq15 _IQ15cos(_iq15 A);\nextern _iq14 _IQ14cos(_iq14 A);\nextern _iq13 _IQ13cos(_iq13 A);\nextern _iq12 _IQ12cos(_iq12 A);\nextern _iq11 _IQ11cos(_iq11 A);\nextern _iq10 _IQ10cos(_iq10 A);\nextern _iq9 _IQ9cos(_iq9 A);\nextern _iq8 _IQ8cos(_iq8 A);\nextern _iq7 _IQ7cos(_iq7 A);\nextern _iq6 _IQ6cos(_iq6 A);\nextern _iq5 _IQ5cos(_iq5 A);\nextern _iq4 _IQ4cos(_iq4 A);\nextern _iq3 _IQ3cos(_iq3 A);\nextern _iq2 _IQ2cos(_iq2 A);\nextern _iq1 _IQ1cos(_iq1 A);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Computes the cosine of a global IQ format input, in radians.\n *\n * @param A               Global IQ format input.\n *\n * @return                Global IQ type result of cosine operation.\n */\n#if GLOBAL_IQ == 29\n#define _IQcos(A)               _IQ29cos(A)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQcos(A)               _IQ28cos(A)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQcos(A)               _IQ27cos(A)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQcos(A)               _IQ26cos(A)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQcos(A)               _IQ25cos(A)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQcos(A)               _IQ24cos(A)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQcos(A)               _IQ23cos(A)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQcos(A)               _IQ22cos(A)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQcos(A)               _IQ21cos(A)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQcos(A)               _IQ20cos(A)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQcos(A)               _IQ19cos(A)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQcos(A)               _IQ18cos(A)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQcos(A)               _IQ17cos(A)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQcos(A)               _IQ16cos(A)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQcos(A)               _IQ15cos(A)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQcos(A)               _IQ14cos(A)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQcos(A)               _IQ13cos(A)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQcos(A)               _IQ12cos(A)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQcos(A)               _IQ11cos(A)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQcos(A)               _IQ10cos(A)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQcos(A)               _IQ9cos(A)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQcos(A)               _IQ8cos(A)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQcos(A)               _IQ7cos(A)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQcos(A)               _IQ6cos(A)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQcos(A)               _IQ5cos(A)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQcos(A)               _IQ4cos(A)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQcos(A)               _IQ3cos(A)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQcos(A)               _IQ2cos(A)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQcos(A)               _IQ1cos(A)\n#endif\n\n//*****************************************************************************\n//\n// Computes the cos of an IQ number, using cycles per unit instead of radians.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern _iq30 _IQ30cosPU(_iq30 A);\nextern _iq29 _IQ29cosPU(_iq29 A);\nextern _iq28 _IQ28cosPU(_iq28 A);\nextern _iq27 _IQ27cosPU(_iq27 A);\nextern _iq26 _IQ26cosPU(_iq26 A);\nextern _iq25 _IQ25cosPU(_iq25 A);\nextern _iq24 _IQ24cosPU(_iq24 A);\nextern _iq23 _IQ23cosPU(_iq23 A);\nextern _iq22 _IQ22cosPU(_iq22 A);\nextern _iq21 _IQ21cosPU(_iq21 A);\nextern _iq20 _IQ20cosPU(_iq20 A);\nextern _iq19 _IQ19cosPU(_iq19 A);\nextern _iq18 _IQ18cosPU(_iq18 A);\nextern _iq17 _IQ17cosPU(_iq17 A);\nextern _iq16 _IQ16cosPU(_iq16 A);\nextern _iq15 _IQ15cosPU(_iq15 A);\nextern _iq14 _IQ14cosPU(_iq14 A);\nextern _iq13 _IQ13cosPU(_iq13 A);\nextern _iq12 _IQ12cosPU(_iq12 A);\nextern _iq11 _IQ11cosPU(_iq11 A);\nextern _iq10 _IQ10cosPU(_iq10 A);\nextern _iq9 _IQ9cosPU(_iq9 A);\nextern _iq8 _IQ8cosPU(_iq8 A);\nextern _iq7 _IQ7cosPU(_iq7 A);\nextern _iq6 _IQ6cosPU(_iq6 A);\nextern _iq5 _IQ5cosPU(_iq5 A);\nextern _iq4 _IQ4cosPU(_iq4 A);\nextern _iq3 _IQ3cosPU(_iq3 A);\nextern _iq2 _IQ2cosPU(_iq2 A);\nextern _iq1 _IQ1cosPU(_iq1 A);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Computes the cossine of a global IQ format input.\n *\n * @param A               Global IQ format input.\n *\n * @return                Global IQ type per-unit result of cosine operation.\n */\n#if GLOBAL_IQ == 30\n#define _IQcosPU(A)             _IQ30cosPU(A)\n#endif\n#if GLOBAL_IQ == 29\n#define _IQcosPU(A)             _IQ29cosPU(A)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQcosPU(A)             _IQ28cosPU(A)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQcosPU(A)             _IQ27cosPU(A)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQcosPU(A)             _IQ26cosPU(A)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQcosPU(A)             _IQ25cosPU(A)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQcosPU(A)             _IQ24cosPU(A)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQcosPU(A)             _IQ23cosPU(A)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQcosPU(A)             _IQ22cosPU(A)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQcosPU(A)             _IQ21cosPU(A)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQcosPU(A)             _IQ20cosPU(A)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQcosPU(A)             _IQ19cosPU(A)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQcosPU(A)             _IQ18cosPU(A)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQcosPU(A)             _IQ17cosPU(A)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQcosPU(A)             _IQ16cosPU(A)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQcosPU(A)             _IQ15cosPU(A)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQcosPU(A)             _IQ14cosPU(A)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQcosPU(A)             _IQ13cosPU(A)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQcosPU(A)             _IQ12cosPU(A)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQcosPU(A)             _IQ11cosPU(A)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQcosPU(A)             _IQ10cosPU(A)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQcosPU(A)             _IQ9cosPU(A)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQcosPU(A)             _IQ8cosPU(A)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQcosPU(A)             _IQ7cosPU(A)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQcosPU(A)             _IQ6cosPU(A)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQcosPU(A)             _IQ5cosPU(A)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQcosPU(A)             _IQ4cosPU(A)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQcosPU(A)             _IQ3cosPU(A)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQcosPU(A)             _IQ2cosPU(A)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQcosPU(A)             _IQ1cosPU(A)\n#endif\n\n//*****************************************************************************\n//\n// Computes the arccos of an IQ number.\n//\n//*****************************************************************************\n/**\n * @brief Computes the inverse cosine of an IQ29 type input.\n *\n * @param A               IQ29 input.\n *\n * @return                IQ29 type result of inverse cosine operation.\n */\n#define _IQ29acos(A)            (_IQ29(1.570796327) - _IQ29asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ28 type input.\n *\n * @param A               IQ28 input.\n *\n * @return                IQ28 type result of inverse cosine operation.\n */\n#define _IQ28acos(A)            (_IQ28(1.570796327) - _IQ28asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ27 type input.\n *\n * @param A               IQ27 input.\n *\n * @return                IQ27 type result of inverse cosine operation.\n */\n#define _IQ27acos(A)            (_IQ27(1.570796327) - _IQ27asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ26 type input.\n *\n * @param A               IQ26 input.\n *\n * @return                IQ26 type result of inverse cosine operation.\n */\n#define _IQ26acos(A)            (_IQ26(1.570796327) - _IQ26asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ25 type input.\n *\n * @param A               IQ25 input.\n *\n * @return                IQ25 type result of inverse cosine operation.\n */\n#define _IQ25acos(A)            (_IQ25(1.570796327) - _IQ25asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ24 type input.\n *\n * @param A               IQ24 input.\n *\n * @return                IQ24 type result of inverse cosine operation.\n */\n#define _IQ24acos(A)            (_IQ24(1.570796327) - _IQ24asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ23 type input.\n *\n * @param A               IQ23 input.\n *\n * @return                IQ23 type result of inverse cosine operation.\n */\n#define _IQ23acos(A)            (_IQ23(1.570796327) - _IQ23asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ22 type input.\n *\n * @param A               IQ22 input.\n *\n * @return                IQ22 type result of inverse cosine operation.\n */\n#define _IQ22acos(A)            (_IQ22(1.570796327) - _IQ22asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ21 type input.\n *\n * @param A               IQ21 input.\n *\n * @return                IQ21 type result of inverse cosine operation.\n */\n#define _IQ21acos(A)            (_IQ21(1.570796327) - _IQ21asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ20 type input.\n *\n * @param A               IQ20 input.\n *\n * @return                IQ20 type result of inverse cosine operation.\n */\n#define _IQ20acos(A)            (_IQ20(1.570796327) - _IQ20asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ19 type input.\n *\n * @param A               IQ19 input.\n *\n * @return                IQ19 type result of inverse cosine operation.\n */\n#define _IQ19acos(A)            (_IQ19(1.570796327) - _IQ19asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ18 type input.\n *\n * @param A               IQ18 input.\n *\n * @return                IQ18 type result of inverse cosine operation.\n */\n#define _IQ18acos(A)            (_IQ18(1.570796327) - _IQ18asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ17 type input.\n *\n * @param A               IQ17 input.\n *\n * @return                IQ17 type result of inverse cosine operation.\n */\n#define _IQ17acos(A)            (_IQ17(1.570796327) - _IQ17asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ16 type input.\n *\n * @param A               IQ16 input.\n *\n * @return                IQ16 type result of inverse cosine operation.\n */\n#define _IQ16acos(A)            (_IQ16(1.570796327) - _IQ16asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ15 type input.\n *\n * @param A               IQ15 input.\n *\n * @return                IQ15 type result of inverse cosine operation.\n */\n#define _IQ15acos(A)            (_IQ15(1.570796327) - _IQ15asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ14 type input.\n *\n * @param A               IQ14 input.\n *\n * @return                IQ14 type result of inverse cosine operation.\n */\n#define _IQ14acos(A)            (_IQ14(1.570796327) - _IQ14asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ13 type input.\n *\n * @param A               IQ13 input.\n *\n * @return                IQ13 type result of inverse cosine operation.\n */\n#define _IQ13acos(A)            (_IQ13(1.570796327) - _IQ13asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ12 type input.\n *\n * @param A               IQ12 input.\n *\n * @return                IQ12 type result of inverse cosine operation.\n */\n#define _IQ12acos(A)            (_IQ12(1.570796327) - _IQ12asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ11 type input.\n *\n * @param A               IQ11 input.\n *\n * @return                IQ11 type result of inverse cosine operation.\n */\n#define _IQ11acos(A)            (_IQ11(1.570796327) - _IQ11asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ10 type input.\n *\n * @param A               IQ10 input.\n *\n * @return                IQ10 type result of inverse cosine operation.\n */\n#define _IQ10acos(A)            (_IQ10(1.570796327) - _IQ10asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ9 type input.\n *\n * @param A               IQ9 input.\n *\n * @return                IQ9 type result of inverse cosine operation.\n */\n#define _IQ9acos(A)             (_IQ9(1.570796327) - _IQ9asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ8 type input.\n *\n * @param A               IQ8 input.\n *\n * @return                IQ8 type result of inverse cosine operation.\n */\n#define _IQ8acos(A)             (_IQ8(1.570796327) - _IQ8asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ7 type input.\n *\n * @param A               IQ7 input.\n *\n * @return                IQ7 type result of inverse cosine operation.\n */\n#define _IQ7acos(A)             (_IQ7(1.570796327) - _IQ7asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ6 type input.\n *\n * @param A               IQ6 input.\n *\n * @return                IQ6 type result of inverse cosine operation.\n */\n#define _IQ6acos(A)             (_IQ6(1.570796327) - _IQ6asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ5 type input.\n *\n * @param A               IQ5 input.\n *\n * @return                IQ5 type result of inverse cosine operation.\n */\n#define _IQ5acos(A)             (_IQ5(1.570796327) - _IQ5asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ4 type input.\n *\n * @param A               IQ4 input.\n *\n * @return                IQ4 type result of inverse cosine operation.\n */\n#define _IQ4acos(A)             (_IQ4(1.570796327) - _IQ4asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ3 type input.\n *\n * @param A               IQ3 input.\n *\n * @return                IQ3 type result of inverse cosine operation.\n */\n#define _IQ3acos(A)             (_IQ3(1.570796327) - _IQ3asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ2 type input.\n *\n * @param A               IQ2 input.\n *\n * @return                IQ2 type result of inverse cosine operation.\n */\n#define _IQ2acos(A)             (_IQ2(1.570796327) - _IQ2asin(A))\n/**\n * @brief Computes the inverse cosine of an IQ1 type input.\n *\n * @param A               IQ1 input.\n *\n * @return                IQ1 type result of inverse cosine operation.\n */\n#define _IQ1acos(A)             (_IQ1(1.570796327) - _IQ1asin(A))\n\n/**\n * @brief Computes the inverse cosine of a global IQ format input.\n *\n * @param A               Global IQ format input.\n *\n * @return                Global IQ type result of inverse cosine operation.\n */\n#if GLOBAL_IQ == 29\n#define _IQacos(A)              _IQ29acos(A)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQacos(A)              _IQ28acos(A)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQacos(A)              _IQ27acos(A)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQacos(A)              _IQ26acos(A)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQacos(A)              _IQ25acos(A)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQacos(A)              _IQ24acos(A)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQacos(A)              _IQ23acos(A)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQacos(A)              _IQ22acos(A)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQacos(A)              _IQ21acos(A)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQacos(A)              _IQ20acos(A)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQacos(A)              _IQ19acos(A)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQacos(A)              _IQ18acos(A)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQacos(A)              _IQ17acos(A)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQacos(A)              _IQ16acos(A)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQacos(A)              _IQ15acos(A)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQacos(A)              _IQ14acos(A)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQacos(A)              _IQ13acos(A)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQacos(A)              _IQ12acos(A)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQacos(A)              _IQ11acos(A)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQacos(A)              _IQ10acos(A)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQacos(A)              _IQ9acos(A)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQacos(A)              _IQ8acos(A)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQacos(A)              _IQ7acos(A)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQacos(A)              _IQ6acos(A)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQacos(A)              _IQ5acos(A)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQacos(A)              _IQ4acos(A)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQacos(A)              _IQ3acos(A)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQacos(A)              _IQ2acos(A)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQacos(A)              _IQ1acos(A)\n#endif\n\n//*****************************************************************************\n//\n// Computes the arctan of a coordinate specified by two IQ numbers.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern _iq29 _IQ29atan2(_iq29 A, _iq29 B);\nextern _iq28 _IQ28atan2(_iq28 A, _iq28 B);\nextern _iq27 _IQ27atan2(_iq27 A, _iq27 B);\nextern _iq26 _IQ26atan2(_iq26 A, _iq26 B);\nextern _iq25 _IQ25atan2(_iq25 A, _iq25 B);\nextern _iq24 _IQ24atan2(_iq24 A, _iq24 B);\nextern _iq23 _IQ23atan2(_iq23 A, _iq23 B);\nextern _iq22 _IQ22atan2(_iq22 A, _iq22 B);\nextern _iq21 _IQ21atan2(_iq21 A, _iq21 B);\nextern _iq20 _IQ20atan2(_iq20 A, _iq20 B);\nextern _iq19 _IQ19atan2(_iq19 A, _iq19 B);\nextern _iq18 _IQ18atan2(_iq18 A, _iq18 B);\nextern _iq17 _IQ17atan2(_iq17 A, _iq17 B);\nextern _iq16 _IQ16atan2(_iq16 A, _iq16 B);\nextern _iq15 _IQ15atan2(_iq15 A, _iq15 B);\nextern _iq14 _IQ14atan2(_iq14 A, _iq14 B);\nextern _iq13 _IQ13atan2(_iq13 A, _iq13 B);\nextern _iq12 _IQ12atan2(_iq12 A, _iq12 B);\nextern _iq11 _IQ11atan2(_iq11 A, _iq11 B);\nextern _iq10 _IQ10atan2(_iq10 A, _iq10 B);\nextern _iq9 _IQ9atan2(_iq9 A, _iq9 B);\nextern _iq8 _IQ8atan2(_iq8 A, _iq8 B);\nextern _iq7 _IQ7atan2(_iq7 A, _iq7 B);\nextern _iq6 _IQ6atan2(_iq6 A, _iq6 B);\nextern _iq5 _IQ5atan2(_iq5 A, _iq5 B);\nextern _iq4 _IQ4atan2(_iq4 A, _iq4 B);\nextern _iq3 _IQ3atan2(_iq3 A, _iq3 B);\nextern _iq2 _IQ2atan2(_iq2 A, _iq2 B);\nextern _iq1 _IQ1atan2(_iq1 A, _iq1 B);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Compute the 4-quadrant arctangent of a\n * global IQ format input, in radians.\n *\n * @param A               Global IQ format input.\n * @param B               Global IQ format input.\n *\n * @return                Global IQ type result of\n *                        4-quadrant arctangent.\n */\n#if GLOBAL_IQ == 29\n#define _IQatan2(A, B)          _IQ29atan2(A, B)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQatan2(A, B)          _IQ28atan2(A, B)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQatan2(A, B)          _IQ27atan2(A, B)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQatan2(A, B)          _IQ26atan2(A, B)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQatan2(A, B)          _IQ25atan2(A, B)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQatan2(A, B)          _IQ24atan2(A, B)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQatan2(A, B)          _IQ23atan2(A, B)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQatan2(A, B)          _IQ22atan2(A, B)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQatan2(A, B)          _IQ21atan2(A, B)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQatan2(A, B)          _IQ20atan2(A, B)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQatan2(A, B)          _IQ19atan2(A, B)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQatan2(A, B)          _IQ18atan2(A, B)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQatan2(A, B)          _IQ17atan2(A, B)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQatan2(A, B)          _IQ16atan2(A, B)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQatan2(A, B)          _IQ15atan2(A, B)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQatan2(A, B)          _IQ14atan2(A, B)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQatan2(A, B)          _IQ13atan2(A, B)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQatan2(A, B)          _IQ12atan2(A, B)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQatan2(A, B)          _IQ11atan2(A, B)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQatan2(A, B)          _IQ10atan2(A, B)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQatan2(A, B)          _IQ9atan2(A, B)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQatan2(A, B)          _IQ8atan2(A, B)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQatan2(A, B)          _IQ7atan2(A, B)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQatan2(A, B)          _IQ6atan2(A, B)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQatan2(A, B)          _IQ5atan2(A, B)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQatan2(A, B)          _IQ4atan2(A, B)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQatan2(A, B)          _IQ3atan2(A, B)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQatan2(A, B)          _IQ2atan2(A, B)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQatan2(A, B)          _IQ1atan2(A, B)\n#endif\n\n//*****************************************************************************\n//\n// Computes the arctan of a coordinate specified by two IQ numbers, returning\n// the value in cycles per unit instead of radians.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern _iq30 _IQ30atan2PU(_iq30 A, _iq30 B);\nextern _iq29 _IQ29atan2PU(_iq29 A, _iq29 B);\nextern _iq28 _IQ28atan2PU(_iq28 A, _iq28 B);\nextern _iq27 _IQ27atan2PU(_iq27 A, _iq27 B);\nextern _iq26 _IQ26atan2PU(_iq26 A, _iq26 B);\nextern _iq25 _IQ25atan2PU(_iq25 A, _iq25 B);\nextern _iq24 _IQ24atan2PU(_iq24 A, _iq24 B);\nextern _iq23 _IQ23atan2PU(_iq23 A, _iq23 B);\nextern _iq22 _IQ22atan2PU(_iq22 A, _iq22 B);\nextern _iq21 _IQ21atan2PU(_iq21 A, _iq21 B);\nextern _iq20 _IQ20atan2PU(_iq20 A, _iq20 B);\nextern _iq19 _IQ19atan2PU(_iq19 A, _iq19 B);\nextern _iq18 _IQ18atan2PU(_iq18 A, _iq18 B);\nextern _iq17 _IQ17atan2PU(_iq17 A, _iq17 B);\nextern _iq16 _IQ16atan2PU(_iq16 A, _iq16 B);\nextern _iq15 _IQ15atan2PU(_iq15 A, _iq15 B);\nextern _iq14 _IQ14atan2PU(_iq14 A, _iq14 B);\nextern _iq13 _IQ13atan2PU(_iq13 A, _iq13 B);\nextern _iq12 _IQ12atan2PU(_iq12 A, _iq12 B);\nextern _iq11 _IQ11atan2PU(_iq11 A, _iq11 B);\nextern _iq10 _IQ10atan2PU(_iq10 A, _iq10 B);\nextern _iq9 _IQ9atan2PU(_iq9 A, _iq9 B);\nextern _iq8 _IQ8atan2PU(_iq8 A, _iq8 B);\nextern _iq7 _IQ7atan2PU(_iq7 A, _iq7 B);\nextern _iq6 _IQ6atan2PU(_iq6 A, _iq6 B);\nextern _iq5 _IQ5atan2PU(_iq5 A, _iq5 B);\nextern _iq4 _IQ4atan2PU(_iq4 A, _iq4 B);\nextern _iq3 _IQ3atan2PU(_iq3 A, _iq3 B);\nextern _iq2 _IQ2atan2PU(_iq2 A, _iq2 B);\nextern _iq1 _IQ1atan2PU(_iq1 A, _iq1 B);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Compute the 4-quadrant arctangent of a\n * global IQ format input.\n *\n * @param A               Global IQ format input.\n * @param B               Global IQ format input.\n *\n * @return                Global IQ type per-unit result of\n *                        4-quadrant arctangent.\n */\n#if GLOBAL_IQ == 30\n#define _IQatan2PU(A, B)        _IQ30atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 29\n#define _IQatan2PU(A, B)        _IQ29atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQatan2PU(A, B)        _IQ28atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQatan2PU(A, B)        _IQ27atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQatan2PU(A, B)        _IQ26atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQatan2PU(A, B)        _IQ25atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQatan2PU(A, B)        _IQ24atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQatan2PU(A, B)        _IQ23atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQatan2PU(A, B)        _IQ22atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQatan2PU(A, B)        _IQ21atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQatan2PU(A, B)        _IQ20atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQatan2PU(A, B)        _IQ19atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQatan2PU(A, B)        _IQ18atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQatan2PU(A, B)        _IQ17atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQatan2PU(A, B)        _IQ16atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQatan2PU(A, B)        _IQ15atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQatan2PU(A, B)        _IQ14atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQatan2PU(A, B)        _IQ13atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQatan2PU(A, B)        _IQ12atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQatan2PU(A, B)        _IQ11atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQatan2PU(A, B)        _IQ10atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQatan2PU(A, B)        _IQ9atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQatan2PU(A, B)        _IQ8atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQatan2PU(A, B)        _IQ7atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQatan2PU(A, B)        _IQ6atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQatan2PU(A, B)        _IQ5atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQatan2PU(A, B)        _IQ4atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQatan2PU(A, B)        _IQ3atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQatan2PU(A, B)        _IQ2atan2PU(A, B)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQatan2PU(A, B)        _IQ1atan2PU(A, B)\n#endif\n\n//*****************************************************************************\n//\n// Computes the arctan of an IQ number.\n//\n//*****************************************************************************\n/**\n * @brief Computes the inverse tangnet of an IQ29 format input.\n *\n * @param A               IQ29 format input.\n *\n * @return                IQ29 type result of inverse tangent operation.\n */\n#define _IQ29atan(A)            _IQ29atan2(A, _IQ29(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ28 format input.\n *\n * @param A               IQ28 format input.\n *\n * @return                IQ28 type result of inverse tangent operation.\n */\n#define _IQ28atan(A)            _IQ28atan2(A, _IQ28(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ27 format input.\n *\n * @param A               IQ27 format input.\n *\n * @return                IQ27 type result of inverse tangent operation.\n */\n#define _IQ27atan(A)            _IQ27atan2(A, _IQ27(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ26 format input.\n *\n * @param A               IQ26 format input.\n *\n * @return                IQ26 type result of inverse tangent operation.\n */\n#define _IQ26atan(A)            _IQ26atan2(A, _IQ26(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ25 format input.\n *\n * @param A               IQ25 format input.\n *\n * @return                IQ25 type result of inverse tangent operation.\n */\n#define _IQ25atan(A)            _IQ25atan2(A, _IQ25(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ24 format input.\n *\n * @param A               IQ24 format input.\n *\n * @return                IQ24 type result of inverse tangent operation.\n */\n#define _IQ24atan(A)            _IQ24atan2(A, _IQ24(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ23 format input.\n *\n * @param A               IQ23 format input.\n *\n * @return                IQ23 type result of inverse tangent operation.\n */\n#define _IQ23atan(A)            _IQ23atan2(A, _IQ23(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ22 format input.\n *\n * @param A               IQ22 format input.\n *\n * @return                IQ22 type result of inverse tangent operation.\n */\n#define _IQ22atan(A)            _IQ22atan2(A, _IQ22(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ21 format input.\n *\n * @param A               IQ21 format input.\n *\n * @return                IQ21 type result of inverse tangent operation.\n */\n#define _IQ21atan(A)            _IQ21atan2(A, _IQ21(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ20 format input.\n *\n * @param A               IQ20 format input.\n *\n * @return                IQ20 type result of inverse tangent operation.\n */\n#define _IQ20atan(A)            _IQ20atan2(A, _IQ20(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ19 format input.\n *\n * @param A               IQ19 format input.\n *\n * @return                IQ19 type result of inverse tangent operation.\n */\n#define _IQ19atan(A)            _IQ19atan2(A, _IQ19(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ18 format input.\n *\n * @param A               IQ18 format input.\n *\n * @return                IQ18 type result of inverse tangent operation.\n */\n#define _IQ18atan(A)            _IQ18atan2(A, _IQ18(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ17 format input.\n *\n * @param A               IQ17 format input.\n *\n * @return                IQ17 type result of inverse tangent operation.\n */\n#define _IQ17atan(A)            _IQ17atan2(A, _IQ17(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ16 format input.\n *\n * @param A               IQ16 format input.\n *\n * @return                IQ16 type result of inverse tangent operation.\n */\n#define _IQ16atan(A)            _IQ16atan2(A, _IQ16(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ15 format input.\n *\n * @param A               IQ15 format input.\n *\n * @return                IQ15 type result of inverse tangent operation.\n */\n#define _IQ15atan(A)            _IQ15atan2(A, _IQ15(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ14 format input.\n *\n * @param A               IQ14 format input.\n *\n * @return                IQ14 type result of inverse tangent operation.\n */\n#define _IQ14atan(A)            _IQ14atan2(A, _IQ14(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ13 format input.\n *\n * @param A               IQ13 format input.\n *\n * @return                IQ13 type result of inverse tangent operation.\n */\n#define _IQ13atan(A)            _IQ13atan2(A, _IQ13(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ12 format input.\n *\n * @param A               IQ12 format input.\n *\n * @return                IQ12 type result of inverse tangent operation.\n */\n#define _IQ12atan(A)            _IQ12atan2(A, _IQ12(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ11 format input.\n *\n * @param A               IQ11 format input.\n *\n * @return                IQ11 type result of inverse tangent operation.\n */\n#define _IQ11atan(A)            _IQ11atan2(A, _IQ11(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ10 format input.\n *\n * @param A               IQ10 format input.\n *\n * @return                IQ10 type result of inverse tangent operation.\n */\n#define _IQ10atan(A)            _IQ10atan2(A, _IQ10(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ9 format input.\n *\n * @param A               IQ9 format input.\n *\n * @return                IQ9 type result of inverse tangent operation.\n */\n#define _IQ9atan(A)             _IQ9atan2(A, _IQ9(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ8 format input.\n *\n * @param A               IQ8 format input.\n *\n * @return                IQ8 type result of inverse tangent operation.\n */\n#define _IQ8atan(A)             _IQ8atan2(A, _IQ8(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ7 format input.\n *\n * @param A               IQ7 format input.\n *\n * @return                IQ7 type result of inverse tangent operation.\n */\n#define _IQ7atan(A)             _IQ7atan2(A, _IQ7(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ6 format input.\n *\n * @param A               IQ6 format input.\n *\n * @return                IQ6 type result of inverse tangent operation.\n */\n#define _IQ6atan(A)             _IQ6atan2(A, _IQ6(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ5 format input.\n *\n * @param A               IQ5 format input.\n *\n * @return                IQ5 type result of inverse tangent operation.\n */\n#define _IQ5atan(A)             _IQ5atan2(A, _IQ5(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ4 format input.\n *\n * @param A               IQ4 format input.\n *\n * @return                IQ4 type result of inverse tangent operation.\n */\n#define _IQ4atan(A)             _IQ4atan2(A, _IQ4(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ3 format input.\n *\n * @param A               IQ3 format input.\n *\n * @return                IQ3 type result of inverse tangent operation.\n */\n#define _IQ3atan(A)             _IQ3atan2(A, _IQ3(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ2 format input.\n *\n * @param A               IQ2 format input.\n *\n * @return                IQ2 type result of inverse tangent operation.\n */\n#define _IQ2atan(A)             _IQ2atan2(A, _IQ2(1.0))\n/**\n * @brief Computes the inverse tangnet of an IQ1 format input.\n *\n * @param A               IQ1 format input.\n *\n * @return                IQ1 type result of inverse tangent operation.\n */\n#define _IQ1atan(A)             _IQ1atan2(A, _IQ1(1.0))\n\n/**\n * @brief Computes the inverse tangent of a global IQ format input.\n *\n * @param A               Global IQ format input.\n *\n * @return                Global IQ type result of the inverse tangent.\n */\n#if GLOBAL_IQ == 29\n#define _IQatan(A)              _IQ29atan2(A, _IQ29(1.0))\n#endif\n#if GLOBAL_IQ == 28\n#define _IQatan(A)              _IQ28atan2(A, _IQ28(1.0))\n#endif\n#if GLOBAL_IQ == 27\n#define _IQatan(A)              _IQ27atan2(A, _IQ27(1.0))\n#endif\n#if GLOBAL_IQ == 26\n#define _IQatan(A)              _IQ26atan2(A, _IQ26(1.0))\n#endif\n#if GLOBAL_IQ == 25\n#define _IQatan(A)              _IQ25atan2(A, _IQ25(1.0))\n#endif\n#if GLOBAL_IQ == 24\n#define _IQatan(A)              _IQ24atan2(A, _IQ24(1.0))\n#endif\n#if GLOBAL_IQ == 23\n#define _IQatan(A)              _IQ23atan2(A, _IQ23(1.0))\n#endif\n#if GLOBAL_IQ == 22\n#define _IQatan(A)              _IQ22atan2(A, _IQ22(1.0))\n#endif\n#if GLOBAL_IQ == 21\n#define _IQatan(A)              _IQ21atan2(A, _IQ21(1.0))\n#endif\n#if GLOBAL_IQ == 20\n#define _IQatan(A)              _IQ20atan2(A, _IQ20(1.0))\n#endif\n#if GLOBAL_IQ == 19\n#define _IQatan(A)              _IQ19atan2(A, _IQ19(1.0))\n#endif\n#if GLOBAL_IQ == 18\n#define _IQatan(A)              _IQ18atan2(A, _IQ18(1.0))\n#endif\n#if GLOBAL_IQ == 17\n#define _IQatan(A)              _IQ17atan2(A, _IQ17(1.0))\n#endif\n#if GLOBAL_IQ == 16\n#define _IQatan(A)              _IQ16atan2(A, _IQ16(1.0))\n#endif\n#if GLOBAL_IQ == 15\n#define _IQatan(A)              _IQ15atan2(A, _IQ15(1.0))\n#endif\n#if GLOBAL_IQ == 14\n#define _IQatan(A)              _IQ14atan2(A, _IQ14(1.0))\n#endif\n#if GLOBAL_IQ == 13\n#define _IQatan(A)              _IQ13atan2(A, _IQ13(1.0))\n#endif\n#if GLOBAL_IQ == 12\n#define _IQatan(A)              _IQ12atan2(A, _IQ12(1.0))\n#endif\n#if GLOBAL_IQ == 11\n#define _IQatan(A)              _IQ11atan2(A, _IQ11(1.0))\n#endif\n#if GLOBAL_IQ == 10\n#define _IQatan(A)              _IQ10atan2(A, _IQ10(1.0))\n#endif\n#if GLOBAL_IQ == 9\n#define _IQatan(A)              _IQ9atan2(A, _IQ9(1.0))\n#endif\n#if GLOBAL_IQ == 8\n#define _IQatan(A)              _IQ8atan2(A, _IQ8(1.0))\n#endif\n#if GLOBAL_IQ == 7\n#define _IQatan(A)              _IQ7atan2(A, _IQ7(1.0))\n#endif\n#if GLOBAL_IQ == 6\n#define _IQatan(A)              _IQ6atan2(A, _IQ6(1.0))\n#endif\n#if GLOBAL_IQ == 5\n#define _IQatan(A)              _IQ5atan2(A, _IQ5(1.0))\n#endif\n#if GLOBAL_IQ == 4\n#define _IQatan(A)              _IQ4atan2(A, _IQ4(1.0))\n#endif\n#if GLOBAL_IQ == 3\n#define _IQatan(A)              _IQ3atan2(A, _IQ3(1.0))\n#endif\n#if GLOBAL_IQ == 2\n#define _IQatan(A)              _IQ2atan2(A, _IQ2(1.0))\n#endif\n#if GLOBAL_IQ == 1\n#define _IQatan(A)              _IQ1atan2(A, _IQ1(1.0))\n#endif\n\n//*****************************************************************************\n//\n// Computes the square root of an IQ number.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern _iq30 _IQ30sqrt(_iq30 A);\nextern _iq29 _IQ29sqrt(_iq29 A);\nextern _iq28 _IQ28sqrt(_iq28 A);\nextern _iq27 _IQ27sqrt(_iq27 A);\nextern _iq26 _IQ26sqrt(_iq26 A);\nextern _iq25 _IQ25sqrt(_iq25 A);\nextern _iq24 _IQ24sqrt(_iq24 A);\nextern _iq23 _IQ23sqrt(_iq23 A);\nextern _iq22 _IQ22sqrt(_iq22 A);\nextern _iq21 _IQ21sqrt(_iq21 A);\nextern _iq20 _IQ20sqrt(_iq20 A);\nextern _iq19 _IQ19sqrt(_iq19 A);\nextern _iq18 _IQ18sqrt(_iq18 A);\nextern _iq17 _IQ17sqrt(_iq17 A);\nextern _iq16 _IQ16sqrt(_iq16 A);\nextern _iq15 _IQ15sqrt(_iq15 A);\nextern _iq14 _IQ14sqrt(_iq14 A);\nextern _iq13 _IQ13sqrt(_iq13 A);\nextern _iq12 _IQ12sqrt(_iq12 A);\nextern _iq11 _IQ11sqrt(_iq11 A);\nextern _iq10 _IQ10sqrt(_iq10 A);\nextern _iq9 _IQ9sqrt(_iq9 A);\nextern _iq8 _IQ8sqrt(_iq8 A);\nextern _iq7 _IQ7sqrt(_iq7 A);\nextern _iq6 _IQ6sqrt(_iq6 A);\nextern _iq5 _IQ5sqrt(_iq5 A);\nextern _iq4 _IQ4sqrt(_iq4 A);\nextern _iq3 _IQ3sqrt(_iq3 A);\nextern _iq2 _IQ2sqrt(_iq2 A);\nextern _iq1 _IQ1sqrt(_iq1 A);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Calculate square root of a global IQ format input.\n *\n * @param A               Global IQ format input.\n *\n * @return                Global IQ type result of the square root operation.\n */\n#if GLOBAL_IQ == 30\n#define _IQsqrt(A)              _IQ30sqrt(A)\n#endif\n#if GLOBAL_IQ == 29\n#define _IQsqrt(A)              _IQ29sqrt(A)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQsqrt(A)              _IQ28sqrt(A)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQsqrt(A)              _IQ27sqrt(A)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQsqrt(A)              _IQ26sqrt(A)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQsqrt(A)              _IQ25sqrt(A)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQsqrt(A)              _IQ24sqrt(A)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQsqrt(A)              _IQ23sqrt(A)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQsqrt(A)              _IQ22sqrt(A)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQsqrt(A)              _IQ21sqrt(A)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQsqrt(A)              _IQ20sqrt(A)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQsqrt(A)              _IQ19sqrt(A)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQsqrt(A)              _IQ18sqrt(A)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQsqrt(A)              _IQ17sqrt(A)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQsqrt(A)              _IQ16sqrt(A)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQsqrt(A)              _IQ15sqrt(A)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQsqrt(A)              _IQ14sqrt(A)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQsqrt(A)              _IQ13sqrt(A)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQsqrt(A)              _IQ12sqrt(A)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQsqrt(A)              _IQ11sqrt(A)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQsqrt(A)              _IQ10sqrt(A)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQsqrt(A)              _IQ9sqrt(A)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQsqrt(A)              _IQ8sqrt(A)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQsqrt(A)              _IQ7sqrt(A)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQsqrt(A)              _IQ6sqrt(A)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQsqrt(A)              _IQ5sqrt(A)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQsqrt(A)              _IQ4sqrt(A)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQsqrt(A)              _IQ3sqrt(A)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQsqrt(A)              _IQ2sqrt(A)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQsqrt(A)              _IQ1sqrt(A)\n#endif\n\n//*****************************************************************************\n//\n// Computes 1 over the square root of an IQ number.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern _iq30 _IQ30isqrt(_iq30 A);\nextern _iq29 _IQ29isqrt(_iq29 A);\nextern _iq28 _IQ28isqrt(_iq28 A);\nextern _iq27 _IQ27isqrt(_iq27 A);\nextern _iq26 _IQ26isqrt(_iq26 A);\nextern _iq25 _IQ25isqrt(_iq25 A);\nextern _iq24 _IQ24isqrt(_iq24 A);\nextern _iq23 _IQ23isqrt(_iq23 A);\nextern _iq22 _IQ22isqrt(_iq22 A);\nextern _iq21 _IQ21isqrt(_iq21 A);\nextern _iq20 _IQ20isqrt(_iq20 A);\nextern _iq19 _IQ19isqrt(_iq19 A);\nextern _iq18 _IQ18isqrt(_iq18 A);\nextern _iq17 _IQ17isqrt(_iq17 A);\nextern _iq16 _IQ16isqrt(_iq16 A);\nextern _iq15 _IQ15isqrt(_iq15 A);\nextern _iq14 _IQ14isqrt(_iq14 A);\nextern _iq13 _IQ13isqrt(_iq13 A);\nextern _iq12 _IQ12isqrt(_iq12 A);\nextern _iq11 _IQ11isqrt(_iq11 A);\nextern _iq10 _IQ10isqrt(_iq10 A);\nextern _iq9 _IQ9isqrt(_iq9 A);\nextern _iq8 _IQ8isqrt(_iq8 A);\nextern _iq7 _IQ7isqrt(_iq7 A);\nextern _iq6 _IQ6isqrt(_iq6 A);\nextern _iq5 _IQ5isqrt(_iq5 A);\nextern _iq4 _IQ4isqrt(_iq4 A);\nextern _iq3 _IQ3isqrt(_iq3 A);\nextern _iq2 _IQ2isqrt(_iq2 A);\nextern _iq1 _IQ1isqrt(_iq1 A);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Computes 1 over the square root of a global IQ format number.\n *\n * @param A              Global IQ format input.\n *\n * @return               Global IQ type result of inverse square root operation.\n */\n#if GLOBAL_IQ == 30\n#define _IQisqrt(A)             _IQ30isqrt(A)\n#endif\n#if GLOBAL_IQ == 29\n#define _IQisqrt(A)             _IQ29isqrt(A)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQisqrt(A)             _IQ28isqrt(A)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQisqrt(A)             _IQ27isqrt(A)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQisqrt(A)             _IQ26isqrt(A)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQisqrt(A)             _IQ25isqrt(A)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQisqrt(A)             _IQ24isqrt(A)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQisqrt(A)             _IQ23isqrt(A)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQisqrt(A)             _IQ22isqrt(A)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQisqrt(A)             _IQ21isqrt(A)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQisqrt(A)             _IQ20isqrt(A)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQisqrt(A)             _IQ19isqrt(A)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQisqrt(A)             _IQ18isqrt(A)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQisqrt(A)             _IQ17isqrt(A)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQisqrt(A)             _IQ16isqrt(A)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQisqrt(A)             _IQ15isqrt(A)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQisqrt(A)             _IQ14isqrt(A)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQisqrt(A)             _IQ13isqrt(A)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQisqrt(A)             _IQ12isqrt(A)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQisqrt(A)             _IQ11isqrt(A)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQisqrt(A)             _IQ10isqrt(A)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQisqrt(A)             _IQ9isqrt(A)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQisqrt(A)             _IQ8isqrt(A)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQisqrt(A)             _IQ7isqrt(A)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQisqrt(A)             _IQ6isqrt(A)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQisqrt(A)             _IQ5isqrt(A)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQisqrt(A)             _IQ4isqrt(A)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQisqrt(A)             _IQ3isqrt(A)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQisqrt(A)             _IQ2isqrt(A)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQisqrt(A)             _IQ1isqrt(A)\n#endif\n\n//*****************************************************************************\n//\n// Computes e^x of an IQ number.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern _iq30 _IQ30exp(_iq30 A);\nextern _iq29 _IQ29exp(_iq29 A);\nextern _iq28 _IQ28exp(_iq28 A);\nextern _iq27 _IQ27exp(_iq27 A);\nextern _iq26 _IQ26exp(_iq26 A);\nextern _iq25 _IQ25exp(_iq25 A);\nextern _iq24 _IQ24exp(_iq24 A);\nextern _iq23 _IQ23exp(_iq23 A);\nextern _iq22 _IQ22exp(_iq22 A);\nextern _iq21 _IQ21exp(_iq21 A);\nextern _iq20 _IQ20exp(_iq20 A);\nextern _iq19 _IQ19exp(_iq19 A);\nextern _iq18 _IQ18exp(_iq18 A);\nextern _iq17 _IQ17exp(_iq17 A);\nextern _iq16 _IQ16exp(_iq16 A);\nextern _iq15 _IQ15exp(_iq15 A);\nextern _iq14 _IQ14exp(_iq14 A);\nextern _iq13 _IQ13exp(_iq13 A);\nextern _iq12 _IQ12exp(_iq12 A);\nextern _iq11 _IQ11exp(_iq11 A);\nextern _iq10 _IQ10exp(_iq10 A);\nextern _iq9 _IQ9exp(_iq9 A);\nextern _iq8 _IQ8exp(_iq8 A);\nextern _iq7 _IQ7exp(_iq7 A);\nextern _iq6 _IQ6exp(_iq6 A);\nextern _iq5 _IQ5exp(_iq5 A);\nextern _iq4 _IQ4exp(_iq4 A);\nextern _iq3 _IQ3exp(_iq3 A);\nextern _iq2 _IQ2exp(_iq2 A);\nextern _iq1 _IQ1exp(_iq1 A);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Computes the exponential of a global IQ format input.\n *\n * @param A               Global IQ format input.\n *\n * @return                Global IQ type result of exponential.\n */\n#if GLOBAL_IQ == 30\n#define _IQexp(A)               _IQ30exp(A)\n#endif\n#if GLOBAL_IQ == 29\n#define _IQexp(A)               _IQ29exp(A)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQexp(A)               _IQ28exp(A)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQexp(A)               _IQ27exp(A)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQexp(A)               _IQ26exp(A)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQexp(A)               _IQ25exp(A)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQexp(A)               _IQ24exp(A)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQexp(A)               _IQ23exp(A)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQexp(A)               _IQ22exp(A)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQexp(A)               _IQ21exp(A)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQexp(A)               _IQ20exp(A)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQexp(A)               _IQ19exp(A)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQexp(A)               _IQ18exp(A)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQexp(A)               _IQ17exp(A)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQexp(A)               _IQ16exp(A)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQexp(A)               _IQ15exp(A)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQexp(A)               _IQ14exp(A)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQexp(A)               _IQ13exp(A)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQexp(A)               _IQ12exp(A)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQexp(A)               _IQ11exp(A)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQexp(A)               _IQ10exp(A)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQexp(A)               _IQ9exp(A)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQexp(A)               _IQ8exp(A)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQexp(A)               _IQ7exp(A)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQexp(A)               _IQ6exp(A)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQexp(A)               _IQ5exp(A)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQexp(A)               _IQ4exp(A)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQexp(A)               _IQ3exp(A)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQexp(A)               _IQ2exp(A)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQexp(A)               _IQ1exp(A)\n#endif\n\n//*****************************************************************************\n//\n// Computes log(x) of an IQ number.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern _iq30 _IQ30log(_iq30 A);\nextern _iq29 _IQ29log(_iq29 A);\nextern _iq28 _IQ28log(_iq28 A);\nextern _iq27 _IQ27log(_iq27 A);\nextern _iq26 _IQ26log(_iq26 A);\nextern _iq25 _IQ25log(_iq25 A);\nextern _iq24 _IQ24log(_iq24 A);\nextern _iq23 _IQ23log(_iq23 A);\nextern _iq22 _IQ22log(_iq22 A);\nextern _iq21 _IQ21log(_iq21 A);\nextern _iq20 _IQ20log(_iq20 A);\nextern _iq19 _IQ19log(_iq19 A);\nextern _iq18 _IQ18log(_iq18 A);\nextern _iq17 _IQ17log(_iq17 A);\nextern _iq16 _IQ16log(_iq16 A);\nextern _iq15 _IQ15log(_iq15 A);\nextern _iq14 _IQ14log(_iq14 A);\nextern _iq13 _IQ13log(_iq13 A);\nextern _iq12 _IQ12log(_iq12 A);\nextern _iq11 _IQ11log(_iq11 A);\nextern _iq10 _IQ10log(_iq10 A);\nextern _iq9 _IQ9log(_iq9 A);\nextern _iq8 _IQ8log(_iq8 A);\nextern _iq7 _IQ7log(_iq7 A);\nextern _iq6 _IQ6log(_iq6 A);\nextern _iq5 _IQ5log(_iq5 A);\nextern _iq4 _IQ4log(_iq4 A);\nextern _iq3 _IQ3log(_iq3 A);\nextern _iq2 _IQ2log(_iq2 A);\nextern _iq1 _IQ1log(_iq1 A);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Computes the base-e logarithm of a global IQ format input.\n *\n * @param A               Global IQ format input.\n *\n * @return                Global IQ type result of base-e logarithm.\n */\n#if GLOBAL_IQ == 30\n#define _IQlog(A)               _IQ30log(A)\n#endif\n#if GLOBAL_IQ == 29\n#define _IQlog(A)               _IQ29log(A)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQlog(A)               _IQ28log(A)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQlog(A)               _IQ27log(A)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQlog(A)               _IQ26log(A)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQlog(A)               _IQ25log(A)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQlog(A)               _IQ24log(A)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQlog(A)               _IQ23log(A)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQlog(A)               _IQ22log(A)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQlog(A)               _IQ21log(A)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQlog(A)               _IQ20log(A)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQlog(A)               _IQ19log(A)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQlog(A)               _IQ18log(A)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQlog(A)               _IQ17log(A)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQlog(A)               _IQ16log(A)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQlog(A)               _IQ15log(A)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQlog(A)               _IQ14log(A)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQlog(A)               _IQ13log(A)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQlog(A)               _IQ12log(A)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQlog(A)               _IQ11log(A)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQlog(A)               _IQ10log(A)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQlog(A)               _IQ9log(A)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQlog(A)               _IQ8log(A)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQlog(A)               _IQ7log(A)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQlog(A)               _IQ6log(A)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQlog(A)               _IQ5log(A)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQlog(A)               _IQ4log(A)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQlog(A)               _IQ3log(A)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQlog(A)               _IQ2log(A)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQlog(A)               _IQ1log(A)\n#endif\n\n//*****************************************************************************\n//\n// Returns the integer portion of an IQ number.\n//\n//*****************************************************************************\n/**\n * @brief Returns the integer portion of an IQ30 type number.\n *\n * @param A               IQ30 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ30int(A)             ((A) >> 30)\n/**\n * @brief Returns the integer portion of an IQ29 type number.\n *\n * @param A               IQ29 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ29int(A)             ((A) >> 29)\n/**\n * @brief Returns the integer portion of an IQ28 type number.\n *\n * @param A               IQ28 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ28int(A)             ((A) >> 28)\n/**\n * @brief Returns the integer portion of an IQ27 type number.\n *\n * @param A               IQ27 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ27int(A)             ((A) >> 27)\n/**\n * @brief Returns the integer portion of an IQ26 type number.\n *\n * @param A               IQ26 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ26int(A)             ((A) >> 26)\n/**\n * @brief Returns the integer portion of an IQ25 type number.\n *\n * @param A               IQ25 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ25int(A)             ((A) >> 25)\n/**\n * @brief Returns the integer portion of an IQ24 type number.\n *\n * @param A               IQ24 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ24int(A)             ((A) >> 24)\n/**\n * @brief Returns the integer portion of an IQ23 type number.\n *\n * @param A               IQ23 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ23int(A)             ((A) >> 23)\n/**\n * @brief Returns the integer portion of an IQ22 type number.\n *\n * @param A               IQ22 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ22int(A)             ((A) >> 22)\n/**\n * @brief Returns the integer portion of an IQ21 type number.\n *\n * @param A               IQ21 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ21int(A)             ((A) >> 21)\n/**\n * @brief Returns the integer portion of an IQ20 type number.\n *\n * @param A               IQ20 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ20int(A)             ((A) >> 20)\n/**\n * @brief Returns the integer portion of an IQ19 type number.\n *\n * @param A               IQ19 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ19int(A)             ((A) >> 19)\n/**\n * @brief Returns the integer portion of an IQ18 type number.\n *\n * @param A               IQ18 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ18int(A)             ((A) >> 18)\n/**\n * @brief Returns the integer portion of an IQ17 type number.\n *\n * @param A               IQ17 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ17int(A)             ((A) >> 17)\n/**\n * @brief Returns the integer portion of an IQ16 type number.\n *\n * @param A               IQ16 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ16int(A)             ((A) >> 16)\n/**\n * @brief Returns the integer portion of an IQ15 type number.\n *\n * @param A               IQ15 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ15int(A)             ((A) >> 15)\n/**\n * @brief Returns the integer portion of an IQ14 type number.\n *\n * @param A               IQ14 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ14int(A)             ((A) >> 14)\n/**\n * @brief Returns the integer portion of an IQ13 type number.\n *\n * @param A               IQ13 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ13int(A)             ((A) >> 13)\n/**\n * @brief Returns the integer portion of an IQ12 type number.\n *\n * @param A               IQ12 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ12int(A)             ((A) >> 12)\n/**\n * @brief Returns the integer portion of an IQ11 type number.\n *\n * @param A               IQ11 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ11int(A)             ((A) >> 11)\n/**\n * @brief Returns the integer portion of an IQ10 type number.\n *\n * @param A               IQ10 type input.\n *\n * @return                Iinteger portion of input.\n */\n#define _IQ10int(A)             ((A) >> 10)\n/**\n * @brief Returns the integer portion of an IQ9 type number.\n *\n * @param A               IQ9 type input.\n *\n * @return                Integer portion of input.\n */\n#define _IQ9int(A)              ((A) >> 9)\n/**\n * @brief Returns the integer portion of an IQ8 type number.\n *\n * @param A               IQ8 type input.\n *\n * @return                Integer portion of input.\n */\n#define _IQ8int(A)              ((A) >> 8)\n/**\n * @brief Returns the integer portion of an IQ7 type number.\n *\n * @param A               IQ7 type input.\n *\n * @return                Integer portion of input.\n */\n#define _IQ7int(A)              ((A) >> 7)\n/**\n * @brief Returns the integer portion of an IQ6 type number.\n *\n * @param A               IQ6 type input.\n *\n * @return                Integer portion of input.\n */\n#define _IQ6int(A)              ((A) >> 6)\n/**\n * @brief Returns the integer portion of an IQ5 type number.\n *\n * @param A               IQ5 type input.\n *\n * @return                Integer portion of input.\n */\n#define _IQ5int(A)              ((A) >> 5)\n/**\n * @brief Returns the integer portion of an IQ4 type number.\n *\n * @param A               IQ4 type input.\n *\n * @return                Integer portion of input.\n */\n#define _IQ4int(A)              ((A) >> 4)\n/**\n * @brief Returns the integer portion of an IQ3 type number.\n *\n * @param A               IQ3 type input.\n *\n * @return                Integer portion of input.\n */\n#define _IQ3int(A)              ((A) >> 3)\n/**\n * @brief Returns the integer portion of an IQ2 type number.\n *\n * @param A               IQ2 type input.\n *\n * @return                Integer portion of input.\n */\n#define _IQ2int(A)              ((A) >> 2)\n/**\n * @brief Returns the integer portion of an IQ1 type number.\n *\n * @param A               IQ1 type input.\n *\n * @return                Integer portion of input.\n */\n#define _IQ1int(A)              ((A) >> 1)\n/**\n * @brief Returns the integer portion of a global IQ format number.\n *\n * @param A               Global IQ format input.\n *\n * @return                Integer portion of input.\n */\n#define _IQint(A)               ((A) >> GLOBAL_IQ)\n\n//*****************************************************************************\n//\n// Computes the fractional portion of an IQ number.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern _iq30 _IQ30frac(_iq30 A);\nextern _iq29 _IQ29frac(_iq29 A);\nextern _iq28 _IQ28frac(_iq28 A);\nextern _iq27 _IQ27frac(_iq27 A);\nextern _iq26 _IQ26frac(_iq26 A);\nextern _iq25 _IQ25frac(_iq25 A);\nextern _iq24 _IQ24frac(_iq24 A);\nextern _iq23 _IQ23frac(_iq23 A);\nextern _iq22 _IQ22frac(_iq22 A);\nextern _iq21 _IQ21frac(_iq21 A);\nextern _iq20 _IQ20frac(_iq20 A);\nextern _iq19 _IQ19frac(_iq19 A);\nextern _iq18 _IQ18frac(_iq18 A);\nextern _iq17 _IQ17frac(_iq17 A);\nextern _iq16 _IQ16frac(_iq16 A);\nextern _iq15 _IQ15frac(_iq15 A);\nextern _iq14 _IQ14frac(_iq14 A);\nextern _iq13 _IQ13frac(_iq13 A);\nextern _iq12 _IQ12frac(_iq12 A);\nextern _iq11 _IQ11frac(_iq11 A);\nextern _iq10 _IQ10frac(_iq10 A);\nextern _iq9 _IQ9frac(_iq9 A);\nextern _iq8 _IQ8frac(_iq8 A);\nextern _iq7 _IQ7frac(_iq7 A);\nextern _iq6 _IQ6frac(_iq6 A);\nextern _iq5 _IQ5frac(_iq5 A);\nextern _iq4 _IQ4frac(_iq4 A);\nextern _iq3 _IQ3frac(_iq3 A);\nextern _iq2 _IQ2frac(_iq2 A);\nextern _iq1 _IQ1frac(_iq1 A);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Computes the fractional portion a global IQ format number.\n *\n * @param A               Global IQ format input.\n *\n * @return                Global IQ format fractional portion of input.\n */\n#if GLOBAL_IQ == 30\n#define _IQfrac(A)              _IQ30frac(A)\n#endif\n#if GLOBAL_IQ == 29\n#define _IQfrac(A)              _IQ29frac(A)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQfrac(A)              _IQ28frac(A)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQfrac(A)              _IQ27frac(A)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQfrac(A)              _IQ26frac(A)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQfrac(A)              _IQ25frac(A)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQfrac(A)              _IQ24frac(A)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQfrac(A)              _IQ23frac(A)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQfrac(A)              _IQ22frac(A)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQfrac(A)              _IQ21frac(A)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQfrac(A)              _IQ20frac(A)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQfrac(A)              _IQ19frac(A)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQfrac(A)              _IQ18frac(A)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQfrac(A)              _IQ17frac(A)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQfrac(A)              _IQ16frac(A)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQfrac(A)              _IQ15frac(A)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQfrac(A)              _IQ14frac(A)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQfrac(A)              _IQ13frac(A)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQfrac(A)              _IQ12frac(A)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQfrac(A)              _IQ11frac(A)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQfrac(A)              _IQ10frac(A)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQfrac(A)              _IQ9frac(A)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQfrac(A)              _IQ8frac(A)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQfrac(A)              _IQ7frac(A)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQfrac(A)              _IQ6frac(A)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQfrac(A)              _IQ5frac(A)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQfrac(A)              _IQ4frac(A)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQfrac(A)              _IQ3frac(A)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQfrac(A)              _IQ2frac(A)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQfrac(A)              _IQ1frac(A)\n#endif\n\n//*****************************************************************************\n//\n// Multiplies two IQ numbers in the specified iQ formats, returning the result\n// in another IQ format.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern int32_t _IQ30mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ29mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ28mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ27mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ26mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ25mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ24mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ23mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ22mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ21mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ20mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ19mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ18mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ17mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ16mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ15mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ14mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ13mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ12mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ11mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ10mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ9mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ8mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ7mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ6mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ5mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ4mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ3mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ2mpyIQX(int32_t A, int n1, int32_t B, int n2);\nextern int32_t _IQ1mpyIQX(int32_t A, int n1, int32_t B, int n2);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Multiply two IQ numbers in different IQ formats,\n * returning the product in global IQ format.\n *\n * @param A               IQN1 format input to be multiplied.\n * @param n1              IQ format for first value.\n * @param B               IQN2 format input to be multiplied.\n * @param n2              IQ format for second value.\n *\n *\n * @return                Global IQ format result of the multiplication.\n */\n#if GLOBAL_IQ == 30\n#define _IQmpyIQX(A, n1, B, n2)              _IQ30mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 29\n#define _IQmpyIQX(A, n1, B, n2)               _IQ29mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQmpyIQX(A, n1, B, n2)              _IQ28mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQmpyIQX(A, n1, B, n2)              _IQ27mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQmpyIQX(A, n1, B, n2)              _IQ26mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQmpyIQX(A, n1, B, n2)              _IQ25mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQmpyIQX(A, n1, B, n2)              _IQ24mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQmpyIQX(A, n1, B, n2)              _IQ23mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQmpyIQX(A, n1, B, n2)              _IQ22mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQmpyIQX(A, n1, B, n2)              _IQ21mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQmpyIQX(A, n1, B, n2)              _IQ20mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQmpyIQX(A, n1, B, n2)              _IQ19mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQmpyIQX(A, n1, B, n2)              _IQ18mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQmpyIQX(A, n1, B, n2)              _IQ17mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQmpyIQX(A, n1, B, n2)              _IQ16mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQmpyIQX(A, n1, B, n2)              _IQ15mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQmpyIQX(A, n1, B, n2)              _IQ14mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQmpyIQX(A, n1, B, n2)              _IQ13mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQmpyIQX(A, n1, B, n2)              _IQ12mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQmpyIQX(A, n1, B, n2)              _IQ11mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQmpyIQX(A, n1, B, n2)              _IQ10mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQmpyIQX(A, n1, B, n2)              _IQ9mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQmpyIQX(A, n1, B, n2)              _IQ8mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQmpyIQX(A, n1, B, n2)              _IQ7mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQmpyIQX(A, n1, B, n2)              _IQ6mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQmpyIQX(A, n1, B, n2)              _IQ5mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQmpyIQX(A, n1, B, n2)              _IQ4mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQmpyIQX(A, n1, B, n2)              _IQ3mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQmpyIQX(A, n1, B, n2)              _IQ2mpyIQX(A, n1, B, n2)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQmpyIQX(A, n1, B, n2)              _IQ1mpyIQX(A, n1, B, n2)\n#endif\n\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\n//*****************************************************************************\n//\n// Multiplies an IQ number by an integer.\n//\n//*****************************************************************************\n#define _IQ30mpyI32(A, B)       ((A) * (B))\n#define _IQ29mpyI32(A, B)       ((A) * (B))\n#define _IQ28mpyI32(A, B)       ((A) * (B))\n#define _IQ27mpyI32(A, B)       ((A) * (B))\n#define _IQ26mpyI32(A, B)       ((A) * (B))\n#define _IQ25mpyI32(A, B)       ((A) * (B))\n#define _IQ24mpyI32(A, B)       ((A) * (B))\n#define _IQ23mpyI32(A, B)       ((A) * (B))\n#define _IQ22mpyI32(A, B)       ((A) * (B))\n#define _IQ21mpyI32(A, B)       ((A) * (B))\n#define _IQ20mpyI32(A, B)       ((A) * (B))\n#define _IQ19mpyI32(A, B)       ((A) * (B))\n#define _IQ18mpyI32(A, B)       ((A) * (B))\n#define _IQ17mpyI32(A, B)       ((A) * (B))\n#define _IQ16mpyI32(A, B)       ((A) * (B))\n#define _IQ15mpyI32(A, B)       ((A) * (B))\n#define _IQ14mpyI32(A, B)       ((A) * (B))\n#define _IQ13mpyI32(A, B)       ((A) * (B))\n#define _IQ12mpyI32(A, B)       ((A) * (B))\n#define _IQ11mpyI32(A, B)       ((A) * (B))\n#define _IQ10mpyI32(A, B)       ((A) * (B))\n#define _IQ9mpyI32(A, B)        ((A) * (B))\n#define _IQ8mpyI32(A, B)        ((A) * (B))\n#define _IQ7mpyI32(A, B)        ((A) * (B))\n#define _IQ6mpyI32(A, B)        ((A) * (B))\n#define _IQ5mpyI32(A, B)        ((A) * (B))\n#define _IQ4mpyI32(A, B)        ((A) * (B))\n#define _IQ3mpyI32(A, B)        ((A) * (B))\n#define _IQ2mpyI32(A, B)        ((A) * (B))\n#define _IQ1mpyI32(A, B)        ((A) * (B))\n#define _IQmpyI32(A, B)         ((A) * (B))\n\n//*****************************************************************************\n//\n// Multiplies an IQ number by an integer, and returns the integer portion.\n//\n//*****************************************************************************\n#define _IQ30mpyI32int(A, B)   _IQ30int(_IQ30mpyI32(A, B))\n#define _IQ29mpyI32int(A, B)   _IQ29int(_IQ29mpyI32(A, B))\n#define _IQ28mpyI32int(A, B)   _IQ28int(_IQ28mpyI32(A, B))\n#define _IQ27mpyI32int(A, B)   _IQ27int(_IQ27mpyI32(A, B))\n#define _IQ26mpyI32int(A, B)   _IQ26int(_IQ26mpyI32(A, B))\n#define _IQ25mpyI32int(A, B)   _IQ25int(_IQ25mpyI32(A, B))\n#define _IQ24mpyI32int(A, B)   _IQ24int(_IQ24mpyI32(A, B))\n#define _IQ23mpyI32int(A, B)   _IQ23int(_IQ23mpyI32(A, B))\n#define _IQ22mpyI32int(A, B)   _IQ22int(_IQ22mpyI32(A, B))\n#define _IQ21mpyI32int(A, B)   _IQ21int(_IQ21mpyI32(A, B))\n#define _IQ20mpyI32int(A, B)   _IQ20int(_IQ20mpyI32(A, B))\n#define _IQ19mpyI32int(A, B)   _IQ19int(_IQ19mpyI32(A, B))\n#define _IQ18mpyI32int(A, B)   _IQ18int(_IQ18mpyI32(A, B))\n#define _IQ17mpyI32int(A, B)   _IQ17int(_IQ17mpyI32(A, B))\n#define _IQ16mpyI32int(A, B)   _IQ16int(_IQ16mpyI32(A, B))\n#define _IQ15mpyI32int(A, B)   _IQ15int(_IQ15mpyI32(A, B))\n#define _IQ14mpyI32int(A, B)   _IQ14int(_IQ14mpyI32(A, B))\n#define _IQ13mpyI32int(A, B)   _IQ13int(_IQ13mpyI32(A, B))\n#define _IQ12mpyI32int(A, B)   _IQ12int(_IQ12mpyI32(A, B))\n#define _IQ11mpyI32int(A, B)   _IQ11int(_IQ11mpyI32(A, B))\n#define _IQ10mpyI32int(A, B)   _IQ10int(_IQ10mpyI32(A, B))\n#define _IQ9mpyI32int(A, B)   _IQ9int(_IQ9mpyI32(A, B))\n#define _IQ8mpyI32int(A, B)   _IQ8int(_IQ8mpyI32(A, B))\n#define _IQ7mpyI32int(A, B)   _IQ7int(_IQ7mpyI32(A, B))\n#define _IQ6mpyI32int(A, B)   _IQ6int(_IQ6mpyI32(A, B))\n#define _IQ5mpyI32int(A, B)   _IQ5int(_IQ5mpyI32(A, B))\n#define _IQ4mpyI32int(A, B)   _IQ4int(_IQ4mpyI32(A, B))\n#define _IQ3mpyI32int(A, B)   _IQ3int(_IQ3mpyI32(A, B))\n#define _IQ2mpyI32int(A, B)   _IQ2int(_IQ2mpyI32(A, B))\n#define _IQ1mpyI32int(A, B)   _IQ1int(_IQ1mpyI32(A, B))\n\n#if GLOBAL_IQ == 30\n#define _IQmpyI32int(A, B)      _IQ30mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 29\n#define _IQmpyI32int(A, B)      _IQ29mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQmpyI32int(A, B)      _IQ28mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQmpyI32int(A, B)      _IQ27mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQmpyI32int(A, B)      _IQ26mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQmpyI32int(A, B)      _IQ25mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQmpyI32int(A, B)      _IQ24mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQmpyI32int(A, B)      _IQ23mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQmpyI32int(A, B)      _IQ22mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQmpyI32int(A, B)      _IQ21mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQmpyI32int(A, B)      _IQ20mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQmpyI32int(A, B)      _IQ19mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQmpyI32int(A, B)      _IQ18mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQmpyI32int(A, B)      _IQ17mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQmpyI32int(A, B)      _IQ16mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQmpyI32int(A, B)      _IQ15mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQmpyI32int(A, B)      _IQ14mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQmpyI32int(A, B)      _IQ13mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQmpyI32int(A, B)      _IQ12mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQmpyI32int(A, B)      _IQ11mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQmpyI32int(A, B)      _IQ10mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQmpyI32int(A, B)      _IQ9mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQmpyI32int(A, B)      _IQ8mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQmpyI32int(A, B)      _IQ7mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQmpyI32int(A, B)      _IQ6mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQmpyI32int(A, B)      _IQ5mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQmpyI32int(A, B)      _IQ4mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQmpyI32int(A, B)      _IQ3mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQmpyI32int(A, B)      _IQ2mpyI32int(A, B)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQmpyI32int(A, B)      _IQ1mpyI32int(A, B)\n#endif\n\n//*****************************************************************************\n//\n// Multiplies an IQ number by an integer, and returns the fractional portion.\n//\n//*****************************************************************************\n#define _IQ30mpyI32frac(A, B)   _IQ30frac(_IQ30mpyI32(A, B))\n#define _IQ29mpyI32frac(A, B)   _IQ29frac(_IQ29mpyI32(A, B))\n#define _IQ28mpyI32frac(A, B)   _IQ28frac(_IQ28mpyI32(A, B))\n#define _IQ27mpyI32frac(A, B)   _IQ27frac(_IQ27mpyI32(A, B))\n#define _IQ26mpyI32frac(A, B)   _IQ26frac(_IQ26mpyI32(A, B))\n#define _IQ25mpyI32frac(A, B)   _IQ25frac(_IQ25mpyI32(A, B))\n#define _IQ24mpyI32frac(A, B)   _IQ24frac(_IQ24mpyI32(A, B))\n#define _IQ23mpyI32frac(A, B)   _IQ23frac(_IQ23mpyI32(A, B))\n#define _IQ22mpyI32frac(A, B)   _IQ22frac(_IQ22mpyI32(A, B))\n#define _IQ21mpyI32frac(A, B)   _IQ21frac(_IQ21mpyI32(A, B))\n#define _IQ20mpyI32frac(A, B)   _IQ20frac(_IQ20mpyI32(A, B))\n#define _IQ19mpyI32frac(A, B)   _IQ19frac(_IQ19mpyI32(A, B))\n#define _IQ18mpyI32frac(A, B)   _IQ18frac(_IQ18mpyI32(A, B))\n#define _IQ17mpyI32frac(A, B)   _IQ17frac(_IQ17mpyI32(A, B))\n#define _IQ16mpyI32frac(A, B)   _IQ16frac(_IQ16mpyI32(A, B))\n#define _IQ15mpyI32frac(A, B)   _IQ15frac(_IQ15mpyI32(A, B))\n#define _IQ14mpyI32frac(A, B)   _IQ14frac(_IQ14mpyI32(A, B))\n#define _IQ13mpyI32frac(A, B)   _IQ13frac(_IQ13mpyI32(A, B))\n#define _IQ12mpyI32frac(A, B)   _IQ12frac(_IQ12mpyI32(A, B))\n#define _IQ11mpyI32frac(A, B)   _IQ11frac(_IQ11mpyI32(A, B))\n#define _IQ10mpyI32frac(A, B)   _IQ10frac(_IQ10mpyI32(A, B))\n#define _IQ9mpyI32frac(A, B)   _IQ9frac(_IQ9mpyI32(A, B))\n#define _IQ8mpyI32frac(A, B)   _IQ8frac(_IQ8mpyI32(A, B))\n#define _IQ7mpyI32frac(A, B)   _IQ7frac(_IQ7mpyI32(A, B))\n#define _IQ6mpyI32frac(A, B)   _IQ6frac(_IQ6mpyI32(A, B))\n#define _IQ5mpyI32frac(A, B)   _IQ5frac(_IQ5mpyI32(A, B))\n#define _IQ4mpyI32frac(A, B)   _IQ4frac(_IQ4mpyI32(A, B))\n#define _IQ3mpyI32frac(A, B)   _IQ3frac(_IQ3mpyI32(A, B))\n#define _IQ2mpyI32frac(A, B)   _IQ2frac(_IQ2mpyI32(A, B))\n#define _IQ1mpyI32frac(A, B)   _IQ1frac(_IQ1mpyI32(A, B))\n\n#if GLOBAL_IQ == 30\n#define _IQmpyI32frac(A, B)     _IQ30mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 29\n#define _IQmpyI32frac(A, B)     _IQ29mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQmpyI32frac(A, B)     _IQ28mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQmpyI32frac(A, B)     _IQ27mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQmpyI32frac(A, B)     _IQ26mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQmpyI32frac(A, B)     _IQ25mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQmpyI32frac(A, B)     _IQ24mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQmpyI32frac(A, B)     _IQ23mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQmpyI32frac(A, B)     _IQ22mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQmpyI32frac(A, B)     _IQ21mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQmpyI32frac(A, B)     _IQ20mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQmpyI32frac(A, B)     _IQ19mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQmpyI32frac(A, B)     _IQ18mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQmpyI32frac(A, B)     _IQ17mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQmpyI32frac(A, B)     _IQ16mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQmpyI32frac(A, B)     _IQ15mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQmpyI32frac(A, B)     _IQ14mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQmpyI32frac(A, B)     _IQ13mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQmpyI32frac(A, B)     _IQ12mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQmpyI32frac(A, B)     _IQ11mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQmpyI32frac(A, B)     _IQ10mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQmpyI32frac(A, B)     _IQ9mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQmpyI32frac(A, B)     _IQ8mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQmpyI32frac(A, B)     _IQ7mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQmpyI32frac(A, B)     _IQ6mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQmpyI32frac(A, B)     _IQ5mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQmpyI32frac(A, B)     _IQ4mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQmpyI32frac(A, B)     _IQ3mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQmpyI32frac(A, B)     _IQ2mpyI32frac(A, B)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQmpyI32frac(A, B)     _IQ1mpyI32frac(A, B)\n#endif\n\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n//*****************************************************************************\n//\n// Computes the square root of A^2 + B^2 using IQ numbers.\n//\n//*****************************************************************************\nextern int32_t _IQmag(int32_t A, int32_t B);\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ30 numbers.\n *\n * @param A               IQ30 type input.\n * @param B               IQ30 type input\n *\n * @return                IQ30 result of magnitude operation.\n */\n#define _IQ30mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ29 numbers.\n *\n * @param A               IQ29 type input.\n * @param B               IQ29 type input\n *\n * @return                IQ29 result of magnitude operation.\n */\n#define _IQ29mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ28 numbers.\n *\n * @param A               IQ28 type input.\n * @param B               IQ28 type input\n *\n * @return                IQ28 result of magnitude operation.\n */\n#define _IQ28mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ27 numbers.\n *\n * @param A               IQ27 type input.\n * @param B               IQ27 type input\n *\n * @return                IQ27 result of magnitude operation.\n */\n#define _IQ27mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ26 numbers.\n *\n * @param A               IQ26 type input.\n * @param B               IQ26 type input\n *\n * @return                IQ26 result of magnitude operation.\n */\n#define _IQ26mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ25 numbers.\n *\n * @param A               IQ25 type input.\n * @param B               IQ25 type input\n *\n * @return                IQ25 result of magnitude operation.\n */\n#define _IQ25mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ24 numbers.\n *\n * @param A               IQ24 type input.\n * @param B               IQ24 type input\n *\n * @return                IQ24 result of magnitude operation.\n */\n#define _IQ24mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ23 numbers.\n *\n * @param A               IQ23 type input.\n * @param B               IQ23 type input\n *\n * @return                IQ23 result of magnitude operation.\n */\n#define _IQ23mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ22 numbers.\n *\n * @param A               IQ22 type input.\n * @param B               IQ22 type input\n *\n * @return                IQ22 result of magnitude operation.\n */\n#define _IQ22mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ21 numbers.\n *\n * @param A               IQ21 type input.\n * @param B               IQ21 type input\n *\n * @return                IQ21 result of magnitude operation.\n */\n#define _IQ21mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ20 numbers.\n *\n * @param A               IQ20 type input.\n * @param B               IQ20 type input\n *\n * @return                IQ20 result of magnitude operation.\n */\n#define _IQ20mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ19 numbers.\n *\n * @param A               IQ19 type input.\n * @param B               IQ19 type input\n *\n * @return                IQ19 result of magnitude operation.\n */\n#define _IQ19mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ18 numbers.\n *\n * @param A               IQ18 type input.\n * @param B               IQ18 type input\n *\n * @return                IQ18 result of magnitude operation.\n */\n#define _IQ18mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ17 numbers.\n *\n * @param A               IQ17 type input.\n * @param B               IQ17 type input\n *\n * @return                IQ17 result of magnitude operation.\n */\n#define _IQ17mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ16 numbers.\n *\n * @param A               IQ16 type input.\n * @param B               IQ16 type input\n *\n * @return                IQ16 result of magnitude operation.\n */\n#define _IQ16mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ15 numbers.\n *\n * @param A               IQ15 type input.\n * @param B               IQ15 type input\n *\n * @return                IQ15 result of magnitude operation.\n */\n#define _IQ15mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ14 numbers.\n *\n * @param A               IQ14 type input.\n * @param B               IQ14 type input\n *\n * @return                IQ14 result of magnitude operation.\n */\n#define _IQ14mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ13 numbers.\n *\n * @param A               IQ13 type input.\n * @param B               IQ13 type input\n *\n * @return                IQ13 result of magnitude operation.\n */\n#define _IQ13mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ12 numbers.\n *\n * @param A               IQ12 type input.\n * @param B               IQ12 type input\n *\n * @return                IQ12 result of magnitude operation.\n */\n#define _IQ12mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ11 numbers.\n *\n * @param A               IQ11 type input.\n * @param B               IQ11 type input\n *\n * @return                IQ11 result of magnitude operation.\n */\n#define _IQ11mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ10 numbers.\n *\n * @param A               IQ10 type input.\n * @param B               IQ10 type input\n *\n * @return                IQ10 result of magnitude operation.\n */\n#define _IQ10mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ9 numbers.\n *\n * @param A               IQ9 type input.\n * @param B               IQ9 type input\n *\n * @return                IQ9 result of magnitude operation.\n */\n#define _IQ9mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ8 numbers.\n *\n * @param A               IQ8 type input.\n * @param B               IQ8 type input\n *\n * @return                IQ8 result of magnitude operation.\n */\n#define _IQ8mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ7 numbers.\n *\n * @param A               IQ7 type input.\n * @param B               IQ7 type input\n *\n * @return                IQ7 result of magnitude operation.\n */\n#define _IQ7mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ6 numbers.\n *\n * @param A               IQ6 type input.\n * @param B               IQ6 type input\n *\n * @return                IQ6 result of magnitude operation.\n */\n#define _IQ6mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ5 numbers.\n *\n * @param A               IQ5 type input.\n * @param B               IQ5 type input\n *\n * @return                IQ5 result of magnitude operation.\n */\n#define _IQ5mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ4 numbers.\n *\n * @param A               IQ4 type input.\n * @param B               IQ4 type input\n *\n * @return                IQ4 result of magnitude operation.\n */\n#define _IQ4mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ3 numbers.\n *\n * @param A               IQ3 type input.\n * @param B               IQ3 type input\n *\n * @return                IQ3 result of magnitude operation.\n */\n#define _IQ3mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ2 numbers.\n *\n * @param A               IQ2 type input.\n * @param B               IQ2 type input\n *\n * @return                IQ2 result of magnitude operation.\n */\n#define _IQ2mag(A, B)             _IQmag(A, B)\n/**\n * @brief Computes the square root of A^2 + B^2 using IQ1 numbers.\n *\n * @param A               IQ1 type input.\n * @param B               IQ1 type input\n *\n * @return                IQ1 result of magnitude operation.\n */\n#define _IQ1mag(A, B)             _IQmag(A, B)\n\n//*****************************************************************************\n//\n// Computes the inverse square root of A^2 + B^2 using IQ numbers.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern _iq29 _IQ30imag(_iq30 A, _iq30 B);\nextern _iq29 _IQ29imag(_iq29 A, _iq29 B);\nextern _iq28 _IQ28imag(_iq28 A, _iq28 B);\nextern _iq27 _IQ27imag(_iq27 A, _iq27 B);\nextern _iq26 _IQ26imag(_iq26 A, _iq26 B);\nextern _iq25 _IQ25imag(_iq25 A, _iq25 B);\nextern _iq24 _IQ24imag(_iq24 A, _iq24 B);\nextern _iq23 _IQ23imag(_iq23 A, _iq23 B);\nextern _iq22 _IQ22imag(_iq22 A, _iq22 B);\nextern _iq21 _IQ21imag(_iq21 A, _iq21 B);\nextern _iq20 _IQ20imag(_iq20 A, _iq20 B);\nextern _iq19 _IQ19imag(_iq19 A, _iq19 B);\nextern _iq18 _IQ18imag(_iq18 A, _iq18 B);\nextern _iq17 _IQ17imag(_iq17 A, _iq17 B);\nextern _iq16 _IQ16imag(_iq16 A, _iq16 B);\nextern _iq15 _IQ15imag(_iq15 A, _iq15 B);\nextern _iq14 _IQ14imag(_iq14 A, _iq14 B);\nextern _iq13 _IQ13imag(_iq13 A, _iq13 B);\nextern _iq12 _IQ12imag(_iq12 A, _iq12 B);\nextern _iq11 _IQ11imag(_iq11 A, _iq11 B);\nextern _iq10 _IQ10imag(_iq10 A, _iq10 B);\nextern _iq9 _IQ9imag(_iq9 A, _iq9 B);\nextern _iq8 _IQ8imag(_iq8 A, _iq8 B);\nextern _iq7 _IQ7imag(_iq7 A, _iq7 B);\nextern _iq6 _IQ6imag(_iq6 A, _iq6 B);\nextern _iq5 _IQ5imag(_iq5 A, _iq5 B);\nextern _iq4 _IQ4imag(_iq4 A, _iq4 B);\nextern _iq3 _IQ3imag(_iq3 A, _iq3 B);\nextern _iq2 _IQ2imag(_iq2 A, _iq2 B);\nextern _iq1 _IQ1imag(_iq1 A, _iq1 B);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Computes the inverse square root of A^2 + B^2 using IQ1 numbers.\n *\n * @param A               Global IQ format input.\n * @param B               Global IQ format input\n *\n * @return                Global IQ  format result of inverse\n *                        magnitude operation.\n */\n#if GLOBAL_IQ == 30\n#define _IQimag(A, B)          _IQ30imag(A, B)\n#endif\n#if GLOBAL_IQ == 29\n#define _IQimag(A, B)          _IQ29imag(A, B)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQimag(A, B)          _IQ28imag(A, B)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQimag(A, B)          _IQ27imag(A, B)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQimag(A, B)          _IQ26imag(A, B)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQimag(A, B)          _IQ25imag(A, B)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQimag(A, B)          _IQ24imag(A, B)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQimag(A, B)          _IQ23imag(A, B)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQimag(A, B)          _IQ22imag(A, B)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQimag(A, B)          _IQ21imag(A, B)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQimag(A, B)          _IQ20imag(A, B)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQimag(A, B)          _IQ19imag(A, B)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQimag(A, B)          _IQ18imag(A, B)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQimag(A, B)          _IQ17imag(A, B)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQimag(A, B)          _IQ16imag(A, B)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQimag(A, B)          _IQ15imag(A, B)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQimag(A, B)          _IQ14imag(A, B)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQimag(A, B)          _IQ13imag(A, B)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQimag(A, B)          _IQ12imag(A, B)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQimag(A, B)          _IQ11imag(A, B)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQimag(A, B)          _IQ10imag(A, B)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQimag(A, B)          _IQ9imag(A, B)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQimag(A, B)          _IQ8imag(A, B)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQimag(A, B)          _IQ7imag(A, B)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQimag(A, B)          _IQ6imag(A, B)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQimag(A, B)          _IQ5imag(A, B)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQimag(A, B)          _IQ4imag(A, B)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQimag(A, B)          _IQ3imag(A, B)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQimag(A, B)          _IQ2imag(A, B)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQimag(A, B)          _IQ1imag(A, B)\n#endif\n\n//*****************************************************************************\n//\n// Converts a string into an IQ number.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern _iq30 _atoIQ30(const char *A);\nextern _iq29 _atoIQ29(const char *A);\nextern _iq28 _atoIQ28(const char *A);\nextern _iq27 _atoIQ27(const char *A);\nextern _iq26 _atoIQ26(const char *A);\nextern _iq25 _atoIQ25(const char *A);\nextern _iq24 _atoIQ24(const char *A);\nextern _iq23 _atoIQ23(const char *A);\nextern _iq22 _atoIQ22(const char *A);\nextern _iq21 _atoIQ21(const char *A);\nextern _iq20 _atoIQ20(const char *A);\nextern _iq19 _atoIQ19(const char *A);\nextern _iq18 _atoIQ18(const char *A);\nextern _iq17 _atoIQ17(const char *A);\nextern _iq16 _atoIQ16(const char *A);\nextern _iq15 _atoIQ15(const char *A);\nextern _iq14 _atoIQ14(const char *A);\nextern _iq13 _atoIQ13(const char *A);\nextern _iq12 _atoIQ12(const char *A);\nextern _iq11 _atoIQ11(const char *A);\nextern _iq10 _atoIQ10(const char *A);\nextern _iq9 _atoIQ9(const char *A);\nextern _iq8 _atoIQ8(const char *A);\nextern _iq7 _atoIQ7(const char *A);\nextern _iq6 _atoIQ6(const char *A);\nextern _iq5 _atoIQ5(const char *A);\nextern _iq4 _atoIQ4(const char *A);\nextern _iq3 _atoIQ3(const char *A);\nextern _iq2 _atoIQ2(const char *A);\nextern _iq1 _atoIQ1(const char *A);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Converts a string into a global IQ format number.\n *\n * @param A               String input.\n *\n * @return                Global IQ  format result of conversion.\n */\n#if GLOBAL_IQ == 30\n#define _atoIQ(A)     _atoIQ30(A)\n#endif\n#if GLOBAL_IQ == 29\n#define _atoIQ(A)     _atoIQ29(A)\n#endif\n#if GLOBAL_IQ == 28\n#define _atoIQ(A)     _atoIQ28(A)\n#endif\n#if GLOBAL_IQ == 27\n#define _atoIQ(A)     _atoIQ27(A)\n#endif\n#if GLOBAL_IQ == 26\n#define _atoIQ(A)     _atoIQ26(A)\n#endif\n#if GLOBAL_IQ == 25\n#define _atoIQ(A)     _atoIQ25(A)\n#endif\n#if GLOBAL_IQ == 24\n#define _atoIQ(A)     _atoIQ24(A)\n#endif\n#if GLOBAL_IQ == 23\n#define _atoIQ(A)     _atoIQ23(A)\n#endif\n#if GLOBAL_IQ == 22\n#define _atoIQ(A)     _atoIQ22(A)\n#endif\n#if GLOBAL_IQ == 21\n#define _atoIQ(A)     _atoIQ21(A)\n#endif\n#if GLOBAL_IQ == 20\n#define _atoIQ(A)     _atoIQ20(A)\n#endif\n#if GLOBAL_IQ == 19\n#define _atoIQ(A)     _atoIQ19(A)\n#endif\n#if GLOBAL_IQ == 18\n#define _atoIQ(A)     _atoIQ18(A)\n#endif\n#if GLOBAL_IQ == 17\n#define _atoIQ(A)     _atoIQ17(A)\n#endif\n#if GLOBAL_IQ == 16\n#define _atoIQ(A)     _atoIQ16(A)\n#endif\n#if GLOBAL_IQ == 15\n#define _atoIQ(A)     _atoIQ15(A)\n#endif\n#if GLOBAL_IQ == 14\n#define _atoIQ(A)     _atoIQ14(A)\n#endif\n#if GLOBAL_IQ == 13\n#define _atoIQ(A)     _atoIQ13(A)\n#endif\n#if GLOBAL_IQ == 12\n#define _atoIQ(A)     _atoIQ12(A)\n#endif\n#if GLOBAL_IQ == 11\n#define _atoIQ(A)     _atoIQ11(A)\n#endif\n#if GLOBAL_IQ == 10\n#define _atoIQ(A)     _atoIQ10(A)\n#endif\n#if GLOBAL_IQ == 9\n#define _atoIQ(A)     _atoIQ9(A)\n#endif\n#if GLOBAL_IQ == 8\n#define _atoIQ(A)     _atoIQ8(A)\n#endif\n#if GLOBAL_IQ == 7\n#define _atoIQ(A)     _atoIQ7(A)\n#endif\n#if GLOBAL_IQ == 6\n#define _atoIQ(A)     _atoIQ6(A)\n#endif\n#if GLOBAL_IQ == 5\n#define _atoIQ(A)     _atoIQ5(A)\n#endif\n#if GLOBAL_IQ == 4\n#define _atoIQ(A)     _atoIQ4(A)\n#endif\n#if GLOBAL_IQ == 3\n#define _atoIQ(A)     _atoIQ3(A)\n#endif\n#if GLOBAL_IQ == 2\n#define _atoIQ(A)     _atoIQ2(A)\n#endif\n#if GLOBAL_IQ == 1\n#define _atoIQ(A)     _atoIQ1(A)\n#endif\n\n//*****************************************************************************\n//\n// Converts an IQ number into a string.\n//\n//*****************************************************************************\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\nextern int16_t _IQ30toa(char *string, const char *format, _iq30 input);\nextern int16_t _IQ29toa(char *string, const char *format, _iq29 input);\nextern int16_t _IQ28toa(char *string, const char *format, _iq28 input);\nextern int16_t _IQ27toa(char *string, const char *format, _iq27 input);\nextern int16_t _IQ26toa(char *string, const char *format, _iq26 input);\nextern int16_t _IQ25toa(char *string, const char *format, _iq25 input);\nextern int16_t _IQ24toa(char *string, const char *format, _iq24 input);\nextern int16_t _IQ23toa(char *string, const char *format, _iq23 input);\nextern int16_t _IQ22toa(char *string, const char *format, _iq22 input);\nextern int16_t _IQ21toa(char *string, const char *format, _iq21 input);\nextern int16_t _IQ20toa(char *string, const char *format, _iq20 input);\nextern int16_t _IQ19toa(char *string, const char *format, _iq19 input);\nextern int16_t _IQ18toa(char *string, const char *format, _iq18 input);\nextern int16_t _IQ17toa(char *string, const char *format, _iq17 input);\nextern int16_t _IQ16toa(char *string, const char *format, _iq16 input);\nextern int16_t _IQ15toa(char *string, const char *format, _iq15 input);\nextern int16_t _IQ14toa(char *string, const char *format, _iq14 input);\nextern int16_t _IQ13toa(char *string, const char *format, _iq13 input);\nextern int16_t _IQ12toa(char *string, const char *format, _iq12 input);\nextern int16_t _IQ11toa(char *string, const char *format, _iq11 input);\nextern int16_t _IQ10toa(char *string, const char *format, _iq10 input);\nextern int16_t _IQ9toa(char *string, const char *format, _iq9 input);\nextern int16_t _IQ8toa(char *string, const char *format, _iq8 input);\nextern int16_t _IQ7toa(char *string, const char *format, _iq7 input);\nextern int16_t _IQ6toa(char *string, const char *format, _iq6 input);\nextern int16_t _IQ5toa(char *string, const char *format, _iq5 input);\nextern int16_t _IQ4toa(char *string, const char *format, _iq4 input);\nextern int16_t _IQ3toa(char *string, const char *format, _iq3 input);\nextern int16_t _IQ2toa(char *string, const char *format, _iq2 input);\nextern int16_t _IQ1toa(char *string, const char *format, _iq1 input);\n#endif /* DOXYGEN_SHOULD_SKIP_THIS */\n\n/**\n * @brief Converts a global IQ format input into a string.\n *\n * @param A               Pointer to the buffer to store the converted IQ number.\n * @param B               The format string specifying how to convert the IQ number.\n * @param C               Global IQ format input.\n *\n * @return                Returns 0 if there is no error, 1 if the width is too small to hold the integer\n *                        characters, and 2 if an illegal format was specified.\n */\n#if GLOBAL_IQ == 30\n#define _IQtoa(A, B, C)     _IQ30toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 29\n#define _IQtoa(A, B, C)     _IQ29toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 28\n#define _IQtoa(A, B, C)     _IQ28toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 27\n#define _IQtoa(A, B, C)     _IQ27toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 26\n#define _IQtoa(A, B, C)     _IQ26toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 25\n#define _IQtoa(A, B, C)     _IQ25toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 24\n#define _IQtoa(A, B, C)     _IQ24toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 23\n#define _IQtoa(A, B, C)     _IQ23toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 22\n#define _IQtoa(A, B, C)     _IQ22toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 21\n#define _IQtoa(A, B, C)     _IQ21toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 20\n#define _IQtoa(A, B, C)     _IQ20toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 19\n#define _IQtoa(A, B, C)     _IQ19toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 18\n#define _IQtoa(A, B, C)     _IQ18toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 17\n#define _IQtoa(A, B, C)     _IQ17toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 16\n#define _IQtoa(A, B, C)     _IQ16toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 15\n#define _IQtoa(A, B, C)     _IQ15toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 14\n#define _IQtoa(A, B, C)     _IQ14toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 13\n#define _IQtoa(A, B, C)     _IQ13toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 12\n#define _IQtoa(A, B, C)     _IQ12toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 11\n#define _IQtoa(A, B, C)     _IQ11toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 10\n#define _IQtoa(A, B, C)     _IQ10toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 9\n#define _IQtoa(A, B, C)     _IQ9toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 8\n#define _IQtoa(A, B, C)     _IQ8toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 7\n#define _IQtoa(A, B, C)     _IQ7toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 6\n#define _IQtoa(A, B, C)     _IQ6toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 5\n#define _IQtoa(A, B, C)     _IQ5toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 4\n#define _IQtoa(A, B, C)     _IQ4toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 3\n#define _IQtoa(A, B, C)     _IQ3toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 2\n#define _IQtoa(A, B, C)     _IQ2toa(A, B, C)\n#endif\n#if GLOBAL_IQ == 1\n#define _IQtoa(A, B, C)     _IQ1toa(A, B, C)\n#endif\n\n//*****************************************************************************\n//\n// Computes the absolute value of an IQ number.\n//\n//*****************************************************************************\n/**\n * @brief Computes the absolute value of an IQ30 number.\n *\n * @param A               IQ30 type input.\n *\n * @return                IQ30 type absolute value of input.\n */\n#define _IQ30abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ29 number.\n *\n * @param A               IQ29 type input.\n *\n * @return                IQ29 type absolute value of input.\n */\n#define _IQ29abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ28 number.\n *\n * @param A               IQ28 type input.\n *\n * @return                IQ28 type absolute value of input.\n */\n#define _IQ28abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ27 number.\n *\n * @param A               IQ27 type input.\n *\n * @return                IQ27 type absolute value of input.\n */\n#define _IQ27abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ26 number.\n *\n * @param A               IQ26 type input.\n *\n * @return                IQ26 type absolute value of input.\n */\n#define _IQ26abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ25 number.\n *\n * @param A               IQ25 type input.\n *\n * @return                IQ25 type absolute value of input.\n */\n#define _IQ25abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ24 number.\n *\n * @param A               IQ24 type input.\n *\n * @return                IQ24 type absolute value of input.\n */\n#define _IQ24abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ23 number.\n *\n * @param A               IQ23 type input.\n *\n * @return                IQ23 type absolute value of input.\n */\n#define _IQ23abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ22 number.\n *\n * @param A               IQ22 type input.\n *\n * @return                IQ22 type absolute value of input.\n */\n#define _IQ22abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ21 number.\n *\n * @param A               IQ21 type input.\n *\n * @return                IQ21 type absolute value of input.\n */\n#define _IQ21abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ20 number.\n *\n * @param A               IQ20 type input.\n *\n * @return                IQ20 type absolute value of input.\n */\n#define _IQ20abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ19 number.\n *\n * @param A               IQ19 type input.\n *\n * @return                IQ19 type absolute value of input.\n */\n#define _IQ19abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ18 number.\n *\n * @param A               IQ18 type input.\n *\n * @return                IQ18 type absolute value of input.\n */\n#define _IQ18abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ17 number.\n *\n * @param A               IQ17 type input.\n *\n * @return                IQ17 type absolute value of input.\n */\n#define _IQ17abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ16 number.\n *\n * @param A               IQ16 type input.\n *\n * @return                IQ16 type absolute value of input.\n */\n#define _IQ16abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ15 number.\n *\n * @param A               IQ15 type input.\n *\n * @return                IQ15 type absolute value of input.\n */\n#define _IQ15abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ14 number.\n *\n * @param A               IQ14 type input.\n *\n * @return                IQ14 type absolute value of input.\n */\n#define _IQ14abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ13 number.\n *\n * @param A               IQ13 type input.\n *\n * @return                IQ13 type absolute value of input.\n */\n#define _IQ13abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ12 number.\n *\n * @param A               IQ12 type input.\n *\n * @return                IQ12 type absolute value of input.\n */\n#define _IQ12abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ11 number.\n *\n * @param A               IQ11 type input.\n *\n * @return                IQ11 type absolute value of input.\n */\n#define _IQ11abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ10 number.\n *\n * @param A               IQ10 type input.\n *\n * @return                IQ10 type absolute value of input.\n */\n#define _IQ10abs(A)             (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ9 number.\n *\n * @param A               IQ9 type input.\n *\n * @return                IQ9 type absolute value of input.\n */\n#define _IQ9abs(A)              (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ8 number.\n *\n * @param A               IQ8 type input.\n *\n * @return                IQ8 type absolute value of input.\n */\n#define _IQ8abs(A)              (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ7 number.\n *\n * @param A               IQ7 type input.\n *\n * @return                IQ7 type absolute value of input.\n */\n#define _IQ7abs(A)              (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ6 number.\n *\n * @param A               IQ6 type input.\n *\n * @return                IQ6 type absolute value of input.\n */\n#define _IQ6abs(A)              (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ5 number.\n *\n * @param A               IQ5 type input.\n *\n * @return                IQ5 type absolute value of input.\n */\n#define _IQ5abs(A)              (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ4 number.\n *\n * @param A               IQ4 type input.\n *\n * @return                IQ4 type absolute value of input.\n */\n#define _IQ4abs(A)              (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ3 number.\n *\n * @param A               IQ3 type input.\n *\n * @return                IQ3 type absolute value of input.\n */\n#define _IQ3abs(A)              (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ2 number.\n *\n * @param A               IQ2 type input.\n *\n * @return                IQ2 type absolute value of input.\n */\n#define _IQ2abs(A)              (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an IQ1 number.\n *\n * @param A               IQ1 type input.\n *\n * @return                IQ1 type absolute value of input.\n */\n#define _IQ1abs(A)              (((A) < 0) ? - (A) : (A))\n/**\n * @brief Computes the absolute value of an global IQ format number.\n *\n * @param A               Global IQ format input.\n *\n * @return                GlobalIQ format absolute value of input.\n */\n#define _IQabs(A)               (((A) < 0) ? - (A) : (A))\n\n//*****************************************************************************\n//\n// Mark the end of the C bindings section for C++ compilers.\n//\n//*****************************************************************************\n#ifdef __cplusplus\n}\n#endif\n\n#endif // __IQMATHLIB_H__\n"
  },
  {
    "path": "iqmath/support/RTS_support.h",
    "content": "#ifndef __RTS_SUPPORTH__\n#define __RTS_SUPPORTH__\n\n////////////////////////////////////////////////////////////\n//                                                        //\n//              MPY32 control functions.                  //\n//                                                        //\n////////////////////////////////////////////////////////////\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpy_start)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline void __mpy_start(uint_fast16_t *ui16IntState, uint_fast16_t *ui16MPYState)\n{\n    /* Do nothing. */\n    return;\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpyf_start)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline void __mpyf_start(uint_fast16_t *ui16IntState, uint_fast16_t *ui16MPYState)\n{\n    /* Do nothing. */\n    return;\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpyfs_start)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline void __mpyfs_start(uint_fast16_t *ui16IntState, uint_fast16_t *ui16MPYState)\n{\n    /* Do nothing. */\n    return;\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpy_clear_ctl0)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline void __mpy_clear_ctl0(void)\n{\n    /* Do nothing. */\n    return;\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpy_set_frac)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline void __mpy_set_frac(void)\n{\n    /* Do nothing. */\n    return;\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpy_stop)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline void __mpy_stop(uint_fast16_t *ui16IntState, uint_fast16_t *ui16MPYState)\n{\n    /* Do nothing. */\n    return;\n}\n\n////////////////////////////////////////////////////////////\n//                                                        //\n//                16-bit functions                        //\n//                                                        //\n////////////////////////////////////////////////////////////\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpy_w)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline int_fast16_t __mpy_w(int_fast16_t arg1, int_fast16_t arg2)\n{\n    return (arg1 * arg2);\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpy_uw)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline uint_fast16_t __mpy_uw(uint_fast16_t arg1, uint_fast16_t arg2)\n{\n    return (arg1 * arg2);\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpyx_w)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline int_fast32_t __mpyx_w(int_fast16_t arg1, int_fast16_t arg2)\n{\n    return ((int_fast32_t)arg1 * (int_fast32_t)arg2);\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpyx_uw)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline uint_fast32_t __mpyx_uw(uint_fast16_t arg1, uint_fast16_t arg2)\n{\n    return ((uint_fast32_t)arg1 * (uint_fast32_t)arg2);\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpyf_w)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline int_fast16_t __mpyf_w(int_fast16_t arg1, int_fast16_t arg2)\n{\n    return (int_fast16_t)(((int_fast32_t)arg1 * (int_fast32_t)arg2) >> 15);\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpyf_w_reuse_arg1)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline int_fast16_t __mpyf_w_reuse_arg1(int_fast16_t arg1, int_fast16_t arg2)\n{\n    /* This is identical to __mpyf_w */\n    return (int_fast16_t)(((int_fast32_t)arg1 * (int_fast32_t)arg2) >> 15);\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpyf_uw)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline uint_fast16_t __mpyf_uw(uint_fast16_t arg1, uint_fast16_t arg2)\n{\n    return (uint_fast16_t)(((uint_fast32_t)arg1 * (uint_fast32_t)arg2) >> 15);\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpyf_uw_reuse_arg1)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline uint_fast16_t __mpyf_uw_reuse_arg1(uint_fast16_t arg1, uint_fast16_t arg2)\n{\n    /* This is identical to __mpyf_uw */\n    return (uint_fast16_t)(((uint_fast32_t)arg1 * (uint_fast32_t)arg2) >> 15);\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpyfx_w)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline int_fast32_t __mpyfx_w(int_fast16_t arg1, int_fast16_t arg2)\n{\n    return (((int_fast32_t)arg1 * (int_fast32_t)arg2) << 1);\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpyfx_uw)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline int_fast32_t __mpyfx_uw(uint_fast16_t arg1, uint_fast16_t arg2)\n{\n    return (((uint_fast32_t)arg1 * (uint_fast32_t)arg2) << 1);\n}\n\n\n////////////////////////////////////////////////////////////\n//                                                        //\n//                 32-bit functions                       //\n//                                                        //\n////////////////////////////////////////////////////////////\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpy_l)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline int_fast32_t __mpy_l(int_fast32_t arg1, int_fast32_t arg2)\n{\n    return (arg1 * arg2);\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpy_ul)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline uint_fast32_t __mpy_ul(uint_fast32_t arg1, uint_fast32_t arg2)\n{\n    return (arg1 * arg2);\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpyx)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline int_fast64_t __mpyx(int_fast32_t arg1, int_fast32_t arg2)\n{\n    return ((int_fast64_t)arg1 * (int_fast64_t)arg2);\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpyx_u)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline uint_fast64_t __mpyx_u(uint_fast32_t arg1, uint_fast32_t arg2)\n{\n    return ((uint_fast64_t)arg1 * (uint_fast64_t)arg2);\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpyf_l)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline int_fast32_t __mpyf_l(int_fast32_t arg1, int_fast32_t arg2)\n{\n    return (int_fast32_t)(((int_fast64_t)arg1 * (int_fast64_t)arg2) >> 31);\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpyf_l_reuse_arg1)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline int_fast32_t __mpyf_l_reuse_arg1(int_fast32_t arg1, int_fast32_t arg2)\n{\n    /* This is identical to __mpyf_l */\n    return (int_fast32_t)(((int_fast64_t)arg1 * (int_fast64_t)arg2) >> 31);\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpyf_ul)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline uint_fast32_t __mpyf_ul(uint_fast32_t arg1, uint_fast32_t arg2)\n{\n    return (uint_fast32_t)(((uint_fast64_t)arg1 * (uint_fast64_t)arg2) >> 31);\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpyf_ul_reuse_arg1)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline int_fast32_t __mpyf_ul_reuse_arg1(uint_fast32_t arg1, uint_fast32_t arg2)\n{\n    /* This is identical to __mpyf_ul */\n    return (uint_fast32_t)(((uint_fast64_t)arg1 * (uint_fast64_t)arg2) >> 31);\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpyfx)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline int_fast64_t __mpyfx(int_fast32_t arg1, int_fast32_t arg2)\n{\n    return (((int_fast64_t)arg1 * (int_fast64_t)arg2) << 1);\n}\n\n#if defined (__TI_COMPILER_VERSION__)\n#pragma FUNC_ALWAYS_INLINE(__mpyfx_u)\n#elif defined(__IAR_SYSTEMS_ICC__)\n#pragma inline=forced\n#endif\nstatic inline uint_fast64_t __mpyfx_u(uint_fast32_t arg1, uint_fast32_t arg2)\n{\n    return (((uint_fast64_t)arg1 * (uint_fast64_t)arg2) << 1);\n}\n\n#endif //__RTS_SUPPORTH__\n"
  },
  {
    "path": "iqmath/support/support.h",
    "content": "#ifndef __SUPPORTH__\n#define __SUPPORTH__\n\n#include <math.h>\n#include \"esp_attr.h\"\n#include \"RTS_support.h\"\n\n#define __STATIC_INLINE FORCE_INLINE_ATTR\n\n/* Common value defines. */\n#define q15_ln2          0x58b9\n#define q13_pi           0x6488\n#define q14_pi           0xc910\n#define q14_halfPi       0x6488\n#define q14_quarterPi    0x3244\n#define q15_halfPi       0xc910\n#define q15_quarterPi    0x6488\n#define q15_invRoot2     0x5a82\n#define q15_tanSmall     0x0021\n#define q15_pointOne     0x0ccd\n#define q15_oneTenth     0x0ccd\n#define iq28_twoPi       0x6487ed51\n#define iq29_pi          0x6487ed51\n#define iq29_halfPi      0x3243f6a8\n#define iq30_pi          0xc90fdaa2\n#define iq30_halfPi      0x6487ed51\n#define iq30_quarterPi   0x3243f6a8\n#define iq31_halfPi      0xc90fdaa2\n#define iq31_quarterPi   0x6487ed51\n#define iq31_invRoot2    0x5a82799a\n#define iq31_tanSmall    0x0020c49b\n#define iq31_ln2         0x58b90bfc\n#define iq31_twoThird    0x55555555\n#define iq31_pointOne    0x0ccccccd\n#define iq31_oneTenth    0x0ccccccd\n#define iq31_one         0x7fffffff\n\n#endif //__SUPPORTH__\n"
  },
  {
    "path": "iqmath/test_apps/CMakeLists.txt",
    "content": "# This is the project CMakeLists.txt file for the test subproject\ncmake_minimum_required(VERSION 3.5)\n\nset(COMPONENTS main)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nproject(iqmath_test)\n"
  },
  {
    "path": "iqmath/test_apps/main/CMakeLists.txt",
    "content": "# This is the project CMakeLists.txt file for the test subproject\nset(src \"test_app_main.c\" \"test_iqmath.c\")\n\nset(priv_reqs unity)\n\nidf_component_register(SRCS ${src}\n                       PRIV_REQUIRES ${priv_reqs}\n                       WHOLE_ARCHIVE\n                       )\n"
  },
  {
    "path": "iqmath/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/iqmath:\n    version: '*'\n    override_path: '../../'\n"
  },
  {
    "path": "iqmath/test_apps/main/test_app_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n\n#include \"unity.h\"\n#include \"unity_test_runner.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_newlib.h\"\n#include \"unity_test_utils_memory.h\"\n\nvoid setUp(void)\n{\n    unity_utils_record_free_mem();\n}\n\nvoid tearDown(void)\n{\n    esp_reent_cleanup();    //clean up some of the newlib's lazy allocations\n    unity_utils_evaluate_leaks_direct(20);\n}\n\nvoid app_main(void)\n{\n    printf(\"Running IQmath component tests\\n\");\n    unity_run_menu();\n}"
  },
  {
    "path": "iqmath/test_apps/main/test_iqmath.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n\n#include <stdio.h>\n#include \"unity.h\"\n#include \"esp_log.h\"\n#include \"IQmathLib.h\"\n\n#define ERROR_WITHIN_TOLERANCE(result, expected, tolerance) \\\n    (((result) >= ((expected) - ((expected) * (tolerance)))) && \\\n    ((result) <= ((expected) + ((expected) * (tolerance)))))\n\nstatic const char *TAG = \"iqmath_test\";\n\nTEST_CASE(\"Test IQmath basic arithmetic\", \"[iqmath]\")\n{\n    const float error_tolerance = 0.01;\n    float res;\n\n    /* IQ variables using global type */\n    _iq qA = _IQ(1.5);\n    _iq qB = _IQ(2.5);\n    _iq qC;\n\n    qC = qA + qB;\n    res = _IQtoF(qC);\n    ESP_LOGI(TAG, \"Addition: %f + %f = %f\", _IQtoF(qA), _IQtoF(qB), res);\n    TEST_ASSERT(ERROR_WITHIN_TOLERANCE(res, 4.0, error_tolerance));\n\n    qC = _IQmpy(qA, qB);\n    res = _IQtoF(qC);\n    ESP_LOGI(TAG, \"Multiplication: %f * %f = %f\", _IQtoF(qA), _IQtoF(qB), res);\n    TEST_ASSERT(ERROR_WITHIN_TOLERANCE(res, 3.75, error_tolerance));\n\n    qC = qB - qA;\n    res = _IQtoF(qC);\n    ESP_LOGI(TAG, \"Subtraction: %f - %f = %f\", _IQtoF(qB), _IQtoF(qA), res);\n    TEST_ASSERT(ERROR_WITHIN_TOLERANCE(res, 1.0, error_tolerance));\n\n    qC = _IQdiv(qB, qA);\n    res = _IQtoF(qC);\n    ESP_LOGI(TAG, \"Division: %f / %f = %f\", _IQtoF(qB), _IQtoF(qA), res);\n    TEST_ASSERT(ERROR_WITHIN_TOLERANCE(res, 1.666667, error_tolerance));\n}\n\nTEST_CASE(\"Test IQmath mathematical functions\", \"[iqmath]\")\n{\n    const float error_tolerance = 0.01;\n    float res;\n\n    _iq qA = _IQ(2.5);\n    _iq qC;\n\n    // Test square root\n    qC = _IQsqrt(qA);\n    res = _IQtoF(qC);\n    ESP_LOGI(TAG, \"Square root of %f = %f\", _IQtoF(qA), res);\n    TEST_ASSERT(ERROR_WITHIN_TOLERANCE(res, 1.58113885, error_tolerance));\n\n    // Test trigonometric functions\n    qA = _IQ(M_PI / 4.0); // 45 degrees\n\n    // Test sin\n    qC = _IQsin(qA);\n    res = _IQtoF(qC);\n    ESP_LOGI(TAG, \"sin(pi/4) = %f\", res);\n    TEST_ASSERT(ERROR_WITHIN_TOLERANCE(res, 0.707106781, error_tolerance));\n\n    // Test cos\n    qC = _IQcos(qA);\n    res = _IQtoF(qC);\n    ESP_LOGI(TAG, \"cos(pi/4) = %f\", res);\n    TEST_ASSERT(ERROR_WITHIN_TOLERANCE(res, 0.707106781, error_tolerance));\n}\n\nTEST_CASE(\"Test IQ8 type operations\", \"[iqmath]\")\n{\n    const float error_tolerance = 0.01;\n    float res;\n\n    /* IQ variables using IQ8 type */\n    _iq8 q8A = _IQ8(1.5);\n    _iq8 q8B = _IQ8(2.5);\n    _iq8 q8C;\n\n    // Test IQ8 addition\n    q8C = q8A + q8B;\n    res = _IQ8toF(q8C);\n    ESP_LOGI(TAG, \"IQ8 Addition: %f + %f = %f\", _IQ8toF(q8A), _IQ8toF(q8B), res);\n    TEST_ASSERT(ERROR_WITHIN_TOLERANCE(res, 4.0, error_tolerance));\n\n    // Test IQ8 multiplication\n    q8C = _IQ8mpy(q8A, q8B);\n    res = _IQ8toF(q8C);\n    ESP_LOGI(TAG, \"IQ8 Multiplication: %f * %f = %f\", _IQ8toF(q8A), _IQ8toF(q8B), res);\n    TEST_ASSERT(ERROR_WITHIN_TOLERANCE(res, 3.75, error_tolerance));\n}\n\nTEST_CASE(\"Test IQ conversion and saturation\", \"[iqmath]\")\n{\n    const float error_tolerance = 0.01;\n    float res;\n\n    // Test float to IQ conversion\n    float test_val = 3.14159;\n    _iq iq_val = _IQ(test_val);\n    res = _IQtoF(iq_val);\n    ESP_LOGI(TAG, \"Float to IQ conversion: %f -> %f\", test_val, res);\n    TEST_ASSERT(ERROR_WITHIN_TOLERANCE(res, test_val, error_tolerance));\n\n    // Test IQ saturation\n    _iq8 q8A = _IQ8(16.0);\n    _iq qC = _IQ8toIQ(_IQsat(q8A, _IQtoQ8(MAX_IQ_POS), _IQtoQ8(MAX_IQ_NEG)));\n    res = _IQtoF(qC);\n    ESP_LOGI(TAG, \"IQ saturation test: %f\", res);\n    TEST_ASSERT(ERROR_WITHIN_TOLERANCE(res, 16.0, error_tolerance));\n}"
  },
  {
    "path": "iqmath/test_apps/pytest_iqmath.py",
    "content": "# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\n\nimport pytest\n\n@pytest.mark.generic\ndef test_iqmath(dut) -> None:\n    dut.run_all_single_board_cases()"
  },
  {
    "path": "iqmath/test_apps/sdkconfig.defaults",
    "content": "CONFIG_UNITY_ENABLE_FIXTURE=n\nCONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y\n\nCONFIG_ESP_TASK_WDT_INIT=n"
  },
  {
    "path": "jsmn/.build-test-rules.yml",
    "content": "jsmn/test_apps:\n  enable:\n    - if: IDF_TARGET in [\"esp32\", \"esp32c3\"]\n      reason: \"Sufficient to test on one Xtensa and one RISC-V target\"\n"
  },
  {
    "path": "jsmn/CMakeLists.txt",
    "content": "idf_component_register(INCLUDE_DIRS \"include\")\n\nif(CONFIG_JSMN_PARENT_LINKS)\n    target_compile_definitions(${COMPONENT_LIB} INTERFACE \"-DJSMN_PARENT_LINKS\")\nendif()\n\nif(CONFIG_JSMN_STRICT)\n    target_compile_definitions(${COMPONENT_LIB} INTERFACE \"-DJSMN_STRICT\")\nendif()\n\nif(CONFIG_JSMN_STATIC)\n    target_compile_definitions(${COMPONENT_LIB} INTERFACE \"-DJSMN_STATIC\")\nendif()\n"
  },
  {
    "path": "jsmn/Kconfig",
    "content": "menu \"jsmn\"\n\n\n    config JSMN_PARENT_LINKS\n        bool \"Enable parent links\"\n        default n\n        help\n            You can access parent node of parsed json\n\n    config JSMN_STRICT\n        bool \"Enable strict mode\"\n        default n\n        help\n            In strict mode primitives are: numbers and booleans\n\n    config JSMN_STATIC\n        bool \"Declare JSMN API as static\"\n        default node\n        help\n            Declare JSMN API as static (instead of extern)\n\nendmenu\n"
  },
  {
    "path": "jsmn/LICENSE",
    "content": "Copyright (c) 2010 Serge A. Zaitsev\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in\r\nall copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\nTHE SOFTWARE.\r\n"
  },
  {
    "path": "jsmn/README.md",
    "content": "JSMN\n====\n\n[![Build Status](https://travis-ci.org/zserge/jsmn.svg?branch=master)](https://travis-ci.org/zserge/jsmn) [![Component Registry](https://components.espressif.com/components/espressif/jsmn/badge.svg)](https://components.espressif.com/components/espressif/jsmn)\n\njsmn (pronounced like 'jasmine') is a minimalistic JSON parser in C.  It can be\neasily integrated into resource-limited or embedded projects.\n\nYou can find more information about JSON format at [json.org][1]\n\nLibrary sources are available at https://github.com/zserge/jsmn\n\nThe web page with some information about jsmn can be found at\n[http://zserge.com/jsmn.html][2]\n\nPhilosophy\n----------\n\nMost JSON parsers offer you a bunch of functions to load JSON data, parse it\nand extract any value by its name. jsmn proves that checking the correctness of\nevery JSON packet or allocating temporary objects to store parsed JSON fields\noften is an overkill. \n\nJSON format itself is extremely simple, so why should we complicate it?\n\njsmn is designed to be\t**robust** (it should work fine even with erroneous\ndata), **fast** (it should parse data on the fly), **portable** (no superfluous\ndependencies or non-standard C extensions). And of course, **simplicity** is a\nkey feature - simple code style, simple algorithm, simple integration into\nother projects.\n\nFeatures\n--------\n\n* compatible with C89\n* no dependencies (even libc!)\n* highly portable (tested on x86/amd64, ARM, AVR)\n* about 200 lines of code\n* extremely small code footprint\n* API contains only 2 functions\n* no dynamic memory allocation\n* incremental single-pass parsing\n* library code is covered with unit-tests\n\nDesign\n------\n\nThe rudimentary jsmn object is a **token**. Let's consider a JSON string:\n\n\t'{ \"name\" : \"Jack\", \"age\" : 27 }'\n\nIt holds the following tokens:\n\n* Object: `{ \"name\" : \"Jack\", \"age\" : 27}` (the whole object)\n* Strings: `\"name\"`, `\"Jack\"`, `\"age\"` (keys and some values)\n* Number: `27`\n\nIn jsmn, tokens do not hold any data, but point to token boundaries in JSON\nstring instead. In the example above jsmn will create tokens like: Object\n[0..31], String [3..7], String [12..16], String [20..23], Number [27..29].\n\nEvery jsmn token has a type, which indicates the type of corresponding JSON\ntoken. jsmn supports the following token types:\n\n* Object - a container of key-value pairs, e.g.:\n\t`{ \"foo\":\"bar\", \"x\":0.3 }`\n* Array - a sequence of values, e.g.:\n\t`[ 1, 2, 3 ]`\n* String - a quoted sequence of chars, e.g.: `\"foo\"`\n* Primitive - a number, a boolean (`true`, `false`) or `null`\n\nBesides start/end positions, jsmn tokens for complex types (like arrays\nor objects) also contain a number of child items, so you can easily follow\nobject hierarchy.\n\nThis approach provides enough information for parsing any JSON data and makes\nit possible to use zero-copy techniques.\n\nUsage\n-----\n\nDownload `jsmn.h`, include it, done.\n\n```\n#include \"jsmn.h\"\n\n...\njsmn_parser p;\njsmntok_t t[128]; /* We expect no more than 128 JSON tokens */\n\njsmn_init(&p);\nr = jsmn_parse(&p, s, strlen(s), t, 128); // \"s\" is the char array holding the json content\n```\n\nSince jsmn is a single-header, header-only library, for more complex use cases\nyou might need to define additional macros. `#define JSMN_STATIC` hides all\njsmn API symbols by making them static. Also, if you want to include `jsmn.h`\nfrom multiple C files, to avoid duplication of symbols you may define  `JSMN_HEADER` macro.\n\n```\n/* In every .c file that uses jsmn include only declarations: */\n#define JSMN_HEADER\n#include \"jsmn.h\"\n\n/* Additionally, create one jsmn.c file for jsmn implementation: */\n#include \"jsmn.h\"\n```\n\nAPI\n---\n\nToken types are described by `jsmntype_t`:\n\n\ttypedef enum {\n\t\tJSMN_UNDEFINED = 0,\n\t\tJSMN_OBJECT = 1 << 0,\n\t\tJSMN_ARRAY = 1 << 1,\n\t\tJSMN_STRING = 1 << 2,\n\t\tJSMN_PRIMITIVE = 1 << 3\n\t} jsmntype_t;\n\n**Note:** Unlike JSON data types, primitive tokens are not divided into\nnumbers, booleans and null, because one can easily tell the type using the\nfirst character:\n\n* <code>'t', 'f'</code> - boolean \n* <code>'n'</code> - null\n* <code>'-', '0'..'9'</code> - number\n\nToken is an object of `jsmntok_t` type:\n\n\ttypedef struct {\n\t\tjsmntype_t type; // Token type\n\t\tint start;       // Token start position\n\t\tint end;         // Token end position\n\t\tint size;        // Number of child (nested) tokens\n\t} jsmntok_t;\n\n**Note:** string tokens point to the first character after\nthe opening quote and the previous symbol before final quote. This was made \nto simplify string extraction from JSON data.\n\nAll job is done by `jsmn_parser` object. You can initialize a new parser using:\n\n\tjsmn_parser parser;\n\tjsmntok_t tokens[10];\n\n\tjsmn_init(&parser);\n\n\t// js - pointer to JSON string\n\t// tokens - an array of tokens available\n\t// 10 - number of tokens available\n\tjsmn_parse(&parser, js, strlen(js), tokens, 10);\n\nThis will create a parser, and then it tries to parse up to 10 JSON tokens from\nthe `js` string.\n\nA non-negative return value of `jsmn_parse` is the number of tokens actually\nused by the parser.\nPassing NULL instead of the tokens array would not store parsing results, but\ninstead the function will return the number of tokens needed to parse the given\nstring. This can be useful if you don't know yet how many tokens to allocate.\n\nIf something goes wrong, you will get an error. Error will be one of these:\n\n* `JSMN_ERROR_INVAL` - bad token, JSON string is corrupted\n* `JSMN_ERROR_NOMEM` - not enough tokens, JSON string is too large\n* `JSMN_ERROR_PART` - JSON string is too short, expecting more JSON data\n\nIf you get `JSMN_ERROR_NOMEM`, you can re-allocate more tokens and call\n`jsmn_parse` once more.  If you read json data from the stream, you can\nperiodically call `jsmn_parse` and check if return value is `JSMN_ERROR_PART`.\nYou will get this error until you reach the end of JSON data.\n\nOther info\n----------\n\nThis software is distributed under [MIT license](http://www.opensource.org/licenses/mit-license.php),\n so feel free to integrate it in your commercial products.\n\n[1]: http://www.json.org/\n[2]: http://zserge.com/jsmn.html\n"
  },
  {
    "path": "jsmn/idf_component.yml",
    "content": "version: \"1.1.0\"\ndescription: \"JSMN: minimalistic JSON parser in C\"\nurl: https://github.com/espressif/idf-extra-components/tree/master/jsmn\ndependencies:\n  idf: \">=4.3\"\n"
  },
  {
    "path": "jsmn/include/jsmn.h",
    "content": "/*\r\n * MIT License\r\n *\r\n * Copyright (c) 2010 Serge Zaitsev\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n * SOFTWARE.\r\n */\r\n#ifndef JSMN_H\r\n#define JSMN_H\r\n\r\n#include <stddef.h>\r\n\r\n#ifdef __cplusplus\r\nextern \"C\" {\r\n#endif\r\n\r\n#ifdef JSMN_STATIC\r\n#define JSMN_API static\r\n#else\r\n#define JSMN_API extern\r\n#endif\r\n\r\n/**\r\n * JSON type identifier. Basic types are:\r\n *  o Object\r\n *  o Array\r\n *  o String\r\n *  o Other primitive: number, boolean (true/false) or null\r\n */\r\ntypedef enum {\r\n    JSMN_UNDEFINED = 0,\r\n    JSMN_OBJECT = 1 << 0,\r\n    JSMN_ARRAY = 1 << 1,\r\n    JSMN_STRING = 1 << 2,\r\n    JSMN_PRIMITIVE = 1 << 3\r\n} jsmntype_t;\r\n\r\nenum jsmnerr {\r\n    /* Not enough tokens were provided */\r\n    JSMN_ERROR_NOMEM = -1,\r\n    /* Invalid character inside JSON string */\r\n    JSMN_ERROR_INVAL = -2,\r\n    /* The string is not a full JSON packet, more bytes expected */\r\n    JSMN_ERROR_PART = -3\r\n};\r\n\r\n/**\r\n * JSON token description.\r\n * type     type (object, array, string etc.)\r\n * start    start position in JSON data string\r\n * end      end position in JSON data string\r\n */\r\ntypedef struct jsmntok {\r\n    jsmntype_t type;\r\n    int start;\r\n    int end;\r\n    int size;\r\n#ifdef JSMN_PARENT_LINKS\r\n    int parent;\r\n#endif\r\n} jsmntok_t;\r\n\r\n/**\r\n * JSON parser. Contains an array of token blocks available. Also stores\r\n * the string being parsed now and current position in that string.\r\n */\r\ntypedef struct jsmn_parser {\r\n    unsigned int pos;     /* offset in the JSON string */\r\n    unsigned int toknext; /* next token to allocate */\r\n    int toksuper;         /* superior token node, e.g. parent object or array */\r\n} jsmn_parser;\r\n\r\n/**\r\n * Create JSON parser over an array of tokens\r\n */\r\nJSMN_API void jsmn_init(jsmn_parser *parser);\r\n\r\n/**\r\n * Run JSON parser. It parses a JSON data string into and array of tokens, each\r\n * describing\r\n * a single JSON object.\r\n */\r\nJSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,\r\n                        jsmntok_t *tokens, const unsigned int num_tokens);\r\n\r\n#ifndef JSMN_HEADER\r\n/**\r\n * Allocates a fresh unused token from the token pool.\r\n */\r\nstatic jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens,\r\n                                   const size_t num_tokens)\r\n{\r\n    jsmntok_t *tok;\r\n    if (parser->toknext >= num_tokens) {\r\n        return NULL;\r\n    }\r\n    tok = &tokens[parser->toknext++];\r\n    tok->start = tok->end = -1;\r\n    tok->size = 0;\r\n#ifdef JSMN_PARENT_LINKS\r\n    tok->parent = -1;\r\n#endif\r\n    return tok;\r\n}\r\n\r\n/**\r\n * Fills token type and boundaries.\r\n */\r\nstatic void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type,\r\n                            const int start, const int end)\r\n{\r\n    token->type = type;\r\n    token->start = start;\r\n    token->end = end;\r\n    token->size = 0;\r\n}\r\n\r\n/**\r\n * Fills next available token with JSON primitive.\r\n */\r\nstatic int jsmn_parse_primitive(jsmn_parser *parser, const char *js,\r\n                                const size_t len, jsmntok_t *tokens,\r\n                                const size_t num_tokens)\r\n{\r\n    jsmntok_t *token;\r\n    int start;\r\n\r\n    start = parser->pos;\r\n\r\n    for (; parser->pos < len && js[parser->pos] != '\\0'; parser->pos++) {\r\n        switch (js[parser->pos]) {\r\n#ifndef JSMN_STRICT\r\n        /* In strict mode primitive must be followed by \",\" or \"}\" or \"]\" */\r\n        case ':':\r\n#endif\r\n        case '\\t':\r\n        case '\\r':\r\n        case '\\n':\r\n        case ' ':\r\n        case ',':\r\n        case ']':\r\n        case '}':\r\n            goto found;\r\n        default:\r\n            /* to quiet a warning from gcc*/\r\n            break;\r\n        }\r\n        if (js[parser->pos] < 32 || js[parser->pos] >= 127) {\r\n            parser->pos = start;\r\n            return JSMN_ERROR_INVAL;\r\n        }\r\n    }\r\n#ifdef JSMN_STRICT\r\n    /* In strict mode primitive must be followed by a comma/object/array */\r\n    parser->pos = start;\r\n    return JSMN_ERROR_PART;\r\n#endif\r\n\r\nfound:\r\n    if (tokens == NULL) {\r\n        parser->pos--;\r\n        return 0;\r\n    }\r\n    token = jsmn_alloc_token(parser, tokens, num_tokens);\r\n    if (token == NULL) {\r\n        parser->pos = start;\r\n        return JSMN_ERROR_NOMEM;\r\n    }\r\n    jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);\r\n#ifdef JSMN_PARENT_LINKS\r\n    token->parent = parser->toksuper;\r\n#endif\r\n    parser->pos--;\r\n    return 0;\r\n}\r\n\r\n/**\r\n * Fills next token with JSON string.\r\n */\r\nstatic int jsmn_parse_string(jsmn_parser *parser, const char *js,\r\n                             const size_t len, jsmntok_t *tokens,\r\n                             const size_t num_tokens)\r\n{\r\n    jsmntok_t *token;\r\n\r\n    int start = parser->pos;\r\n\r\n    /* Skip starting quote */\r\n    parser->pos++;\r\n\r\n    for (; parser->pos < len && js[parser->pos] != '\\0'; parser->pos++) {\r\n        char c = js[parser->pos];\r\n\r\n        /* Quote: end of string */\r\n        if (c == '\\\"') {\r\n            if (tokens == NULL) {\r\n                return 0;\r\n            }\r\n            token = jsmn_alloc_token(parser, tokens, num_tokens);\r\n            if (token == NULL) {\r\n                parser->pos = start;\r\n                return JSMN_ERROR_NOMEM;\r\n            }\r\n            jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos);\r\n#ifdef JSMN_PARENT_LINKS\r\n            token->parent = parser->toksuper;\r\n#endif\r\n            return 0;\r\n        }\r\n\r\n        /* Backslash: Quoted symbol expected */\r\n        if (c == '\\\\' && parser->pos + 1 < len) {\r\n            int i;\r\n            parser->pos++;\r\n            switch (js[parser->pos]) {\r\n            /* Allowed escaped symbols */\r\n            case '\\\"':\r\n            case '/':\r\n            case '\\\\':\r\n            case 'b':\r\n            case 'f':\r\n            case 'r':\r\n            case 'n':\r\n            case 't':\r\n                break;\r\n            /* Allows escaped symbol \\uXXXX */\r\n            case 'u':\r\n                parser->pos++;\r\n                for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\\0';\r\n                        i++) {\r\n                    /* If it isn't a hex character we have an error */\r\n                    if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) ||   /* 0-9 */\r\n                            (js[parser->pos] >= 65 && js[parser->pos] <= 70) ||   /* A-F */\r\n                            (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */\r\n                        parser->pos = start;\r\n                        return JSMN_ERROR_INVAL;\r\n                    }\r\n                    parser->pos++;\r\n                }\r\n                parser->pos--;\r\n                break;\r\n            /* Unexpected symbol */\r\n            default:\r\n                parser->pos = start;\r\n                return JSMN_ERROR_INVAL;\r\n            }\r\n        }\r\n    }\r\n    parser->pos = start;\r\n    return JSMN_ERROR_PART;\r\n}\r\n\r\n/**\r\n * Parse JSON string and fill tokens.\r\n */\r\nJSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,\r\n                        jsmntok_t *tokens, const unsigned int num_tokens)\r\n{\r\n    int r;\r\n    int i;\r\n    jsmntok_t *token;\r\n    int count = parser->toknext;\r\n\r\n    for (; parser->pos < len && js[parser->pos] != '\\0'; parser->pos++) {\r\n        char c;\r\n        jsmntype_t type;\r\n\r\n        c = js[parser->pos];\r\n        switch (c) {\r\n        case '{':\r\n        case '[':\r\n            count++;\r\n            if (tokens == NULL) {\r\n                break;\r\n            }\r\n            token = jsmn_alloc_token(parser, tokens, num_tokens);\r\n            if (token == NULL) {\r\n                return JSMN_ERROR_NOMEM;\r\n            }\r\n            if (parser->toksuper != -1) {\r\n                jsmntok_t *t = &tokens[parser->toksuper];\r\n#ifdef JSMN_STRICT\r\n                /* In strict mode an object or array can't become a key */\r\n                if (t->type == JSMN_OBJECT) {\r\n                    return JSMN_ERROR_INVAL;\r\n                }\r\n#endif\r\n                t->size++;\r\n#ifdef JSMN_PARENT_LINKS\r\n                token->parent = parser->toksuper;\r\n#endif\r\n            }\r\n            token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);\r\n            token->start = parser->pos;\r\n            parser->toksuper = parser->toknext - 1;\r\n            break;\r\n        case '}':\r\n        case ']':\r\n            if (tokens == NULL) {\r\n                break;\r\n            }\r\n            type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);\r\n#ifdef JSMN_PARENT_LINKS\r\n            if (parser->toknext < 1) {\r\n                return JSMN_ERROR_INVAL;\r\n            }\r\n            token = &tokens[parser->toknext - 1];\r\n            for (;;) {\r\n                if (token->start != -1 && token->end == -1) {\r\n                    if (token->type != type) {\r\n                        return JSMN_ERROR_INVAL;\r\n                    }\r\n                    token->end = parser->pos + 1;\r\n                    parser->toksuper = token->parent;\r\n                    break;\r\n                }\r\n                if (token->parent == -1) {\r\n                    if (token->type != type || parser->toksuper == -1) {\r\n                        return JSMN_ERROR_INVAL;\r\n                    }\r\n                    break;\r\n                }\r\n                token = &tokens[token->parent];\r\n            }\r\n#else\r\n            for (i = parser->toknext - 1; i >= 0; i--) {\r\n                token = &tokens[i];\r\n                if (token->start != -1 && token->end == -1) {\r\n                    if (token->type != type) {\r\n                        return JSMN_ERROR_INVAL;\r\n                    }\r\n                    parser->toksuper = -1;\r\n                    token->end = parser->pos + 1;\r\n                    break;\r\n                }\r\n            }\r\n            /* Error if unmatched closing bracket */\r\n            if (i == -1) {\r\n                return JSMN_ERROR_INVAL;\r\n            }\r\n            for (; i >= 0; i--) {\r\n                token = &tokens[i];\r\n                if (token->start != -1 && token->end == -1) {\r\n                    parser->toksuper = i;\r\n                    break;\r\n                }\r\n            }\r\n#endif\r\n            break;\r\n        case '\\\"':\r\n            r = jsmn_parse_string(parser, js, len, tokens, num_tokens);\r\n            if (r < 0) {\r\n                return r;\r\n            }\r\n            count++;\r\n            if (parser->toksuper != -1 && tokens != NULL) {\r\n                tokens[parser->toksuper].size++;\r\n            }\r\n            break;\r\n        case '\\t':\r\n        case '\\r':\r\n        case '\\n':\r\n        case ' ':\r\n            break;\r\n        case ':':\r\n            parser->toksuper = parser->toknext - 1;\r\n            break;\r\n        case ',':\r\n            if (tokens != NULL && parser->toksuper != -1 &&\r\n                    tokens[parser->toksuper].type != JSMN_ARRAY &&\r\n                    tokens[parser->toksuper].type != JSMN_OBJECT) {\r\n#ifdef JSMN_PARENT_LINKS\r\n                parser->toksuper = tokens[parser->toksuper].parent;\r\n#else\r\n                for (i = parser->toknext - 1; i >= 0; i--) {\r\n                    if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {\r\n                        if (tokens[i].start != -1 && tokens[i].end == -1) {\r\n                            parser->toksuper = i;\r\n                            break;\r\n                        }\r\n                    }\r\n                }\r\n#endif\r\n            }\r\n            break;\r\n#ifdef JSMN_STRICT\r\n        /* In strict mode primitives are: numbers and booleans */\r\n        case '-':\r\n        case '0':\r\n        case '1':\r\n        case '2':\r\n        case '3':\r\n        case '4':\r\n        case '5':\r\n        case '6':\r\n        case '7':\r\n        case '8':\r\n        case '9':\r\n        case 't':\r\n        case 'f':\r\n        case 'n':\r\n            /* And they must not be keys of the object */\r\n            if (tokens != NULL && parser->toksuper != -1) {\r\n                const jsmntok_t *t = &tokens[parser->toksuper];\r\n                if (t->type == JSMN_OBJECT ||\r\n                        (t->type == JSMN_STRING && t->size != 0)) {\r\n                    return JSMN_ERROR_INVAL;\r\n                }\r\n            }\r\n#else\r\n        /* In non-strict mode every unquoted value is a primitive */\r\n        default:\r\n#endif\r\n            r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);\r\n            if (r < 0) {\r\n                return r;\r\n            }\r\n            count++;\r\n            if (parser->toksuper != -1 && tokens != NULL) {\r\n                tokens[parser->toksuper].size++;\r\n            }\r\n            break;\r\n\r\n#ifdef JSMN_STRICT\r\n        /* Unexpected char in strict mode */\r\n        default:\r\n            return JSMN_ERROR_INVAL;\r\n#endif\r\n        }\r\n    }\r\n\r\n    if (tokens != NULL) {\r\n        for (i = parser->toknext - 1; i >= 0; i--) {\r\n            /* Unmatched opened object or array */\r\n            if (tokens[i].start != -1 && tokens[i].end == -1) {\r\n                return JSMN_ERROR_PART;\r\n            }\r\n        }\r\n    }\r\n\r\n    return count;\r\n}\r\n\r\n/**\r\n * Creates a new parser based over a given buffer with an array of tokens\r\n * available.\r\n */\r\nJSMN_API void jsmn_init(jsmn_parser *parser)\r\n{\r\n    parser->pos = 0;\r\n    parser->toknext = 0;\r\n    parser->toksuper = -1;\r\n}\r\n\r\n#endif /* JSMN_HEADER */\r\n\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n\r\n#endif /* JSMN_H */\r\n"
  },
  {
    "path": "jsmn/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(jsmn_test)\n"
  },
  {
    "path": "jsmn/test_apps/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"jsmn_test.c\"\n                    INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES unity)\n"
  },
  {
    "path": "jsmn/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/jsmn:\n    version: \"*\"\n    override_path: \"../..\"\n"
  },
  {
    "path": "jsmn/test_apps/main/jsmn_test.c",
    "content": "#include <stdio.h>\n\nvoid app_main(void)\n{\n\n}\n"
  },
  {
    "path": "json_generator/.build-test-rules.yml",
    "content": "json_generator/test_apps:\n  enable:\n    - if: IDF_TARGET in [\"esp32\", \"esp32c3\"]\n      reason: \"Sufficient to test on one Xtensa and one RISC-V target\"\n"
  },
  {
    "path": "json_generator/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"src/json_generator.c\"\n                    INCLUDE_DIRS \"include\"\n                    )\n"
  },
  {
    "path": "json_generator/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2020 Piyush Shah <shahpiyushv@gmail.com>\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "json_generator/README.md",
    "content": "# JSON Generator\n\n[![Component Registry](https://components.espressif.com/components/espressif/json_generator/badge.svg)](https://components.espressif.com/components/espressif/json_generator)\n\nA simple JSON (JavasScript Object Notation) generator with flushing capability.\nDetails of JSON can be found at [http://www.json.org/](http://www.json.org/).\nThe JSON strings generated can be validated using any standard JSON validator. Eg. [https://jsonlint.com/](https://jsonlint.com/)\n\n# Files\n- `src/json_generator.c`: Actual source file for the JSON generator with implementation of all APIS\n- `include/json_generator.h`: Header file documenting and exposing all available APIs\n\n# Usage\n\nInclude the C and H files in your project's build system and that should be enough.\n`json_generator` requires only standard library functions for compilation\n"
  },
  {
    "path": "json_generator/idf_component.yml",
    "content": "version: \"1.2.0\"\ndescription: A simple JSON (JavasScript Object Notation) generator with flushing capability\nurl: https://github.com/espressif/json_generator\n"
  },
  {
    "path": "json_generator/include/json_generator.h",
    "content": "/*\n *    Copyright 2020 Piyush Shah <shahpiyushv@gmail.com>\n *\n *   Licensed under the Apache License, Version 2.0 (the \"License\");\n *   you may not use this file except in compliance with the License.\n *   You may obtain a copy of the License at\n *\n *       http://www.apache.org/licenses/LICENSE-2.0\n *\n *   Unless required by applicable law or agreed to in writing, software\n *   distributed under the License is distributed on an \"AS IS\" BASIS,\n *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *   See the License for the specific language governing permissions and\n *   limitations under the License.\n */\n\n/*\n * JSON String Generator\n *\n * This module can be used to create JSON strings with a facility\n * to flush out data if the destination buffer is full. All commas\n * and colons as required are automatically added by the APIs\n *\n */\n#ifndef _JSON_GENERATOR_H\n#define _JSON_GENERATOR_H\n\n#include <stdint.h>\n#include <stdbool.h>\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\n/** Float precision i.e. number of digits after decimal point */\n#ifndef JSON_FLOAT_PRECISION\n#define JSON_FLOAT_PRECISION 5\n#endif\n\n/** JSON string flush callback prototype\n *\n * This is a prototype of the function that needs to be passed to\n * json_gen_str_start() and which will be invoked by the JSON generator\n * module either when the buffer is full or json_gen_str_end() ins invoked.\n *\n * \\param[in] buf Pointer to a NULL terminated JSON string\n * \\param[in] priv Private data to be passed to the flush callback. Will\n * be the same as the one passed to json_gen_str_start()\n */\ntypedef void (*json_gen_flush_cb_t) (char *buf, void *priv);\n\n/** JSON String structure\n *\n * Please do not set/modify any elements.\n * Just define this structure and pass a pointer to it in the APIs below\n */\ntypedef struct {\n    /** Pointer to the JSON buffer provided by the calling function */\n    char *buf;\n    /** Size of the above buffer */\n    int buf_size;\n    /** (Optional) callback function to invoke when the buffer gets full */\n    json_gen_flush_cb_t flush_cb;\n    /** (Optional) Private data to pass to the callback function */\n    void *priv;\n    /** (For Internal use only) */\n    bool comma_req;\n    /** (For Internal use only) */\n    char *free_ptr;\n    /** Total length */\n    int total_len;\n} json_gen_str_t;\n\n/** Start a JSON String\n *\n * This is the first function to be called for creating a JSON string.\n * It initializes the internal data structures. After the JSON string\n * generation is over, the json_gen_str_end() function should be called.\n *\n * \\param[out] jstr Pointer to an allocated \\ref json_gen_str_t structure.\n * This will be initialised internally and needs to be passed to all\n * subsequent function calls\n * \\param[out] buf Pointer to an allocated buffer into which the JSON\n * string will be written\n * \\param[in] buf_size Size of the buffer\n * \\param[in] flush_cb Pointer to the flushing function of type \\ref json_gen_flush_cb_t\n * which will be invoked either when the buffer is full or when json_gen_str_end()\n * is invoked. Can be left NULL.\n * \\param[in] priv Private data to be passed to the flushing function callback.\n * Can be something like a session identifier (Eg. socket). Can be left NULL.\n */\nvoid json_gen_str_start(json_gen_str_t *jstr, char *buf, int buf_size,\n                        json_gen_flush_cb_t flush_cb, void *priv);\n\n/** End JSON string\n *\n * This should be the last function to be called after the entire JSON string\n * has been generated.\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n *\n * \\return Total length of the JSON created, including the NULL termination byte.\n */\nint json_gen_str_end(json_gen_str_t *jstr);\n\n/** Start a JSON object\n *\n * This starts a JSON object by adding a '{'\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_start_object(json_gen_str_t *jstr);\n\n/** End a JSON object\n *\n * This ends a JSON object by adding a '}'\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_end_object(json_gen_str_t *jstr);\n\n/** Start a JSON array\n *\n * This starts a JSON object by adding a '['\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_start_array(json_gen_str_t *jstr);\n\n/** End a JSON object\n *\n * This ends a JSON object by adding a ']'\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_end_array(json_gen_str_t *jstr);\n\n/** Push a named JSON object\n *\n * This adds a JSON object like \"name\":{\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n * \\param[in] name Name of the object\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_push_object(json_gen_str_t *jstr, const char *name);\n\n/** Pop a named JSON object\n *\n * This ends a JSON object by adding a '}'. This is basically same as\n * json_gen_end_object() but included so as to complement json_gen_push_object()\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_pop_object(json_gen_str_t *jstr);\n\n/** Push a JSON object string\n *\n * This adds a complete pre-formatted JSON object string to the JSON object.\n *\n * Eg. json_gen_push_object_str(jstr, \"pre-formatted\", \"{\\\"a\\\":1,\\\"b\\\":2}\");\n * This will add \"pre-formatted\":{\"a\":1,\"b\":2}\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n * \\param[in] name Name of the JSON object string\n * \\param[in] object_str The pre-formatted JSON object string\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that.\n */\nint json_gen_push_object_str(json_gen_str_t *jstr, const char *name, const char *object_str);\n\n/** Push a named JSON array\n *\n * This adds a JSON array like \"name\":[\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n * \\param[in] name Name of the array\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_push_array(json_gen_str_t *jstr, const char *name);\n\n/** Pop a named JSON array\n *\n * This ends a JSON array by adding a ']'. This is basically same as\n * json_gen_end_array() but included so as to complement json_gen_push_array()\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_pop_array(json_gen_str_t *jstr);\n\n/** Push a JSON array string\n *\n * This adds a complete pre-formatted JSON array string to the JSON object.\n *\n * Eg. json_gen_push_object_str(jstr, \"pre-formatted\", \"[1,2,3]\");\n * This will add \"pre-formatted\":[1,2,3]\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n * \\param[in] name Name of the JSON array string\n * \\param[in] array_str The pre-formatted JSON array string\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that.\n */\nint json_gen_push_array_str(json_gen_str_t *jstr, const char *name, const char *array_str);\n\n/** Add a boolean element to an object\n *\n * This adds a boolean element to an object. Eg. \"bool_val\":true\n *\n * \\note This must be called between json_gen_start_object()/json_gen_push_object()\n * and json_gen_end_object()/json_gen_pop_object()\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n * \\param[in] name Name of the element\n * \\param[in] val Boolean value of the element\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_obj_set_bool(json_gen_str_t *jstr, const char *name, bool val);\n\n/** Add an integer element to an object\n *\n * This adds an integer element to an object. Eg. \"int_val\":28\n *\n * \\note This must be called between json_gen_start_object()/json_gen_push_object()\n * and json_gen_end_object()/json_gen_pop_object()\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n * \\param[in] name Name of the element\n * \\param[in] val Integer value of the element\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_obj_set_int(json_gen_str_t *jstr, const char *name, int val);\n\n/** Add a 64 bit integer element to an object\n *\n * \\note This must be called between json_gen_start_object()/json_gen_push_object()\n * and json_gen_end_object()/json_gen_pop_object()\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n * \\param[in] name Name of the element\n * \\param[in] val 64 bit integer value of the element\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_obj_set_int64(json_gen_str_t *jstr, const char *name, int64_t val);\n\n/** Add a float element to an object\n *\n * This adds a float element to an object. Eg. \"float_val\":23.8\n *\n * \\note This must be called between json_gen_start_object()/json_gen_push_object()\n * and json_gen_end_object()/json_gen_pop_object()\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n * \\param[in] name Name of the element\n * \\param[in] val Float value of the element\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_obj_set_float(json_gen_str_t *jstr, const char *name, float val);\n\n/** Add a string element to an object\n *\n * This adds a string element to an object. Eg. \"string_val\":\"my_string\"\n *\n * \\note This must be called between json_gen_start_object()/json_gen_push_object()\n * and json_gen_end_object()/json_gen_pop_object()\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n * \\param[in] name Name of the element\n * \\param[in] val Null terminated string value of the element\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_obj_set_string(json_gen_str_t *jstr, const char *name, const char *val);\n\n/** Add a NULL element to an object\n *\n * This adds a NULL element to an object. Eg. \"null_val\":null\n *\n * \\note This must be called between json_gen_start_object()/json_gen_push_object()\n * and json_gen_end_object()/json_gen_pop_object()\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n * \\param[in] name Name of the element\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_obj_set_null(json_gen_str_t *jstr, const char *name);\n\n/** Add a boolean element to an array\n *\n * \\note This must be called between json_gen_start_array()/json_gen_push_array()\n * and json_gen_end_array()/json_gen_pop_array()\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n * \\param[in] val Boolean value of the element\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_arr_set_bool(json_gen_str_t *jstr, bool val);\n\n/** Add an integer element to an array\n *\n * \\note This must be called between json_gen_start_array()/json_gen_push_array()\n * and json_gen_end_array()/json_gen_pop_array()\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n * \\param[in] val Integer value of the element\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_arr_set_int(json_gen_str_t *jstr, int val);\n\n/** Add a 64 bit integer element to an array\n *\n * \\note This must be called between json_gen_start_array()/json_gen_push_array()\n * and json_gen_end_array()/json_gen_pop_array()\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n * \\param[in] val 64 bit integer value of the element\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_arr_set_int64(json_gen_str_t *jstr, int64_t val);\n\n/** Add a float element to an array\n *\n * \\note This must be called between json_gen_start_array()/json_gen_push_array()\n * and json_gen_end_array()/json_gen_pop_array()\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n * \\param[in] val Float value of the element\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_arr_set_float(json_gen_str_t *jstr, float val);\n\n/** Add a string element to an array\n *\n * \\note This must be called between json_gen_start_array()/json_gen_push_array()\n * and json_gen_end_array()/json_gen_pop_array()\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n * \\param[in] val Null terminated string value of the element\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_arr_set_string(json_gen_str_t *jstr, const char *val);\n\n/** Add a NULL element to an array\n *\n * \\note This must be called between json_gen_start_array()/json_gen_push_array()\n * and json_gen_end_array()/json_gen_pop_array()\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_arr_set_null(json_gen_str_t *jstr);\n\n/** Start a Long string in an object\n *\n * This starts a string in an object, but does not end it (i.e., does not add the\n * terminating quotes. This is useful for long strings. Eg. \"string_val\":\"my_string.\n * The API json_gen_add_to_long_string() must be used to add to this string and the API\n * json_gen_end_long_string() must be used to terminate it (i.e. add the ending quotes).\n *\n * \\note This must be called between json_gen_start_object()/json_gen_push_object()\n * and json_gen_end_object()/json_gen_pop_object()\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n * \\param[in] name Name of the element\n * \\param[in] val Null terminated initial part of the string value. It can also be NULL\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_obj_start_long_string(json_gen_str_t *jstr, const char *name, const char *val);\n\n/** Start a Long string in an array\n *\n * This starts a string in an arrayt, but does not end it (i.e., does not add the\n * terminating quotes. This is useful for long strings.\n * The API json_gen_add_to_long_string() must be used to add to this string and the API\n * json_gen_end_long_string() must be used to terminate it (i.e. add the ending quotes).\n *\n * \\note This must be called between json_gen_start_array()/json_gen_push_array()\n * and json_gen_end_array()/json_gen_pop_array()\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by\n * json_gen_str_start()\n * \\param[in] val Null terminated initial part of the string value. It can also be NULL\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_arr_start_long_string(json_gen_str_t *jstr, const char *val);\n\n/** Add to a JSON Long string\n *\n * This extends the string initialised by json_gen_obj_start_long_string() or\n * json_gen_arr_start_long_string(). After the entire string is created, it should be terminated\n * with json_gen_end_long_string().\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by json_gen_str_start()\n * \\param[in] val Null terminated extending part of the string value.\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_add_to_long_string(json_gen_str_t *jstr, const char *val);\n\n/** End a JSON Long string\n *\n * This ends the string initialised by json_gen_obj_start_long_string() or\n * json_gen_arr_start_long_string() by adding the ending quotes.\n *\n * \\param[in] jstr Pointer to the \\ref json_gen_str_t structure initialised by json_gen_str_start()\n *\n *\n * \\return 0 on Success\n * \\return -1 if buffer is out of space (possible only if no callback function\n * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data\n * added after that\n */\nint json_gen_end_long_string(json_gen_str_t *jstr);\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "json_generator/src/json_generator.c",
    "content": "/*\n *    Copyright 2020 Piyush Shah <shahpiyushv@gmail.com>\n *\n *   Licensed under the Apache License, Version 2.0 (the \"License\");\n *   you may not use this file except in compliance with the License.\n *   You may obtain a copy of the License at\n *\n *       http://www.apache.org/licenses/LICENSE-2.0\n *\n *   Unless required by applicable law or agreed to in writing, software\n *   distributed under the License is distributed on an \"AS IS\" BASIS,\n *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *   See the License for the specific language governing permissions and\n *   limitations under the License.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <stdbool.h>\n#include <string.h>\n#include <inttypes.h>\n\n#include <json_generator.h>\n\n#define MAX_INT_IN_STR      24\n#define MAX_INT64_IN_STR    24\n#define MAX_FLOAT_IN_STR    30\n\nstatic inline int json_gen_get_empty_len(json_gen_str_t *jstr)\n{\n    return (jstr->buf_size - (jstr->free_ptr - jstr->buf) - 1);\n}\n\n/* This will add the incoming string to the JSON string buffer\n * and flush it out if the buffer is full. Note that the data being\n * flushed out will always be equal to the size of the buffer unless\n * this is the last chunk being flushed out on json_gen_end_str()\n */\nstatic int json_gen_add_to_str(json_gen_str_t *jstr, const char *str)\n{\n    if (!str) {\n        return 0;\n    }\n    int len = strlen(str);\n    jstr->total_len += len;\n    if (jstr->buf == NULL) {\n        return 0;\n    }\n    const char *cur_ptr = str;\n    while (1) {\n        int len_remaining = json_gen_get_empty_len(jstr);\n        int copy_len = len_remaining > len ? len : len_remaining;\n        memmove(jstr->free_ptr, cur_ptr, copy_len);\n        cur_ptr += copy_len;\n        jstr->free_ptr += copy_len;\n        len -= copy_len;\n        if (len) {\n            *jstr->free_ptr = '\\0';\n            /* Report error if the buffer is full and no flush callback\n             * is registered\n             */\n            if (!jstr->flush_cb) {\n                return -1;\n            }\n            jstr->flush_cb(jstr->buf, jstr->priv);\n            jstr->free_ptr = jstr->buf;\n        } else {\n            break;\n        }\n    }\n    return 0;\n}\n\n\nvoid json_gen_str_start(json_gen_str_t *jstr, char *buf, int buf_size,\n                        json_gen_flush_cb_t flush_cb, void *priv)\n{\n    memset(jstr, 0, sizeof(json_gen_str_t));\n    jstr->buf = buf;\n    jstr->buf_size = buf_size;\n    jstr->flush_cb = flush_cb;\n    jstr->free_ptr = buf;\n    jstr->priv = priv;\n}\n\nint json_gen_str_end(json_gen_str_t *jstr)\n{\n    int total_len = jstr->total_len;\n    if (jstr->buf) {\n        *jstr->free_ptr = '\\0';\n        if (jstr->flush_cb) {\n            jstr->flush_cb(jstr->buf, jstr->priv);\n        }\n    }\n    memset(jstr, 0, sizeof(json_gen_str_t));\n    return total_len + 1; /* +1 for the NULL termination */\n}\n\nstatic inline void json_gen_handle_comma(json_gen_str_t *jstr)\n{\n    if (jstr->comma_req) {\n        json_gen_add_to_str(jstr, \",\");\n    }\n}\n\n\nstatic int json_gen_handle_name(json_gen_str_t *jstr, const char *name)\n{\n    json_gen_add_to_str(jstr, \"\\\"\");\n    json_gen_add_to_str(jstr, name);\n    return json_gen_add_to_str(jstr, \"\\\":\");\n}\n\n\nint json_gen_start_object(json_gen_str_t *jstr)\n{\n    json_gen_handle_comma(jstr);\n    jstr->comma_req = false;\n    return json_gen_add_to_str(jstr, \"{\");\n}\n\nint json_gen_end_object(json_gen_str_t *jstr)\n{\n    jstr->comma_req = true;\n    return json_gen_add_to_str(jstr, \"}\");\n}\n\n\nint json_gen_start_array(json_gen_str_t *jstr)\n{\n    json_gen_handle_comma(jstr);\n    jstr->comma_req = false;\n    return json_gen_add_to_str(jstr, \"[\");\n}\n\nint json_gen_end_array(json_gen_str_t *jstr)\n{\n    jstr->comma_req = true;\n    return json_gen_add_to_str(jstr, \"]\");\n}\n\nint json_gen_push_object(json_gen_str_t *jstr, const char *name)\n{\n    json_gen_handle_comma(jstr);\n    json_gen_handle_name(jstr, name);\n    jstr->comma_req = false;\n    return json_gen_add_to_str(jstr, \"{\");\n}\n\nint json_gen_pop_object(json_gen_str_t *jstr)\n{\n    jstr->comma_req = true;\n    return json_gen_add_to_str(jstr, \"}\");\n}\n\nint json_gen_push_object_str(json_gen_str_t *jstr, const char *name, const char *object_str)\n{\n    json_gen_handle_comma(jstr);\n    json_gen_handle_name(jstr, name);\n    jstr->comma_req = true;\n    return json_gen_add_to_str(jstr, object_str);\n}\n\nint json_gen_push_array(json_gen_str_t *jstr, const char *name)\n{\n    json_gen_handle_comma(jstr);\n    json_gen_handle_name(jstr, name);\n    jstr->comma_req = false;\n    return json_gen_add_to_str(jstr, \"[\");\n}\nint json_gen_pop_array(json_gen_str_t *jstr)\n{\n    jstr->comma_req = true;\n    return json_gen_add_to_str(jstr, \"]\");\n}\n\nint json_gen_push_array_str(json_gen_str_t *jstr, const char *name, const char *array_str)\n{\n    json_gen_handle_comma(jstr);\n    json_gen_handle_name(jstr, name);\n    jstr->comma_req = true;\n    return json_gen_add_to_str(jstr, array_str);\n}\n\nstatic int json_gen_set_bool(json_gen_str_t *jstr, bool val)\n{\n    jstr->comma_req = true;\n    if (val) {\n        return json_gen_add_to_str(jstr, \"true\");\n    } else {\n        return json_gen_add_to_str(jstr, \"false\");\n    }\n}\nint json_gen_obj_set_bool(json_gen_str_t *jstr, const char *name, bool val)\n{\n    json_gen_handle_comma(jstr);\n    json_gen_handle_name(jstr, name);\n    return json_gen_set_bool(jstr, val);\n}\n\nint json_gen_arr_set_bool(json_gen_str_t *jstr, bool val)\n{\n    json_gen_handle_comma(jstr);\n    return json_gen_set_bool(jstr, val);\n}\n\nstatic int json_gen_set_int(json_gen_str_t *jstr, int val)\n{\n    jstr->comma_req = true;\n    char str[MAX_INT_IN_STR];\n    snprintf(str, MAX_INT_IN_STR, \"%d\", val);\n    return json_gen_add_to_str(jstr, str);\n}\n\nint json_gen_obj_set_int(json_gen_str_t *jstr, const char *name, int val)\n{\n    json_gen_handle_comma(jstr);\n    json_gen_handle_name(jstr, name);\n    return json_gen_set_int(jstr, val);\n}\n\nint json_gen_arr_set_int(json_gen_str_t *jstr, int val)\n{\n    json_gen_handle_comma(jstr);\n    return json_gen_set_int(jstr, val);\n}\n\nstatic int json_gen_set_int64(json_gen_str_t *jstr, int64_t val)\n{\n    jstr->comma_req = true;\n    char str[MAX_INT64_IN_STR];\n    snprintf(str, MAX_INT64_IN_STR, \"%\" PRId64, val);\n    return json_gen_add_to_str(jstr, str);\n}\n\nint json_gen_obj_set_int64(json_gen_str_t *jstr, const char *name, int64_t val)\n{\n    json_gen_handle_comma(jstr);\n    json_gen_handle_name(jstr, name);\n    return json_gen_set_int64(jstr, val);\n}\n\nint json_gen_arr_set_int64(json_gen_str_t *jstr, int64_t val)\n{\n    json_gen_handle_comma(jstr);\n    return json_gen_set_int64(jstr, val);\n}\n\nstatic int json_gen_set_float(json_gen_str_t *jstr, float val)\n{\n    jstr->comma_req = true;\n    char str[MAX_FLOAT_IN_STR];\n    snprintf(str, MAX_FLOAT_IN_STR, \"%.*f\", JSON_FLOAT_PRECISION, val);\n    return json_gen_add_to_str(jstr, str);\n}\nint json_gen_obj_set_float(json_gen_str_t *jstr, const char *name, float val)\n{\n    json_gen_handle_comma(jstr);\n    json_gen_handle_name(jstr, name);\n    return json_gen_set_float(jstr, val);\n}\nint json_gen_arr_set_float(json_gen_str_t *jstr, float val)\n{\n    json_gen_handle_comma(jstr);\n    return json_gen_set_float(jstr, val);\n}\n\nstatic int json_gen_set_string(json_gen_str_t *jstr, const char *val)\n{\n    jstr->comma_req = true;\n    json_gen_add_to_str(jstr, \"\\\"\");\n    json_gen_add_to_str(jstr, val);\n    return json_gen_add_to_str(jstr, \"\\\"\");\n}\n\nint json_gen_obj_set_string(json_gen_str_t *jstr, const char *name, const char *val)\n{\n    json_gen_handle_comma(jstr);\n    json_gen_handle_name(jstr, name);\n    return json_gen_set_string(jstr, val);\n}\n\nint json_gen_arr_set_string(json_gen_str_t *jstr, const char *val)\n{\n    json_gen_handle_comma(jstr);\n    return json_gen_set_string(jstr, val);\n}\n\nstatic int json_gen_set_long_string(json_gen_str_t *jstr, const char *val)\n{\n    jstr->comma_req = true;\n    json_gen_add_to_str(jstr, \"\\\"\");\n    return json_gen_add_to_str(jstr, val);\n}\n\nint json_gen_obj_start_long_string(json_gen_str_t *jstr, const char *name, const char *val)\n{\n    json_gen_handle_comma(jstr);\n    json_gen_handle_name(jstr, name);\n    return json_gen_set_long_string(jstr, val);\n}\n\nint json_gen_arr_start_long_string(json_gen_str_t *jstr, const char *val)\n{\n    json_gen_handle_comma(jstr);\n    return json_gen_set_long_string(jstr, val);\n}\n\nint json_gen_add_to_long_string(json_gen_str_t *jstr, const char *val)\n{\n    return json_gen_add_to_str(jstr, val);\n}\n\nint json_gen_end_long_string(json_gen_str_t *jstr)\n{\n    return json_gen_add_to_str(jstr, \"\\\"\");\n}\nstatic int json_gen_set_null(json_gen_str_t *jstr)\n{\n    jstr->comma_req = true;\n    return json_gen_add_to_str(jstr, \"null\");\n}\nint json_gen_obj_set_null(json_gen_str_t *jstr, const char *name)\n{\n    json_gen_handle_comma(jstr);\n    json_gen_handle_name(jstr, name);\n    return json_gen_set_null(jstr);\n}\n\nint json_gen_arr_set_null(json_gen_str_t *jstr)\n{\n    json_gen_handle_comma(jstr);\n    return json_gen_set_null(jstr);\n}\n"
  },
  {
    "path": "json_generator/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(json_generator_test)\n"
  },
  {
    "path": "json_generator/test_apps/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"json_generator_test.c\"\n                    INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES unity)\n\n"
  },
  {
    "path": "json_generator/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/json_generator:\n    version: \"*\"\n    override_path: \"../..\"\n"
  },
  {
    "path": "json_generator/test_apps/main/json_generator_test.c",
    "content": "#include <stdio.h>\n\nvoid app_main(void)\n{\n\n}\n"
  },
  {
    "path": "json_parser/.build-test-rules.yml",
    "content": "json_parser/test_apps:\n  enable:\n    - if: IDF_TARGET in [\"esp32\", \"esp32c3\"]\n      reason: \"Sufficient to test on one Xtensa and one RISC-V target\"\n"
  },
  {
    "path": "json_parser/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"src/json_parser.c\"\n                    INCLUDE_DIRS \"include\"\n                    REQUIRES \"jsmn\"\n                    )\n"
  },
  {
    "path": "json_parser/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2020 Piyush Shah <shahpiyushv@gmail.com>\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "json_parser/README.md",
    "content": "# JSON Parser\n\n[![Component Registry](https://components.espressif.com/components/espressif/json_parser/badge.svg)](https://components.espressif.com/components/espressif/json_parser)\n\nThis is a simple, light weight JSON parser built on top of [jsmn](https://github.com/zserge/jsmn).\n\nFiles\n\n- `src/json_parser.c`: Source file which has all the logic for implementing the APIs built on top of JSMN\n- `include/json_parser.h`: Header file that exposes all APIs\n"
  },
  {
    "path": "json_parser/idf_component.yml",
    "content": "version: \"1.0.3\"\ndescription: This is a simple, light weight JSON parser built on top of jsmn\nurl: https://github.com/espressif/json_parser\ndependencies:\n  jsmn:\n    version: \"~1.1\"\n    rules:\n      - if: \"idf_version >=5.0\"\n    override_path: \"../jsmn/\"\n"
  },
  {
    "path": "json_parser/include/json_parser.h",
    "content": "/*\n *    Copyright 2020 Piyush Shah <shahpiyushv@gmail.com>\n *\n *   Licensed under the Apache License, Version 2.0 (the \"License\");\n *   you may not use this file except in compliance with the License.\n *   You may obtain a copy of the License at\n *\n *       http://www.apache.org/licenses/LICENSE-2.0\n *\n *   Unless required by applicable law or agreed to in writing, software\n *   distributed under the License is distributed on an \"AS IS\" BASIS,\n *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *   See the License for the specific language governing permissions and\n *   limitations under the License.\n */\n#ifndef _JSON_PARSER_H_\n#define _JSON_PARSER_H_\n\n#define JSMN_PARENT_LINKS\n#define JSMN_HEADER\n#include <jsmn.h>\n#include <stdint.h>\n#include <stdbool.h>\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\n#define OS_SUCCESS  0\n#define OS_FAIL     -1\n\ntypedef jsmn_parser json_parser_t;\ntypedef jsmntok_t json_tok_t;\n\ntypedef struct {\n    json_parser_t parser;\n    const char *js;\n    json_tok_t *tokens;\n    json_tok_t *cur;\n    int num_tokens;\n} jparse_ctx_t;\n\nint json_parse_start(jparse_ctx_t *jctx, const char *js, int len);\nint json_parse_end(jparse_ctx_t *jctx);\nint json_parse_start_static(jparse_ctx_t *jctx, const char *js, int len, json_tok_t *buffer_tokens, int buffer_tokens_max_count);\nint json_parse_end_static(jparse_ctx_t *jctx);\n\nint json_obj_get_array(jparse_ctx_t *jctx, const char *name, int *num_elem);\nint json_obj_leave_array(jparse_ctx_t *jctx);\nint json_obj_get_object(jparse_ctx_t *jctx, const char *name);\nint json_obj_leave_object(jparse_ctx_t *jctx);\nint json_obj_get_bool(jparse_ctx_t *jctx, const char *name, bool *val);\nint json_obj_get_int(jparse_ctx_t *jctx, const char *name, int *val);\nint json_obj_get_int64(jparse_ctx_t *jctx, const char *name, int64_t *val);\nint json_obj_get_float(jparse_ctx_t *jctx, const char *name, float *val);\nint json_obj_get_string(jparse_ctx_t *jctx, const char *name, char *val, int size);\nint json_obj_get_strlen(jparse_ctx_t *jctx, const char *name, int *strlen);\nint json_obj_get_object_str(jparse_ctx_t *jctx, const char *name, char *val, int size);\nint json_obj_get_object_strlen(jparse_ctx_t *jctx, const char *name, int *strlen);\nint json_obj_get_array_str(jparse_ctx_t *jctx, const char *name, char *val, int size);\nint json_obj_get_array_strlen(jparse_ctx_t *jctx, const char *name, int *strlen);\n\nint json_arr_get_array(jparse_ctx_t *jctx, uint32_t index);\nint json_arr_leave_array(jparse_ctx_t *jctx);\nint json_arr_get_object(jparse_ctx_t *jctx, uint32_t index);\nint json_arr_leave_object(jparse_ctx_t *jctx);\nint json_arr_get_bool(jparse_ctx_t *jctx, uint32_t index, bool *val);\nint json_arr_get_int(jparse_ctx_t *jctx, uint32_t index, int *val);\nint json_arr_get_int64(jparse_ctx_t *jctx, uint32_t index, int64_t *val);\nint json_arr_get_float(jparse_ctx_t *jctx, uint32_t index, float *val);\nint json_arr_get_string(jparse_ctx_t *jctx, uint32_t index, char *val, int size);\nint json_arr_get_strlen(jparse_ctx_t *jctx, uint32_t index, int *strlen);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _JSON_PARSER_H_ */\n\n"
  },
  {
    "path": "json_parser/src/json_parser.c",
    "content": "/*\n *    Copyright 2020 Piyush Shah <shahpiyushv@gmail.com>\n *\n *   Licensed under the Apache License, Version 2.0 (the \"License\");\n *   you may not use this file except in compliance with the License.\n *   You may obtain a copy of the License at\n *\n *       http://www.apache.org/licenses/LICENSE-2.0\n *\n *   Unless required by applicable law or agreed to in writing, software\n *   distributed under the License is distributed on an \"AS IS\" BASIS,\n *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *   See the License for the specific language governing permissions and\n *   limitations under the License.\n */\n#include <stdint.h>\n#include <stdbool.h>\n#include <string.h>\n#include <stdlib.h>\n#define JSMN_PARENT_LINKS\n#define JSMN_STRICT\n#define JSMN_STATIC\n#include <jsmn.h>\n#include <json_parser.h>\n\nstatic bool token_matches_str(jparse_ctx_t *ctx, json_tok_t *tok, const char *str)\n{\n    const char *js = ctx->js;\n    return ((strncmp(js + tok->start, str, strlen(str)) == 0)\n            && (strlen(str) == (size_t) (tok->end - tok->start)));\n}\n\nstatic json_tok_t *json_skip_elem(json_tok_t *token)\n{\n    json_tok_t *cur = token;\n    int cnt = cur->size;\n    while (cnt--) {\n        cur++;\n        cur = json_skip_elem(cur);\n    }\n    return cur;\n}\n\nstatic int json_tok_to_bool(jparse_ctx_t *jctx, json_tok_t *tok, bool *val)\n{\n    if (token_matches_str(jctx, tok, \"true\") || token_matches_str(jctx, tok, \"1\")) {\n        *val = true;\n    } else if  (token_matches_str(jctx, tok, \"false\") || token_matches_str(jctx, tok, \"0\")) {\n        *val = false;\n    } else {\n        return -OS_FAIL;\n    }\n    return OS_SUCCESS;\n}\n\nstatic int json_tok_to_int(jparse_ctx_t *jctx, json_tok_t *tok, int *val)\n{\n    const char *tok_start = &jctx->js[tok->start];\n    const char *tok_end = &jctx->js[tok->end];\n    char *endptr;\n    int i = strtoul(tok_start, &endptr, 10);\n    if (endptr == tok_end) {\n        *val = i;\n        return OS_SUCCESS;\n    }\n    return -OS_FAIL;\n}\n\nstatic int json_tok_to_int64(jparse_ctx_t *jctx, json_tok_t *tok, int64_t *val)\n{\n    const char *tok_start = &jctx->js[tok->start];\n    const char *tok_end = &jctx->js[tok->end];\n    char *endptr;\n    int64_t i64 = strtoull(tok_start, &endptr, 10);\n    if (endptr == tok_end) {\n        *val = i64;\n        return OS_SUCCESS;\n    }\n    return -OS_FAIL;\n}\n\nstatic int json_tok_to_float(jparse_ctx_t *jctx, json_tok_t *tok, float *val)\n{\n    const char *tok_start = &jctx->js[tok->start];\n    const char *tok_end = &jctx->js[tok->end];\n    char *endptr;\n    float f = strtof(tok_start, &endptr);\n    if (endptr == tok_end) {\n        *val = f;\n        return OS_SUCCESS;\n    }\n    return -OS_FAIL;\n}\n\nstatic int json_tok_to_string(jparse_ctx_t *jctx, json_tok_t *tok, char *val, int size)\n{\n    if ((tok->end - tok->start) > (size - 1)) {\n        return -OS_FAIL;\n    }\n    strncpy(val, jctx->js + tok->start, tok->end - tok->start);\n    val[tok->end - tok->start] = 0;\n    return OS_SUCCESS;\n}\n\nstatic json_tok_t *json_obj_search(jparse_ctx_t *jctx, const char *key)\n{\n    json_tok_t *tok = jctx->cur;\n    int size = tok->size;\n    if (size <= 0) {\n        return NULL;\n    }\n    if (tok->type != JSMN_OBJECT) {\n        return NULL;\n    }\n\n    while (size--) {\n        tok++;\n        if (token_matches_str(jctx, tok, key)) {\n            return tok;\n        }\n        tok = json_skip_elem(tok);\n    }\n    return NULL;\n}\n\nstatic json_tok_t *json_obj_get_val_tok(jparse_ctx_t *jctx, const char *name, jsmntype_t type)\n{\n    json_tok_t *tok = json_obj_search(jctx, name);\n    if (!tok) {\n        return NULL;\n    }\n    tok++;\n    if (tok->type != type) {\n        return NULL;\n    }\n    return tok;\n}\n\nint json_obj_get_array(jparse_ctx_t *jctx, const char *name, int *num_elem)\n{\n    json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_ARRAY);\n    if (!tok) {\n        return -OS_FAIL;\n    }\n    jctx->cur = tok;\n    *num_elem = tok->size;\n    return OS_SUCCESS;\n}\n\nint json_obj_leave_array(jparse_ctx_t *jctx)\n{\n    /* The array's parent will be the key */\n    if (jctx->cur->parent < 0) {\n        return -OS_FAIL;\n    }\n    jctx->cur = &jctx->tokens[jctx->cur->parent];\n\n    /* The key's parent will be the actual parent object */\n    if (jctx->cur->parent < 0) {\n        return -OS_FAIL;\n    }\n    jctx->cur = &jctx->tokens[jctx->cur->parent];\n    return OS_SUCCESS;\n}\n\nint json_obj_get_object(jparse_ctx_t *jctx, const char *name)\n{\n    json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_OBJECT);\n    if (!tok) {\n        return -OS_FAIL;\n    }\n    jctx->cur = tok;\n    return OS_SUCCESS;\n}\n\nint json_obj_leave_object(jparse_ctx_t *jctx)\n{\n    /* The objects's parent will be the key */\n    if (jctx->cur->parent < 0) {\n        return -OS_FAIL;\n    }\n    jctx->cur = &jctx->tokens[jctx->cur->parent];\n\n    /* The key's parent will be the actual parent object */\n    if (jctx->cur->parent < 0) {\n        return -OS_FAIL;\n    }\n    jctx->cur = &jctx->tokens[jctx->cur->parent];\n    return OS_SUCCESS;\n}\n\nint json_obj_get_bool(jparse_ctx_t *jctx, const char *name, bool *val)\n{\n    json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_PRIMITIVE);\n    if (!tok) {\n        return -OS_FAIL;\n    }\n    return json_tok_to_bool(jctx, tok, val);\n}\n\nint json_obj_get_int(jparse_ctx_t *jctx, const char *name, int *val)\n{\n    json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_PRIMITIVE);\n    if (!tok) {\n        return -OS_FAIL;\n    }\n    return json_tok_to_int(jctx, tok, val);\n}\n\nint json_obj_get_int64(jparse_ctx_t *jctx, const char *name, int64_t *val)\n{\n    json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_PRIMITIVE);\n    if (!tok) {\n        return -OS_FAIL;\n    }\n    return json_tok_to_int64(jctx, tok, val);\n}\n\nint json_obj_get_float(jparse_ctx_t *jctx, const char *name, float *val)\n{\n    json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_PRIMITIVE);\n    if (!tok) {\n        return -OS_FAIL;\n    }\n    return json_tok_to_float(jctx, tok, val);\n}\n\nint json_obj_get_string(jparse_ctx_t *jctx, const char *name, char *val, int size)\n{\n    json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_STRING);\n    if (!tok) {\n        return -OS_FAIL;\n    }\n    return json_tok_to_string(jctx, tok, val, size);\n}\n\nint json_obj_get_strlen(jparse_ctx_t *jctx, const char *name, int *strlen)\n{\n    json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_STRING);\n    if (!tok) {\n        return -OS_FAIL;\n    }\n    *strlen = tok->end - tok->start;\n    return OS_SUCCESS;\n}\n\nint json_obj_get_object_str(jparse_ctx_t *jctx, const char *name, char *val, int size)\n{\n    json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_OBJECT);\n    if (!tok) {\n        return -OS_FAIL;\n    }\n    return json_tok_to_string(jctx, tok, val, size);\n}\n\nint json_obj_get_object_strlen(jparse_ctx_t *jctx, const char *name, int *strlen)\n{\n    json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_OBJECT);\n    if (!tok) {\n        return -OS_FAIL;\n    }\n    *strlen = tok->end - tok->start;\n    return OS_SUCCESS;\n}\nint json_obj_get_array_str(jparse_ctx_t *jctx, const char *name, char *val, int size)\n{\n    json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_ARRAY);\n    if (!tok) {\n        return -OS_FAIL;\n    }\n    return json_tok_to_string(jctx, tok, val, size);\n}\n\nint json_obj_get_array_strlen(jparse_ctx_t *jctx, const char *name, int *strlen)\n{\n    json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_ARRAY);\n    if (!tok) {\n        return -OS_FAIL;\n    }\n    *strlen = tok->end - tok->start;\n    return OS_SUCCESS;\n}\n\nstatic json_tok_t *json_arr_search(jparse_ctx_t *ctx, uint32_t index)\n{\n    json_tok_t *tok = ctx->cur;\n    if ((tok->type != JSMN_ARRAY) || (tok->size <= 0)) {\n        return NULL;\n    }\n    if (index > (uint32_t)(tok->size - 1)) {\n        return NULL;\n    }\n    /* Increment by 1, so that token points to index 0 */\n    tok++;\n    while (index--) {\n        tok = json_skip_elem(tok);\n        tok++;\n    }\n    return tok;\n}\nstatic json_tok_t *json_arr_get_val_tok(jparse_ctx_t *jctx, uint32_t index, jsmntype_t type)\n{\n    json_tok_t *tok = json_arr_search(jctx, index);\n    if (!tok) {\n        return NULL;\n    }\n    if (tok->type != type) {\n        return NULL;\n    }\n    return tok;\n}\n\nint json_arr_get_array(jparse_ctx_t *jctx, uint32_t index)\n{\n    json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_ARRAY);\n    if (!tok) {\n        return -OS_FAIL;\n    }\n    jctx->cur = tok;\n    return OS_SUCCESS;\n}\n\nint json_arr_leave_array(jparse_ctx_t *jctx)\n{\n    if (jctx->cur->parent < 0) {\n        return -OS_FAIL;\n    }\n    jctx->cur = &jctx->tokens[jctx->cur->parent];\n    return OS_SUCCESS;\n}\n\nint json_arr_get_object(jparse_ctx_t *jctx, uint32_t index)\n{\n    json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_OBJECT);\n    if (!tok) {\n        return -OS_FAIL;\n    }\n    jctx->cur = tok;\n    return OS_SUCCESS;\n}\n\nint json_arr_leave_object(jparse_ctx_t *jctx)\n{\n    if (jctx->cur->parent < 0) {\n        return -OS_FAIL;\n    }\n    jctx->cur = &jctx->tokens[jctx->cur->parent];\n    return OS_SUCCESS;\n}\n\nint json_arr_get_bool(jparse_ctx_t *jctx, uint32_t index, bool *val)\n{\n    json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_PRIMITIVE);\n    if (!tok) {\n        return -OS_FAIL;\n    }\n    return json_tok_to_bool(jctx, tok, val);\n}\n\nint json_arr_get_int(jparse_ctx_t *jctx, uint32_t index, int *val)\n{\n    json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_PRIMITIVE);\n    if (!tok) {\n        return -OS_FAIL;\n    }\n    return json_tok_to_int(jctx, tok, val);\n}\n\nint json_arr_get_int64(jparse_ctx_t *jctx, uint32_t index, int64_t *val)\n{\n    json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_PRIMITIVE);\n    if (!tok) {\n        return -OS_FAIL;\n    }\n    return json_tok_to_int64(jctx, tok, val);\n}\n\nint json_arr_get_float(jparse_ctx_t *jctx, uint32_t index, float *val)\n{\n    json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_PRIMITIVE);\n    if (!tok) {\n        return -OS_FAIL;\n    }\n    return json_tok_to_float(jctx, tok, val);\n}\n\nint json_arr_get_string(jparse_ctx_t *jctx, uint32_t index, char *val, int size)\n{\n    json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_STRING);\n    if (!tok) {\n        return -OS_FAIL;\n    }\n    return json_tok_to_string(jctx, tok, val, size);\n}\n\nint json_arr_get_strlen(jparse_ctx_t *jctx, uint32_t index, int *strlen)\n{\n    json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_STRING);\n    if (!tok) {\n        return -OS_FAIL;\n    }\n    *strlen = tok->end - tok->start;\n    return OS_SUCCESS;\n}\n\nint json_parse_start(jparse_ctx_t *jctx, const char *js, int len)\n{\n    memset(jctx, 0, sizeof(jparse_ctx_t));\n    jsmn_init(&jctx->parser);\n    int num_tokens = jsmn_parse(&jctx->parser, js, len, NULL, 0);\n    if (num_tokens <= 0) {\n        return -OS_FAIL;\n    }\n    jctx->num_tokens = num_tokens;\n    jctx->tokens = calloc(num_tokens, sizeof(json_tok_t));\n    if (!jctx->tokens) {\n        return -OS_FAIL;\n    }\n    jctx->js = js;\n    jsmn_init(&jctx->parser);\n    int ret = jsmn_parse(&jctx->parser, js, len, jctx->tokens, jctx->num_tokens);\n    if (ret <= 0) {\n        free(jctx->tokens);\n        memset(jctx, 0, sizeof(jparse_ctx_t));\n        return -OS_FAIL;\n    }\n    jctx->cur = jctx->tokens;\n    return OS_SUCCESS;\n}\n\nint json_parse_end(jparse_ctx_t *jctx)\n{\n    if (jctx->tokens) {\n        free(jctx->tokens);\n    }\n    memset(jctx, 0, sizeof(jparse_ctx_t));\n    return OS_SUCCESS;\n}\n\nint json_parse_start_static(jparse_ctx_t *jctx, const char *js, int len, json_tok_t *buffer_tokens, int buffer_tokens_max_count)\n{\n    // Init\n    memset(buffer_tokens, 0, buffer_tokens_max_count * sizeof(json_tok_t));\n    memset(jctx, 0, sizeof(jparse_ctx_t));\n\n    // Check fit\n    jsmn_init(&jctx->parser);\n    int num_tokens = jsmn_parse(&jctx->parser, js, len, NULL, 0);\n    if (num_tokens <= 0 || num_tokens > buffer_tokens_max_count) {\n        return -OS_FAIL;\n    }\n\n    // Set struct\n    jctx->num_tokens = num_tokens;\n    jctx->tokens = buffer_tokens;\n    jctx->js = js;\n\n    // Parse\n    jsmn_init(&jctx->parser);\n    int ret = jsmn_parse(&jctx->parser, js, len, jctx->tokens, jctx->num_tokens);\n    if (ret <= 0) {\n        memset(jctx, 0, sizeof(jparse_ctx_t));\n        return -OS_FAIL;\n    }\n    jctx->cur = jctx->tokens;\n    return OS_SUCCESS;\n}\n\nint json_parse_end_static(jparse_ctx_t *jctx)\n{\n    memset(jctx, 0, sizeof(jparse_ctx_t));\n    return OS_SUCCESS;\n}\n\n"
  },
  {
    "path": "json_parser/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(json_parser_test)\n"
  },
  {
    "path": "json_parser/test_apps/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS test_main.c test_json_parser.c\n                       PRIV_REQUIRES unity\n                       WHOLE_ARCHIVE)\n"
  },
  {
    "path": "json_parser/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/json_parser:\n    version: \"*\"\n    override_path: \"../..\"\n"
  },
  {
    "path": "json_parser/test_apps/main/test_json_parser.c",
    "content": "#include <assert.h>\n#include <string.h>\n#include \"json_parser.h\"\n#include \"unity.h\"\n\n#define json_test_str   \"{\\n\\\"str_val\\\" :    \\\"JSON Parser\\\",\\n\" \\\n            \"\\t\\\"float_val\\\" : 2.0,\\n\" \\\n            \"\\\"int_val\\\" : 2017,\\n\" \\\n            \"\\\"bool_val\\\" : false,\\n\" \\\n            \"\\\"supported_el\\\" :\\t [\\\"bool\\\",\\\"int\\\",\"\\\n            \"\\\"float\\\",\\\"str\\\"\" \\\n            \",\\\"object\\\",\\\"array\\\"],\\n\" \\\n            \"\\\"features\\\" : { \\\"objects\\\":true, \"\\\n            \"\\\"arrays\\\":\\\"yes\\\"},\\n\"\\\n            \"\\\"int_64\\\":109174583252}\"\n\nTEST_CASE(\"json_parser basic tests\", \"[json_parser]\")\n{\n    jparse_ctx_t jctx;\n    int ret = json_parse_start(&jctx, json_test_str, strlen(json_test_str));\n    TEST_ASSERT_EQUAL(OS_SUCCESS, ret);\n\n    char str_val[64];\n    int int_val, num_elem;\n    int64_t int64_val;\n    bool bool_val;\n    float float_val;\n\n    TEST_ASSERT_EQUAL(OS_SUCCESS, json_obj_get_string(&jctx, \"str_val\", str_val, sizeof(str_val)));\n    TEST_ASSERT_EQUAL_STRING(\"JSON Parser\", str_val);\n\n    TEST_ASSERT_EQUAL(OS_SUCCESS, json_obj_get_float(&jctx, \"float_val\", &float_val));\n    TEST_ASSERT(fabs(float_val - 2.0f) < 0.0001f);\n\n    TEST_ASSERT_EQUAL(OS_SUCCESS, json_obj_get_int(&jctx, \"int_val\", &int_val));\n    TEST_ASSERT_EQUAL_INT(2017, int_val);\n\n    TEST_ASSERT_EQUAL(OS_SUCCESS, json_obj_get_bool(&jctx, \"bool_val\", &bool_val));\n    TEST_ASSERT_EQUAL(false, bool_val);\n\n    TEST_ASSERT_EQUAL(OS_SUCCESS, json_obj_get_array(&jctx, \"supported_el\", &num_elem));\n    const char *expected_values[] = {\"bool\", \"int\", \"float\", \"str\", \"object\", \"array\"};\n    TEST_ASSERT_EQUAL(sizeof(expected_values) / sizeof(expected_values[0]), num_elem);\n    for (int i = 0; i < num_elem; ++i) {\n        TEST_ASSERT_EQUAL(OS_SUCCESS, json_arr_get_string(&jctx, i, str_val, sizeof(str_val)));\n        TEST_ASSERT_EQUAL_STRING(expected_values[i], str_val);\n    }\n    json_obj_leave_array(&jctx);\n\n    TEST_ASSERT_EQUAL(OS_SUCCESS, json_obj_get_object(&jctx, \"features\"));\n    TEST_ASSERT_EQUAL(OS_SUCCESS, json_obj_get_bool(&jctx, \"objects\", &bool_val));\n    TEST_ASSERT_EQUAL(true, bool_val);\n    TEST_ASSERT_EQUAL(OS_SUCCESS, json_obj_get_string(&jctx, \"arrays\", str_val, sizeof(str_val)));\n    TEST_ASSERT_EQUAL_STRING(\"yes\", str_val);\n    json_obj_leave_object(&jctx);\n\n    TEST_ASSERT_EQUAL(OS_SUCCESS, json_obj_get_int64(&jctx, \"int_64\", &int64_val));\n    TEST_ASSERT(int64_val == 109174583252);\n\n    json_parse_end(&jctx);\n}"
  },
  {
    "path": "json_parser/test_apps/main/test_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"unity.h\"\n#include \"unity_test_runner.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_newlib.h\"\n#include \"unity_test_utils_memory.h\"\n\nvoid setUp(void)\n{\n    unity_utils_record_free_mem();\n}\n\nvoid tearDown(void)\n{\n    esp_reent_cleanup();    //clean up some of the newlib's lazy allocations\n    unity_utils_evaluate_leaks_direct(0);\n}\n\nvoid app_main(void)\n{\n    printf(\"Running json_parser component tests\\n\");\n    unity_run_menu();\n}\n"
  },
  {
    "path": "json_parser/test_apps/pytest_json_parser.py",
    "content": "import pytest\n\n\n@pytest.mark.generic\ndef test_json_parser(dut) -> None:\n    dut.run_all_single_board_cases()\n"
  },
  {
    "path": "json_parser/test_apps/sdkconfig.defaults",
    "content": "# This file was generated using idf.py save-defconfig. It can be edited manually.\n# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration\n#\nCONFIG_ESP_TASK_WDT_INIT=n\n"
  },
  {
    "path": "led_strip/CHANGELOG.md",
    "content": "## 3.0.3\n\n- Support WS2816 with 16-bit color\n\n## 3.0.1\n\n- Support WS2811 bit timing\n\n## 3.0.0\n\n- Discontinued support for ESP-IDF v4.x\n- Added configuration for user-defined color component format\n\n## 2.5.5\n\n- Simplified the led_strip component dependency, the time of full build with ESP-IDF v5.3 can now be shorter.\n\n## 2.5.4\n\n- Inserted extra delay when initialize the SPI LED device, to ensure all LEDs are in the reset state correctly\n\n## 2.5.3\n\n- Extend reset time (280us) to support WS2812B-V5\n\n## 2.5.2\n\n- Added API reference doc (api.md)\n\n## 2.5.0\n\n- Enabled support for IDF4.4 and above\n  - with RMT backend only\n- Added API `led_strip_set_pixel_hsv`\n\n## 2.4.0\n\n- Support configurable SPI mode to control leds\n  - recommend enabling DMA when using SPI mode\n\n## 2.3.0\n\n- Support configurable RMT channel size by setting `mem_block_symbols`\n\n## 2.2.0\n\n- Support for 4 components RGBW leds (SK6812):\n  - in led_strip_config_t new fields\n      led_pixel_format, controlling byte format (LED_PIXEL_FORMAT_GRB, LED_PIXEL_FORMAT_GRBW)\n      led_model, used to configure bit timing (LED_MODEL_WS2812, LED_MODEL_SK6812)\n  - new API led_strip_set_pixel_rgbw\n  - new interface type set_pixel_rgbw\n\n## 2.1.0\n\n- Support DMA feature, which offloads the CPU by a lot when it comes to drive a bunch of LEDs\n- Support various RMT clock sources\n- Acquire and release the power management lock before and after each refresh\n- New driver flag: `invert_out` which can invert the led control signal by hardware\n\n## 2.0.0\n\n- Reimplemented the driver using the new RMT driver (`driver/rmt_tx.h`)\n\n## 1.0.0\n\n- Initial driver version, based on the legacy RMT driver (`driver/rmt.h`)\n"
  },
  {
    "path": "led_strip/CMakeLists.txt",
    "content": "include($ENV{IDF_PATH}/tools/cmake/version.cmake)\n\nset(srcs \"src/led_strip_api.c\")\nset(public_requires)\n\nif(CONFIG_SOC_RMT_SUPPORTED)\n    list(APPEND srcs \"src/led_strip_rmt_dev.c\" \"src/led_strip_rmt_encoder.c\")\nendif()\n\n# the SPI backend driver relies on some feature that was available in IDF 5.1\nif(\"${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}\" VERSION_GREATER_EQUAL \"5.1\")\n    if(CONFIG_SOC_GPSPI_SUPPORTED)\n        list(APPEND srcs \"src/led_strip_spi_dev.c\")\n    endif()\nendif()\n\n# Starting from esp-idf v5.3, the RMT and SPI drivers are moved to separate components\nif(\"${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}\" VERSION_GREATER_EQUAL \"5.3\")\n    list(APPEND public_requires \"esp_driver_rmt\" \"esp_driver_spi\")\nelse()\n    list(APPEND public_requires \"driver\")\nendif()\n\nidf_component_register(SRCS ${srcs}\n                       INCLUDE_DIRS \"include\" \"interface\"\n                       REQUIRES ${public_requires})\n"
  },
  {
    "path": "led_strip/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "led_strip/README.md",
    "content": "# LED Strip Driver\n\n[![Component Registry](https://components.espressif.com/components/espressif/led_strip/badge.svg)](https://components.espressif.com/components/espressif/led_strip)\n\nThis driver is designed for addressable LEDs like [WS2812](http://world-semi.com/ws2812-family/), where each LED is controlled by a single data line.\n\n## Supported Backend Peripherals\n\nThe LED strip driver supports two different backend peripherals to generate the timing signals required by addressable LEDs:\n\n### The [RMT](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/rmt.html) Peripheral\n\nThis is the most economical way to drive the LEDs because it only consumes one RMT channel, leaving other channels free to use. However, the memory usage increases dramatically with the number of LEDs. If the RMT hardware can't be assist by DMA, the driver will going into interrupt very frequently, thus result in a high CPU usage. What's worse, if the RMT interrupt is delayed or not serviced in time (e.g. if Wi-Fi interrupt happens on the same CPU core), the RMT transaction will be corrupted and the LEDs will display incorrect colors. If you want to use RMT to drive a large number of LEDs, you'd better to enable the DMA feature if possible [^1].\n\n### The [SPI](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/spi_master.html) Peripheral\n\nSPI peripheral can also be used to generate the timing required by the LED strip, in a so-called \"Clock-less\" mode. However this backend is not as economical as the RMT one, because it will take up the whole **bus**. You **CANNOT** connect other devices to the same SPI bus if it's been used by the led_strip, because the led_strip doesn't have the concept of \"Chip Select\".\n\n## Documentation\n\nFor detailed information about the LED Strip component, including API reference and user guides, please visit:\n\n-   **Programming Guide & API Reference**: [LED Strip Documentation](https://espressif.github.io/idf-extra-components/latest/led_strip/index.html)\n"
  },
  {
    "path": "led_strip/docs/Doxyfile",
    "content": "# Set this to the header file you want\nINPUT = \\\n    ../include/ \\\n    ../interface/\n\n# The output directory for the generated XML documentation\nOUTPUT_DIRECTORY = doxygen_output\n\n# Warning-related settings, it's recommended to keep them enabled\nWARN_IF_UNDOC_ENUM_VAL = YES\nWARN_AS_ERROR = YES\n\n# Other common settings\nFULL_PATH_NAMES = YES\nSTRIP_FROM_PATH = ../\nSTRIP_FROM_INC_PATH = ../\nENABLE_PREPROCESSING   = YES\nMACRO_EXPANSION        = YES\nOPTIMIZE_OUTPUT_FOR_C  = YES\nEXPAND_ONLY_PREDEF     = YES\nEXTRACT_ALL            = YES\nPREDEFINED             = $(ENV_DOXYGEN_DEFINES)\nHAVE_DOT = NO\nGENERATE_XML    = YES\nXML_OUTPUT      = xml\nGENERATE_HTML   = NO\nHAVE_DOT        = NO\nGENERATE_LATEX  = NO\nQUIET = YES\nMARKDOWN_SUPPORT = YES"
  },
  {
    "path": "led_strip/docs/book.toml",
    "content": "[book]\ntitle = \"LED Strip Documentation\"\nlanguage = \"en\"\n\n[output.html]\ndefault-theme = \"light\"\ngit-repository-url = \"https://github.com/espressif/idf-extra-components/tree/master/led_strip\"\nedit-url-template = \"https://github.com/espressif/idf-extra-components/edit/master/led_strip/docs/{path}\"\n"
  },
  {
    "path": "led_strip/docs/src/SUMMARY.md",
    "content": "# Summary\n\n---\n\n# Programming Guide\n\n- [LED Strip](index.md)\n\n---\n\n# API Reference\n\n- [API Reference](api.md)\n"
  },
  {
    "path": "led_strip/docs/src/api.md",
    "content": "# API Reference\n\n<div class=\"warning\">\n\nThis file is automatically generated by esp-doxybook.\n\nDO NOT edit it manually.\n\n</div>\n"
  },
  {
    "path": "led_strip/docs/src/index.md",
    "content": "# LED Strip Programming Guide\n\n## Allocate LED Strip Object with RMT Backend\n\n```c\n#define BLINK_GPIO 0\n\n/// LED strip common configuration\nled_strip_config_t strip_config = {\n    .strip_gpio_num = BLINK_GPIO,  // The GPIO that connected to the LED strip's data line\n    .max_leds = 1,                 // The number of LEDs in the strip,\n    .led_model = LED_MODEL_WS2812, // LED strip model, it determines the bit timing\n    .color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB, // The color component format is G-R-B\n    .flags = {\n        .invert_out = false, // don't invert the output signal\n    }\n};\n\n/// RMT backend specific configuration\nled_strip_rmt_config_t rmt_config = {\n    .clk_src = RMT_CLK_SRC_DEFAULT,    // different clock source can lead to different power consumption\n    .resolution_hz = 10 * 1000 * 1000, // RMT counter clock frequency: 10MHz\n    .mem_block_symbols = 64,           // the memory size of each RMT channel, in words (4 bytes)\n    .flags = {\n        .with_dma = false, // DMA feature is available on chips like ESP32-S3/P4\n    }\n};\n\n/// Create the LED strip object\nled_strip_handle_t led_strip = NULL;\nESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip));\n```\n\n---\n\nYou can create multiple LED strip objects with different GPIOs and pixel numbers. The backend driver will automatically allocate sufficient RMT channels for you wherever possible. If the RMT channels are not enough, the [led_strip_new_rmt_device](api.md#function-led_strip_new_rmt_device) will return an error.\n\n## Allocate LED Strip Object with SPI Backend\n\n```c\n#define BLINK_GPIO 0\n\n/// LED strip common configuration\nled_strip_config_t strip_config = {\n    .strip_gpio_num = BLINK_GPIO,  // The GPIO that connected to the LED strip's data line\n    .max_leds = 1,                 // The number of LEDs in the strip,\n    .led_model = LED_MODEL_WS2812, // LED strip model, it determines the bit timing\n    .color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB, // The color component format is G-R-B\n    .flags = {\n        .invert_out = false, // don't invert the output signal\n    }\n};\n\n/// SPI backend specific configuration\nled_strip_spi_config_t spi_config = {\n    .clk_src = SPI_CLK_SRC_DEFAULT, // different clock source can lead to different power consumption\n    .spi_bus = SPI2_HOST,           // SPI bus ID\n    .flags = {\n        .with_dma = true, // Using DMA can improve performance and help drive more LEDs\n    }\n};\n\n/// Create the LED strip object\nled_strip_handle_t led_strip = NULL;\nESP_ERROR_CHECK(led_strip_new_spi_device(&strip_config, &spi_config, &led_strip));\n```\n\n---\n\nThe number of LED strip objects can be created depends on how many free SPI controllers are free to use in your project.\n\n## FAQ\n\n-   How to set the brightness of the LED strip?\n    -   You can tune the brightness by scaling the value of each R-G-B element with a **same** factor. But pay attention to the overflow of the value.\n"
  },
  {
    "path": "led_strip/examples/led_strip_rmt_ws2812/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\nset(COMPONENTS main)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nproject(led_strip_rmt_ws2812)\n"
  },
  {
    "path": "led_strip/examples/led_strip_rmt_ws2812/README.md",
    "content": "# LED Strip Example (RMT backend + WS2812)\n\nThis example demonstrates how to blink the WS2812 LED using the [led_strip](https://components.espressif.com/component/espressif/led_strip) component.\n\n## How to Use Example\n\n### Hardware Required\n\n* A development board with Espressif SoC\n* A USB cable for Power supply and programming\n* WS2812 LED strip\n\n### Configure the Example\n\nBefore project configuration and build, be sure to set the correct chip target using `idf.py set-target <chip_name>`. Then assign the proper GPIO in the [source file](main/led_strip_rmt_ws2812_main.c). If your led strip has multiple LEDs, don't forget update the number.\n\n### Build and Flash\n\nRun `idf.py -p PORT build flash monitor` to build, flash and monitor the project.\n\n(To exit the serial monitor, type ``Ctrl-]``.)\n\nSee the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.\n\n## Example Output\n\n```text\nI (299) gpio: GPIO[8]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0\nI (309) example: Created LED strip object with RMT backend\nI (309) example: Start blinking LED strip\n```\n"
  },
  {
    "path": "led_strip/examples/led_strip_rmt_ws2812/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"led_strip_rmt_ws2812_main.c\"\n                       INCLUDE_DIRS \".\")\n"
  },
  {
    "path": "led_strip/examples/led_strip_rmt_ws2812/main/idf_component.yml",
    "content": "## IDF Component Manager Manifest File\ndependencies:\n  espressif/led_strip:\n    version: '^3'\n    override_path: '../../../'\n"
  },
  {
    "path": "led_strip/examples/led_strip_rmt_ws2812/main/led_strip_rmt_ws2812_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n#include <stdio.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"led_strip.h\"\n#include \"esp_log.h\"\n#include \"esp_err.h\"\n\n// Set to 1 to use DMA for driving the LED strip, 0 otherwise\n// Please note the RMT DMA feature is only available on chips e.g. ESP32-S3/P4\n#define LED_STRIP_USE_DMA  0\n\n#if LED_STRIP_USE_DMA\n// Numbers of the LED in the strip\n#define LED_STRIP_LED_COUNT 256\n#define LED_STRIP_MEMORY_BLOCK_WORDS 1024 // this determines the DMA block size\n#else\n// Numbers of the LED in the strip\n#define LED_STRIP_LED_COUNT 24\n#define LED_STRIP_MEMORY_BLOCK_WORDS 0 // let the driver choose a proper memory block size automatically\n#endif // LED_STRIP_USE_DMA\n\n// GPIO assignment\n#define LED_STRIP_GPIO_PIN  2\n\n// 10MHz resolution, 1 tick = 0.1us (led strip needs a high resolution)\n#define LED_STRIP_RMT_RES_HZ  (10 * 1000 * 1000)\n\nstatic const char *TAG = \"example\";\n\nled_strip_handle_t configure_led(void)\n{\n    // LED strip general initialization, according to your led board design\n    led_strip_config_t strip_config = {\n        .strip_gpio_num = LED_STRIP_GPIO_PIN, // The GPIO that connected to the LED strip's data line\n        .max_leds = LED_STRIP_LED_COUNT,      // The number of LEDs in the strip,\n        .led_model = LED_MODEL_WS2812,        // LED strip model\n        .color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB, // The color order of the strip: GRB\n        .flags = {\n            .invert_out = false, // don't invert the output signal\n        }\n    };\n\n    // LED strip backend configuration: RMT\n    led_strip_rmt_config_t rmt_config = {\n        .clk_src = RMT_CLK_SRC_DEFAULT,        // different clock source can lead to different power consumption\n        .resolution_hz = LED_STRIP_RMT_RES_HZ, // RMT counter clock frequency\n        .mem_block_symbols = LED_STRIP_MEMORY_BLOCK_WORDS, // the memory block size used by the RMT channel\n        .flags = {\n            .with_dma = LED_STRIP_USE_DMA,     // Using DMA can improve performance when driving more LEDs\n        }\n    };\n\n    // LED Strip object handle\n    led_strip_handle_t led_strip;\n    ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip));\n    ESP_LOGI(TAG, \"Created LED strip object with RMT backend\");\n    return led_strip;\n}\n\nvoid app_main(void)\n{\n    led_strip_handle_t led_strip = configure_led();\n    bool led_on_off = false;\n\n    ESP_LOGI(TAG, \"Start blinking LED strip\");\n    while (1) {\n        if (led_on_off) {\n            /* Set the LED pixel using RGB from 0 (0%) to 255 (100%) for each color */\n            for (int i = 0; i < LED_STRIP_LED_COUNT; i++) {\n                ESP_ERROR_CHECK(led_strip_set_pixel(led_strip, i, 5, 5, 5));\n            }\n            /* Refresh the strip to send data */\n            ESP_ERROR_CHECK(led_strip_refresh(led_strip));\n            ESP_LOGI(TAG, \"LED ON!\");\n        } else {\n            /* Set all LED off to clear all pixels */\n            ESP_ERROR_CHECK(led_strip_clear(led_strip));\n            ESP_LOGI(TAG, \"LED OFF!\");\n        }\n\n        led_on_off = !led_on_off;\n        vTaskDelay(pdMS_TO_TICKS(500));\n    }\n}\n"
  },
  {
    "path": "led_strip/examples/led_strip_spi_ws2812/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\nset(COMPONENTS main)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nproject(led_strip_spi_ws2812)\n"
  },
  {
    "path": "led_strip/examples/led_strip_spi_ws2812/README.md",
    "content": "# LED Strip Example (SPI backend + WS2812)\n\nThis example demonstrates how to blink the WS2812 LED using the [led_strip](https://components.espressif.com/component/espressif/led_strip) component.\n\n## How to Use Example\n\n### Hardware Required\n\n* A development board with Espressif SoC\n* A USB cable for Power supply and programming\n* WS2812 LED strip\n\n### Configure the Example\n\nBefore project configuration and build, be sure to set the correct chip target using `idf.py set-target <chip_name>`. Then assign the proper GPIO in the [source file](main/led_strip_spi_ws2812_main.c). If your led strip has multiple LEDs, don't forget update the number.\n\n### Build and Flash\n\nRun `idf.py -p PORT build flash monitor` to build, flash and monitor the project.\n\n(To exit the serial monitor, type ``Ctrl-]``.)\n\nSee the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.\n\n## Example Output\n\n```text\nI (299) gpio: GPIO[14]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0\nI (309) example: Created LED strip object with SPI backend\nI (309) example: Start blinking LED strip\n```\n"
  },
  {
    "path": "led_strip/examples/led_strip_spi_ws2812/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"led_strip_spi_ws2812_main.c\"\n                       INCLUDE_DIRS \".\")\n"
  },
  {
    "path": "led_strip/examples/led_strip_spi_ws2812/main/idf_component.yml",
    "content": "## IDF Component Manager Manifest File\ndependencies:\n  espressif/led_strip:\n    version: '^3'\n    override_path: '../../../'\n  idf: \">=5.1\"\n"
  },
  {
    "path": "led_strip/examples/led_strip_spi_ws2812/main/led_strip_spi_ws2812_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n#include <stdio.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"led_strip.h\"\n#include \"esp_log.h\"\n#include \"esp_err.h\"\n\n// GPIO assignment\n#define LED_STRIP_GPIO_PIN  2\n// Numbers of the LED in the strip\n#define LED_STRIP_LED_COUNT 24\n\nstatic const char *TAG = \"example\";\n\nled_strip_handle_t configure_led(void)\n{\n    // LED strip general initialization, according to your led board design\n    led_strip_config_t strip_config = {\n        .strip_gpio_num = LED_STRIP_GPIO_PIN, // The GPIO that connected to the LED strip's data line\n        .max_leds = LED_STRIP_LED_COUNT,      // The number of LEDs in the strip,\n        .led_model = LED_MODEL_WS2812,        // LED strip model\n        // set the color order of the strip: GRB\n        .color_component_format = {\n            .format = {\n                .r_pos = 1, // red is the second byte in the color data\n                .g_pos = 0, // green is the first byte in the color data\n                .b_pos = 2, // blue is the third byte in the color data\n                .num_components = 3, // total 3 color components\n            },\n        },\n        .flags = {\n            .invert_out = false, // don't invert the output signal\n        }\n    };\n\n    // LED strip backend configuration: SPI\n    led_strip_spi_config_t spi_config = {\n        .clk_src = SPI_CLK_SRC_DEFAULT, // different clock source can lead to different power consumption\n        .spi_bus = SPI2_HOST,           // SPI bus ID\n        .flags = {\n            .with_dma = true, // Using DMA can improve performance and help drive more LEDs\n        }\n    };\n\n    // LED Strip object handle\n    led_strip_handle_t led_strip;\n    ESP_ERROR_CHECK(led_strip_new_spi_device(&strip_config, &spi_config, &led_strip));\n    ESP_LOGI(TAG, \"Created LED strip object with SPI backend\");\n    return led_strip;\n}\n\nvoid app_main(void)\n{\n    led_strip_handle_t led_strip = configure_led();\n    bool led_on_off = false;\n\n    ESP_LOGI(TAG, \"Start blinking LED strip\");\n    while (1) {\n        if (led_on_off) {\n            /* Set the LED pixel using RGB from 0 (0%) to 255 (100%) for each color */\n            for (int i = 0; i < LED_STRIP_LED_COUNT; i++) {\n                ESP_ERROR_CHECK(led_strip_set_pixel(led_strip, i, 5, 5, 5));\n            }\n            /* Refresh the strip to send data */\n            ESP_ERROR_CHECK(led_strip_refresh(led_strip));\n            ESP_LOGI(TAG, \"LED ON!\");\n        } else {\n            /* Set all LED off to clear all pixels */\n            ESP_ERROR_CHECK(led_strip_clear(led_strip));\n            ESP_LOGI(TAG, \"LED OFF!\");\n        }\n\n        led_on_off = !led_on_off;\n        vTaskDelay(pdMS_TO_TICKS(500));\n    }\n}\n"
  },
  {
    "path": "led_strip/idf_component.yml",
    "content": "version: \"3.0.3\"\ndescription: Driver for Addressable LED Strip (WS2812, etc)\nurl: https://github.com/espressif/idf-extra-components/tree/master/led_strip\nrepository: https://github.com/espressif/idf-extra-components.git\ndocumentation: https://espressif.github.io/idf-extra-components/latest/led_strip/index.html\nissues: https://github.com/espressif/idf-extra-components/issues\ndependencies:\n  idf: \">=5.0\"\n"
  },
  {
    "path": "led_strip/include/led_strip.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdint.h>\n#include \"esp_err.h\"\n#include \"led_strip_rmt.h\"\n#include \"led_strip_spi.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief Set RGB for a specific pixel\n *\n * @param strip: LED strip\n * @param index: index of pixel to set\n * @param red: red part of color\n * @param green: green part of color\n * @param blue: blue part of color\n *\n * @return\n *      - ESP_OK: Set RGB for a specific pixel successfully\n *      - ESP_ERR_INVALID_ARG: Set RGB for a specific pixel failed because of invalid parameters\n *      - ESP_FAIL: Set RGB for a specific pixel failed because other error occurred\n */\nesp_err_t led_strip_set_pixel(led_strip_handle_t strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue);\n\n/**\n * @brief Set RGBW for a specific pixel\n *\n * @note Only call this function if your led strip does have the white component (e.g. SK6812-RGBW)\n * @note Also see `led_strip_set_pixel` if you only want to specify the RGB part of the color and bypass the white component\n *\n * @param strip: LED strip\n * @param index: index of pixel to set\n * @param red: red part of color\n * @param green: green part of color\n * @param blue: blue part of color\n * @param white: separate white component\n *\n * @return\n *      - ESP_OK: Set RGBW color for a specific pixel successfully\n *      - ESP_ERR_INVALID_ARG: Set RGBW color for a specific pixel failed because of an invalid argument\n *      - ESP_FAIL: Set RGBW color for a specific pixel failed because other error occurred\n */\nesp_err_t led_strip_set_pixel_rgbw(led_strip_handle_t strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white);\n\n/**\n * @brief Set HSV for a specific pixel\n *\n * @param strip: LED strip\n * @param index: index of pixel to set\n * @param hue: hue part of color (0 - 360)\n * @param saturation: saturation part of color (0 - 255, rescaled from 0 - 1. e.g. saturation = 0.5, rescaled to 127)\n * @param value: value part of color (0 - 255, rescaled from 0 - 1. e.g. value = 0.5, rescaled to 127)\n *\n * @return\n *      - ESP_OK: Set HSV color for a specific pixel successfully\n *      - ESP_ERR_INVALID_ARG: Set HSV color for a specific pixel failed because of an invalid argument\n *      - ESP_FAIL: Set HSV color for a specific pixel failed because other error occurred\n */\nesp_err_t led_strip_set_pixel_hsv(led_strip_handle_t strip, uint32_t index, uint16_t hue, uint8_t saturation, uint8_t value);\n\n/**\n * @brief Set HSV for a specific pixel in 16-bit resolution\n *\n * @param strip: LED strip\n * @param index: index of pixel to set\n * @param hue: hue part of color (0 - 360)\n * @param saturation: saturation part of color (0 - 65535, rescaled from 0 - 1. e.g. saturation = 0.5, rescaled to 32767)\n * @param value: value part of color (0 - 65535, rescaled from 0 - 1. e.g. value = 0.5, rescaled to 32767)\n *\n * @return\n *      - ESP_OK: Set HSV color for a specific pixel successfully\n *      - ESP_ERR_INVALID_ARG: Set HSV color for a specific pixel failed because of an invalid argument\n *      - ESP_FAIL: Set HSV color for a specific pixel failed because other error occurred\n */\nesp_err_t led_strip_set_pixel_hsv_16(led_strip_handle_t strip, uint32_t index, uint16_t hue, uint16_t saturation, uint16_t value);\n\n/**\n * @brief Refresh memory colors to LEDs\n *\n * @param strip: LED strip\n *\n * @return\n *      - ESP_OK: Refresh successfully\n *      - ESP_FAIL: Refresh failed because some other error occurred\n *\n * @note:\n *      After updating the LED colors in the memory, a following invocation of this API is needed to flush colors to strip.\n */\nesp_err_t led_strip_refresh(led_strip_handle_t strip);\n\n/**\n * @brief Clear LED strip (turn off all LEDs)\n *\n * @param strip: LED strip\n *\n * @return\n *      - ESP_OK: Clear LEDs successfully\n *      - ESP_FAIL: Clear LEDs failed because some other error occurred\n */\nesp_err_t led_strip_clear(led_strip_handle_t strip);\n\n/**\n * @brief Free LED strip resources\n *\n * @param strip: LED strip\n *\n * @return\n *      - ESP_OK: Free resources successfully\n *      - ESP_FAIL: Free resources failed because error occurred\n */\nesp_err_t led_strip_del(led_strip_handle_t strip);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "led_strip/include/led_strip_rmt.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdint.h>\n#include \"esp_err.h\"\n#include \"led_strip_types.h\"\n#include \"esp_idf_version.h\"\n#include \"driver/rmt_types.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief LED Strip RMT specific configuration\n */\ntypedef struct {\n    rmt_clock_source_t clk_src; /*!< RMT clock source */\n    uint32_t resolution_hz;     /*!< RMT tick resolution, if set to zero, a default resolution (10MHz) will be applied */\n    size_t mem_block_symbols;   /*!< How many RMT symbols can one RMT channel hold at one time. Set to 0 will fallback to use the default size. */\n    /*!< Extra RMT specific driver flags */\n    struct led_strip_rmt_extra_config {\n        uint32_t with_dma: 1;   /*!< Use DMA to transmit data */\n    } flags;                    /*!< Extra driver flags */\n} led_strip_rmt_config_t;\n\n/**\n * @brief Create LED strip based on RMT TX channel\n *\n * @param led_config LED strip configuration\n * @param rmt_config RMT specific configuration\n * @param ret_strip Returned LED strip handle\n * @return\n *      - ESP_OK: create LED strip handle successfully\n *      - ESP_ERR_INVALID_ARG: create LED strip handle failed because of invalid argument\n *      - ESP_ERR_NO_MEM: create LED strip handle failed because of out of memory\n *      - ESP_FAIL: create LED strip handle failed because some other error\n */\nesp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const led_strip_rmt_config_t *rmt_config, led_strip_handle_t *ret_strip);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "led_strip/include/led_strip_spi.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdint.h>\n#include \"esp_err.h\"\n#include \"driver/spi_master.h\"\n#include \"led_strip_types.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief LED Strip SPI specific configuration\n */\ntypedef struct {\n    spi_clock_source_t clk_src; /*!< SPI clock source */\n    spi_host_device_t spi_bus;  /*!< SPI bus ID. Which buses are available depends on the specific chip */\n    struct {\n        uint32_t with_dma: 1;   /*!< Use DMA to transmit data */\n    } flags;                    /*!< Extra driver flags */\n} led_strip_spi_config_t;\n\n/**\n * @brief Create LED strip based on SPI MOSI channel\n *\n * @note Although only the MOSI line is used for generating the signal, the whole SPI bus can't be used for other purposes.\n *\n * @param led_config LED strip configuration\n * @param spi_config SPI specific configuration\n * @param ret_strip Returned LED strip handle\n * @return\n *      - ESP_OK: create LED strip handle successfully\n *      - ESP_ERR_INVALID_ARG: create LED strip handle failed because of invalid argument\n *      - ESP_ERR_NOT_SUPPORTED: create LED strip handle failed because of unsupported configuration\n *      - ESP_ERR_NO_MEM: create LED strip handle failed because of out of memory\n *      - ESP_FAIL: create LED strip handle failed because some other error\n */\nesp_err_t led_strip_new_spi_device(const led_strip_config_t *led_config, const led_strip_spi_config_t *spi_config, led_strip_handle_t *ret_strip);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "led_strip/include/led_strip_types.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdint.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief Type of LED strip handle\n */\ntypedef struct led_strip_t *led_strip_handle_t;\n\n/**\n * @brief LED strip model\n * @note Different led model may have different timing parameters, so we need to distinguish them.\n */\ntypedef enum {\n    LED_MODEL_WS2812, /*!< LED strip model: WS2812 */\n    LED_MODEL_SK6812, /*!< LED strip model: SK6812 */\n    LED_MODEL_WS2811, /*!< LED strip model: WS2811 */\n    LED_MODEL_WS2816, /*!< LED strip model: WS2816 */\n    LED_MODEL_INVALID /*!< Invalid LED strip model */\n} led_model_t;\n\n/**\n * @brief LED color component format\n * @note The format is used to specify the order of color components in each pixel, also the number of color components.\n */\ntypedef union {\n    struct format_layout {\n        uint32_t r_pos: 2;           /*!< Position of the red channel in the color order: 0~3 */\n        uint32_t g_pos: 2;           /*!< Position of the green channel in the color order: 0~3 */\n        uint32_t b_pos: 2;           /*!< Position of the blue channel in the color order: 0~3 */\n        uint32_t w_pos: 2;           /*!< Position of the white channel in the color order: 0~3 */\n        uint32_t reserved: 19;       /*!< Reserved */\n        uint32_t bytes_per_color: 2; /*!< Bytes per color component: 1 or 2. If set to 0, it will fallback to 1 */\n        uint32_t num_components: 3;  /*!< Number of color components per pixel: 3 or 4. If set to 0, it will fallback to 3 */\n    } format;                        /*!< Format layout */\n    uint32_t format_id;              /*!< Format ID */\n} led_color_component_format_t;\n\n/// Helper macros to set the color component format\n#define LED_STRIP_COLOR_COMPONENT_FMT_GRB (led_color_component_format_t){.format = {.r_pos = 1, .g_pos = 0, .b_pos = 2, .w_pos = 3, .reserved = 0, .bytes_per_color = 1, .num_components = 3}}\n#define LED_STRIP_COLOR_COMPONENT_FMT_GRB_16 (led_color_component_format_t){.format = {.r_pos = 1, .g_pos = 0, .b_pos = 2, .w_pos = 3, .reserved = 0, .bytes_per_color = 2, .num_components = 3}}\n#define LED_STRIP_COLOR_COMPONENT_FMT_GRBW (led_color_component_format_t){.format = {.r_pos = 1, .g_pos = 0, .b_pos = 2, .w_pos = 3, .reserved = 0, .bytes_per_color = 1, .num_components = 4}}\n#define LED_STRIP_COLOR_COMPONENT_FMT_GRBW_16 (led_color_component_format_t){.format = {.r_pos = 1, .g_pos = 0, .b_pos = 2, .w_pos = 3, .reserved = 0, .bytes_per_color = 2, .num_components = 4}}\n#define LED_STRIP_COLOR_COMPONENT_FMT_RGB (led_color_component_format_t){.format = {.r_pos = 0, .g_pos = 1, .b_pos = 2, .w_pos = 3, .reserved = 0, .bytes_per_color = 1, .num_components = 3}}\n#define LED_STRIP_COLOR_COMPONENT_FMT_RGB_16 (led_color_component_format_t){.format = {.r_pos = 0, .g_pos = 1, .b_pos = 2, .w_pos = 3, .reserved = 0, .bytes_per_color = 2, .num_components = 3}}\n#define LED_STRIP_COLOR_COMPONENT_FMT_RGBW (led_color_component_format_t){.format = {.r_pos = 0, .g_pos = 1, .b_pos = 2, .w_pos = 3, .reserved = 0, .bytes_per_color = 1, .num_components = 4}}\n#define LED_STRIP_COLOR_COMPONENT_FMT_RGBW_16 (led_color_component_format_t){.format = {.r_pos = 0, .g_pos = 1, .b_pos = 2, .w_pos = 3, .reserved = 0, .bytes_per_color = 2, .num_components = 4}}\n\n/**\n * @brief LED Strip common configurations\n *        The common configurations are not specific to any backend peripheral.\n */\ntypedef struct {\n    int strip_gpio_num;           /*!< GPIO number that used by LED strip */\n    uint32_t max_leds;            /*!< Maximum number of LEDs that can be controlled in a single strip */\n    led_model_t led_model;        /*!< Specifies the LED strip model (e.g., WS2812, SK6812) */\n    led_color_component_format_t color_component_format; /*!< Specifies the order of color components in each pixel.\n                                                              Use helper macros like `LED_STRIP_COLOR_COMPONENT_FMT_GRB` to set the format */\n    /*!< LED strip extra driver flags */\n    struct led_strip_extra_flags {\n        uint32_t invert_out: 1; /*!< Invert output signal */\n    } flags; /*!< Extra driver flags */\n} led_strip_config_t;\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "led_strip/interface/led_strip_interface.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdint.h>\n#include \"esp_err.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct led_strip_t led_strip_t; /*!< Type of LED strip */\n\n/**\n * @brief LED strip interface definition\n */\nstruct led_strip_t {\n    /**\n     * @brief Set RGB for a specific pixel\n     *\n     * @param strip: LED strip\n     * @param index: index of pixel to set\n     * @param red: red part of color\n     * @param green: green part of color\n     * @param blue: blue part of color\n     *\n     * @return\n     *      - ESP_OK: Set RGB for a specific pixel successfully\n     *      - ESP_ERR_INVALID_ARG: Set RGB for a specific pixel failed because of invalid parameters\n     *      - ESP_FAIL: Set RGB for a specific pixel failed because other error occurred\n     */\n    esp_err_t (*set_pixel)(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue);\n\n    /**\n     * @brief Set RGBW for a specific pixel. Similar to `set_pixel` but also set the white component\n     *\n     * @param strip: LED strip\n     * @param index: index of pixel to set\n     * @param red: red part of color\n     * @param green: green part of color\n     * @param blue: blue part of color\n     * @param white: separate white component\n     *\n     * @return\n     *      - ESP_OK: Set RGBW color for a specific pixel successfully\n     *      - ESP_ERR_INVALID_ARG: Set RGBW color for a specific pixel failed because of an invalid argument\n     *      - ESP_FAIL: Set RGBW color for a specific pixel failed because other error occurred\n     */\n    esp_err_t (*set_pixel_rgbw)(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white);\n\n    /**\n     * @brief Refresh memory colors to LEDs\n     *\n     * @param strip: LED strip\n     * @param timeout_ms: timeout value for refreshing task\n     *\n     * @return\n     *      - ESP_OK: Refresh successfully\n     *      - ESP_FAIL: Refresh failed because some other error occurred\n     *\n     * @note:\n     *      After updating the LED colors in the memory, a following invocation of this API is needed to flush colors to strip.\n     */\n    esp_err_t (*refresh)(led_strip_t *strip);\n\n    /**\n     * @brief Clear LED strip (turn off all LEDs)\n     *\n     * @param strip: LED strip\n     * @param timeout_ms: timeout value for clearing task\n     *\n     * @return\n     *      - ESP_OK: Clear LEDs successfully\n     *      - ESP_FAIL: Clear LEDs failed because some other error occurred\n     */\n    esp_err_t (*clear)(led_strip_t *strip);\n\n    /**\n     * @brief Free LED strip resources\n     *\n     * @param strip: LED strip\n     *\n     * @return\n     *      - ESP_OK: Free resources successfully\n     *      - ESP_FAIL: Free resources failed because error occurred\n     */\n    esp_err_t (*del)(led_strip_t *strip);\n};\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "led_strip/src/led_strip_api.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include \"esp_log.h\"\n#include \"esp_check.h\"\n#include \"led_strip.h\"\n#include \"led_strip_interface.h\"\n\nstatic const char *TAG = \"led_strip\";\n\nesp_err_t led_strip_set_pixel(led_strip_handle_t strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)\n{\n    ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    return strip->set_pixel(strip, index, red, green, blue);\n}\n\nesp_err_t led_strip_set_pixel_hsv(led_strip_handle_t strip, uint32_t index, uint16_t hue, uint8_t saturation, uint8_t value)\n{\n    ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n\n    uint32_t red = 0;\n    uint32_t green = 0;\n    uint32_t blue = 0;\n\n    uint32_t rgb_max = value;\n    uint32_t rgb_min = rgb_max * (255 - saturation) / 255;\n\n    uint32_t i = hue / 60;\n    uint32_t diff = hue % 60;\n\n    // RGB adjustment amount by hue\n    uint32_t rgb_adj = (rgb_max - rgb_min) * diff / 60;\n\n    switch (i) {\n    case 0:\n        red = rgb_max;\n        green = rgb_min + rgb_adj;\n        blue = rgb_min;\n        break;\n    case 1:\n        red = rgb_max - rgb_adj;\n        green = rgb_max;\n        blue = rgb_min;\n        break;\n    case 2:\n        red = rgb_min;\n        green = rgb_max;\n        blue = rgb_min + rgb_adj;\n        break;\n    case 3:\n        red = rgb_min;\n        green = rgb_max - rgb_adj;\n        blue = rgb_max;\n        break;\n    case 4:\n        red = rgb_min + rgb_adj;\n        green = rgb_min;\n        blue = rgb_max;\n        break;\n    default:\n        red = rgb_max;\n        green = rgb_min;\n        blue = rgb_max - rgb_adj;\n        break;\n    }\n\n    return strip->set_pixel(strip, index, red, green, blue);\n}\n\nesp_err_t led_strip_set_pixel_hsv_16(led_strip_handle_t strip, uint32_t index, uint16_t hue, uint16_t saturation, uint16_t value)\n{\n    ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n\n    uint32_t red = 0;\n    uint32_t green = 0;\n    uint32_t blue = 0;\n\n    uint32_t rgb_max = value;\n    uint32_t rgb_min = rgb_max * (65535 - saturation) / 65535;\n\n    uint32_t i = hue / 60;\n    uint32_t diff = hue % 60;\n\n    // RGB adjustment amount by hue\n    uint32_t rgb_adj = (rgb_max - rgb_min) * diff / 60;\n\n    switch (i) {\n    case 0:\n        red = rgb_max;\n        green = rgb_min + rgb_adj;\n        blue = rgb_min;\n        break;\n    case 1:\n        red = rgb_max - rgb_adj;\n        green = rgb_max;\n        blue = rgb_min;\n        break;\n    case 2:\n        red = rgb_min;\n        green = rgb_max;\n        blue = rgb_min + rgb_adj;\n        break;\n    case 3:\n        red = rgb_min;\n        green = rgb_max - rgb_adj;\n        blue = rgb_max;\n        break;\n    case 4:\n        red = rgb_min + rgb_adj;\n        green = rgb_min;\n        blue = rgb_max;\n        break;\n    default:\n        red = rgb_max;\n        green = rgb_min;\n        blue = rgb_max - rgb_adj;\n        break;\n    }\n\n    return strip->set_pixel(strip, index, red, green, blue);\n}\n\nesp_err_t led_strip_set_pixel_rgbw(led_strip_handle_t strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white)\n{\n    ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    return strip->set_pixel_rgbw(strip, index, red, green, blue, white);\n}\n\nesp_err_t led_strip_refresh(led_strip_handle_t strip)\n{\n    ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    return strip->refresh(strip);\n}\n\nesp_err_t led_strip_clear(led_strip_handle_t strip)\n{\n    ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    return strip->clear(strip);\n}\n\nesp_err_t led_strip_del(led_strip_handle_t strip)\n{\n    ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    return strip->del(strip);\n}\n"
  },
  {
    "path": "led_strip/src/led_strip_rmt_dev.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include <stdlib.h>\n#include <string.h>\n#include <sys/cdefs.h>\n#include \"esp_log.h\"\n#include \"esp_check.h\"\n#include \"driver/rmt_tx.h\"\n#include \"led_strip.h\"\n#include \"led_strip_interface.h\"\n#include \"led_strip_rmt_encoder.h\"\n\n#define LED_STRIP_RMT_DEFAULT_RESOLUTION 10000000 // 10MHz resolution\n#define LED_STRIP_RMT_DEFAULT_TRANS_QUEUE_SIZE 4\n// the memory size of each RMT channel, in words (4 bytes)\n#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2\n#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS 64\n#else\n#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS 48\n#endif\n\nstatic const char *TAG = \"led_strip_rmt\";\n\ntypedef struct {\n    led_strip_t base;\n    rmt_channel_handle_t rmt_chan;\n    rmt_encoder_handle_t strip_encoder;\n    uint32_t strip_len;\n    uint8_t bytes_per_pixel;\n    led_color_component_format_t component_fmt;\n    uint8_t pixel_buf[];\n} led_strip_rmt_obj;\n\nstatic esp_err_t led_strip_rmt_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)\n{\n    led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);\n    ESP_RETURN_ON_FALSE(index < rmt_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, \"index out of maximum number of LEDs\");\n\n    struct format_layout format = rmt_strip->component_fmt.format;\n    uint32_t start = index * rmt_strip->bytes_per_pixel;\n    uint8_t *pixel_buf = rmt_strip->pixel_buf;\n    uint8_t pos_bytes = format.bytes_per_color;\n\n    for (uint8_t i = 0; i < format.bytes_per_color; i++) {\n        uint8_t color_shift = 8 * (format.bytes_per_color - 1 - i);\n        pixel_buf[start + format.r_pos * pos_bytes + i] = (red >> color_shift) & 0xFF;\n        pixel_buf[start + format.g_pos * pos_bytes + i] = (green >> color_shift) & 0xFF;\n        pixel_buf[start + format.b_pos * pos_bytes + i] = (blue >> color_shift) & 0xFF;\n        if (format.num_components > 3) {\n            pixel_buf[start + format.w_pos * pos_bytes + i] = 0;\n        }\n    }\n    return ESP_OK;\n}\n\nstatic esp_err_t led_strip_rmt_set_pixel_rgbw(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white)\n{\n    led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);\n    struct format_layout format = rmt_strip->component_fmt.format;\n    ESP_RETURN_ON_FALSE(index < rmt_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, \"index out of maximum number of LEDs\");\n    ESP_RETURN_ON_FALSE(format.num_components == 4, ESP_ERR_INVALID_ARG, TAG, \"led doesn't have 4 components\");\n\n    uint32_t start = index * rmt_strip->bytes_per_pixel;\n    uint8_t *pixel_buf = rmt_strip->pixel_buf;\n    uint8_t pos_bytes = format.bytes_per_color;\n\n    for (uint8_t i = 0; i < format.bytes_per_color; i++) {\n        uint8_t color_shift = 8 * (format.bytes_per_color - 1 - i);\n        pixel_buf[start + format.r_pos * pos_bytes + i] = (red >> color_shift) & 0xFF;\n        pixel_buf[start + format.g_pos * pos_bytes + i] = (green >> color_shift) & 0xFF;\n        pixel_buf[start + format.b_pos * pos_bytes + i] = (blue >> color_shift) & 0xFF;\n        pixel_buf[start + format.w_pos * pos_bytes + i] = (white >> color_shift) & 0xFF;\n    }\n    return ESP_OK;\n}\n\nstatic esp_err_t led_strip_rmt_refresh(led_strip_t *strip)\n{\n    led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);\n    rmt_transmit_config_t tx_conf = {\n        .loop_count = 0,\n    };\n\n    ESP_RETURN_ON_ERROR(rmt_enable(rmt_strip->rmt_chan), TAG, \"enable RMT channel failed\");\n    ESP_RETURN_ON_ERROR(rmt_transmit(rmt_strip->rmt_chan, rmt_strip->strip_encoder, rmt_strip->pixel_buf,\n                                     rmt_strip->strip_len * rmt_strip->bytes_per_pixel, &tx_conf), TAG, \"transmit pixels by RMT failed\");\n    ESP_RETURN_ON_ERROR(rmt_tx_wait_all_done(rmt_strip->rmt_chan, -1), TAG, \"flush RMT channel failed\");\n    ESP_RETURN_ON_ERROR(rmt_disable(rmt_strip->rmt_chan), TAG, \"disable RMT channel failed\");\n    return ESP_OK;\n}\n\nstatic esp_err_t led_strip_rmt_clear(led_strip_t *strip)\n{\n    led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);\n    // Write zero to turn off all leds\n    memset(rmt_strip->pixel_buf, 0, rmt_strip->strip_len * rmt_strip->bytes_per_pixel);\n    return led_strip_rmt_refresh(strip);\n}\n\nstatic esp_err_t led_strip_rmt_del(led_strip_t *strip)\n{\n    led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);\n    ESP_RETURN_ON_ERROR(rmt_del_channel(rmt_strip->rmt_chan), TAG, \"delete RMT channel failed\");\n    ESP_RETURN_ON_ERROR(rmt_del_encoder(rmt_strip->strip_encoder), TAG, \"delete strip encoder failed\");\n    free(rmt_strip);\n    return ESP_OK;\n}\n\nesp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const led_strip_rmt_config_t *rmt_config, led_strip_handle_t *ret_strip)\n{\n    led_strip_rmt_obj *rmt_strip = NULL;\n    esp_err_t ret = ESP_OK;\n    ESP_GOTO_ON_FALSE(led_config && rmt_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, \"invalid argument\");\n    led_color_component_format_t component_fmt = led_config->color_component_format;\n    // If R/G/B order is not specified, set default GRB order as fallback\n    if (component_fmt.format_id == 0) {\n        component_fmt = LED_STRIP_COLOR_COMPONENT_FMT_GRB;\n    }\n    if (led_config->led_model == LED_MODEL_WS2816) {\n        component_fmt.format.bytes_per_color = 2;\n    }\n    if (component_fmt.format.bytes_per_color == 0) {\n        component_fmt.format.bytes_per_color = 1;\n    }\n    // check the validation of the color component format\n    uint8_t mask = 0;\n    if (component_fmt.format.num_components == 3) {\n        mask = BIT(component_fmt.format.r_pos) | BIT(component_fmt.format.g_pos) | BIT(component_fmt.format.b_pos);\n        // Check for invalid values\n        ESP_RETURN_ON_FALSE(mask == 0x07, ESP_ERR_INVALID_ARG, TAG, \"invalid order argument\");\n    } else if (component_fmt.format.num_components == 4) {\n        mask = BIT(component_fmt.format.r_pos) | BIT(component_fmt.format.g_pos) | BIT(component_fmt.format.b_pos) | BIT(component_fmt.format.w_pos);\n        // Check for invalid values\n        ESP_RETURN_ON_FALSE(mask == 0x0F, ESP_ERR_INVALID_ARG, TAG, \"invalid order argument\");\n    } else {\n        ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_ARG, TAG, \"invalid number of color components: %d\", component_fmt.format.num_components);\n    }\n    uint8_t bytes_per_pixel = component_fmt.format.num_components;\n    if (component_fmt.format.bytes_per_color > 1) {\n        bytes_per_pixel *= component_fmt.format.bytes_per_color;\n    }\n    rmt_strip = calloc(1, sizeof(led_strip_rmt_obj) + led_config->max_leds * bytes_per_pixel);\n    ESP_GOTO_ON_FALSE(rmt_strip, ESP_ERR_NO_MEM, err, TAG, \"no mem for rmt strip\");\n    uint32_t resolution = rmt_config->resolution_hz ? rmt_config->resolution_hz : LED_STRIP_RMT_DEFAULT_RESOLUTION;\n\n    // for backward compatibility, if the user does not set the clk_src, use the default value\n    rmt_clock_source_t clk_src = RMT_CLK_SRC_DEFAULT;\n    if (rmt_config->clk_src) {\n        clk_src = rmt_config->clk_src;\n    }\n    size_t mem_block_symbols = LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS;\n    // override the default value if the user sets it\n    if (rmt_config->mem_block_symbols) {\n        mem_block_symbols = rmt_config->mem_block_symbols;\n    }\n    rmt_tx_channel_config_t rmt_chan_config = {\n        .clk_src = clk_src,\n        .gpio_num = led_config->strip_gpio_num,\n        .mem_block_symbols = mem_block_symbols,\n        .resolution_hz = resolution,\n        .trans_queue_depth = LED_STRIP_RMT_DEFAULT_TRANS_QUEUE_SIZE,\n        .flags.with_dma = rmt_config->flags.with_dma,\n        .flags.invert_out = led_config->flags.invert_out,\n    };\n    ESP_GOTO_ON_ERROR(rmt_new_tx_channel(&rmt_chan_config, &rmt_strip->rmt_chan), err, TAG, \"create RMT TX channel failed\");\n\n    led_strip_encoder_config_t strip_encoder_conf = {\n        .resolution = resolution,\n        .led_model = led_config->led_model\n    };\n    ESP_GOTO_ON_ERROR(rmt_new_led_strip_encoder(&strip_encoder_conf, &rmt_strip->strip_encoder), err, TAG, \"create LED strip encoder failed\");\n\n    rmt_strip->component_fmt = component_fmt;\n    rmt_strip->bytes_per_pixel = bytes_per_pixel;\n    rmt_strip->strip_len = led_config->max_leds;\n    rmt_strip->base.set_pixel = led_strip_rmt_set_pixel;\n    rmt_strip->base.set_pixel_rgbw = led_strip_rmt_set_pixel_rgbw;\n    rmt_strip->base.refresh = led_strip_rmt_refresh;\n    rmt_strip->base.clear = led_strip_rmt_clear;\n    rmt_strip->base.del = led_strip_rmt_del;\n\n    *ret_strip = &rmt_strip->base;\n    return ESP_OK;\nerr:\n    if (rmt_strip) {\n        if (rmt_strip->rmt_chan) {\n            rmt_del_channel(rmt_strip->rmt_chan);\n        }\n        if (rmt_strip->strip_encoder) {\n            rmt_del_encoder(rmt_strip->strip_encoder);\n        }\n        free(rmt_strip);\n    }\n    return ret;\n}\n"
  },
  {
    "path": "led_strip/src/led_strip_rmt_encoder.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"sdkconfig.h\"\n#include \"esp_idf_version.h\"\n#include \"esp_check.h\"\n#include \"esp_attr.h\"\n#include \"led_strip_rmt_encoder.h\"\n\nstatic const char *TAG = \"led_rmt_encoder\";\n\n#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 5, 0)\n#if CONFIG_RMT_ISR_IRAM_SAFE\n#define RMT_ENCODER_FUNC_ATTR IRAM_ATTR\n#else\n#define RMT_ENCODER_FUNC_ATTR\n#endif // CONFIG_RMT_ISR_IRAM_SAFE\n#endif // ESP_IDF_VERSION\n\ntypedef struct {\n    rmt_encoder_t base;\n    rmt_encoder_t *bytes_encoder;\n    rmt_encoder_t *copy_encoder;\n    int state;\n    rmt_symbol_word_t reset_code;\n} rmt_led_strip_encoder_t;\n\nRMT_ENCODER_FUNC_ATTR\nstatic size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)\n{\n    rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);\n    rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder;\n    rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder;\n    rmt_encode_state_t session_state = 0;\n    rmt_encode_state_t state = 0;\n    size_t encoded_symbols = 0;\n    switch (led_encoder->state) {\n    case 0: // send RGB data\n        encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, primary_data, data_size, &session_state);\n        if (session_state & RMT_ENCODING_COMPLETE) {\n            led_encoder->state = 1; // switch to next state when current encoding session finished\n        }\n        if (session_state & RMT_ENCODING_MEM_FULL) {\n            state |= RMT_ENCODING_MEM_FULL;\n            goto out; // yield if there's no free space for encoding artifacts\n        }\n    // fall-through\n    case 1: // send reset code\n        encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_encoder->reset_code,\n                                                sizeof(led_encoder->reset_code), &session_state);\n        if (session_state & RMT_ENCODING_COMPLETE) {\n            led_encoder->state = 0; // back to the initial encoding session\n            state |= RMT_ENCODING_COMPLETE;\n        }\n        if (session_state & RMT_ENCODING_MEM_FULL) {\n            state |= RMT_ENCODING_MEM_FULL;\n            goto out; // yield if there's no free space for encoding artifacts\n        }\n    }\nout:\n    *ret_state = state;\n    return encoded_symbols;\n}\n\nstatic esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t *encoder)\n{\n    rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);\n    rmt_del_encoder(led_encoder->bytes_encoder);\n    rmt_del_encoder(led_encoder->copy_encoder);\n    free(led_encoder);\n    return ESP_OK;\n}\n\nRMT_ENCODER_FUNC_ATTR\nstatic esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder)\n{\n    rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);\n    rmt_encoder_reset(led_encoder->bytes_encoder);\n    rmt_encoder_reset(led_encoder->copy_encoder);\n    led_encoder->state = 0;\n    return ESP_OK;\n}\n\nesp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)\n{\n    esp_err_t ret = ESP_OK;\n    rmt_led_strip_encoder_t *led_encoder = NULL;\n    ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, \"invalid argument\");\n    ESP_GOTO_ON_FALSE(config->led_model < LED_MODEL_INVALID, ESP_ERR_INVALID_ARG, err, TAG, \"invalid led model\");\n    led_encoder = calloc(1, sizeof(rmt_led_strip_encoder_t));\n    ESP_GOTO_ON_FALSE(led_encoder, ESP_ERR_NO_MEM, err, TAG, \"no mem for led strip encoder\");\n    led_encoder->base.encode = rmt_encode_led_strip;\n    led_encoder->base.del = rmt_del_led_strip_encoder;\n    led_encoder->base.reset = rmt_led_strip_encoder_reset;\n    rmt_bytes_encoder_config_t bytes_encoder_config;\n    uint32_t reset_ticks = config->resolution / 1000000 * 280 / 2; // reset code duration defaults to 280us to accommodate WS2812B-V5\n    if (config->led_model == LED_MODEL_SK6812) {\n        bytes_encoder_config = (rmt_bytes_encoder_config_t) {\n            .bit0 = {\n                .level0 = 1,\n                .duration0 = 0.3 * config->resolution / 1000000, // T0H=0.3us\n                .level1 = 0,\n                .duration1 = 0.9 * config->resolution / 1000000, // T0L=0.9us\n            },\n            .bit1 = {\n                .level0 = 1,\n                .duration0 = 0.6 * config->resolution / 1000000, // T1H=0.6us\n                .level1 = 0,\n                .duration1 = 0.6 * config->resolution / 1000000, // T1L=0.6us\n            },\n            .flags.msb_first = 1 // SK6812 transfer bit order: G7...G0R7...R0B7...B0(W7...W0)\n        };\n    } else if (config->led_model == LED_MODEL_WS2812) {\n        // different led strip might have its own timing requirements, following parameter is for WS2812\n        bytes_encoder_config = (rmt_bytes_encoder_config_t) {\n            .bit0 = {\n                .level0 = 1,\n                .duration0 = 0.3 * config->resolution / 1000000, // T0H=0.3us\n                .level1 = 0,\n                .duration1 = 0.9 * config->resolution / 1000000, // T0L=0.9us\n            },\n            .bit1 = {\n                .level0 = 1,\n                .duration0 = 0.9 * config->resolution / 1000000, // T1H=0.9us\n                .level1 = 0,\n                .duration1 = 0.3 * config->resolution / 1000000, // T1L=0.3us\n            },\n            .flags.msb_first = 1 // WS2812 transfer bit order: G7...G0R7...R0B7...B0\n        };\n    } else if (config->led_model == LED_MODEL_WS2811) {\n        // different led strip might have its own timing requirements, following parameter is for WS2811\n        bytes_encoder_config = (rmt_bytes_encoder_config_t) {\n            .bit0 = {\n                .level0 = 1,\n                .duration0 = 0.5 * config->resolution / 1000000., // T0H=0.5us\n                .level1 = 0,\n                .duration1 = 2.0 * config->resolution / 1000000., // T0L=2.0us\n            },\n            .bit1 = {\n                .level0 = 1,\n                .duration0 = 1.2 * config->resolution / 1000000., // T1H=1.2us\n                .level1 = 0,\n                .duration1 = 1.3 * config->resolution / 1000000., // T1L=1.3us\n            },\n            .flags.msb_first = 1\n        };\n        reset_ticks = config->resolution / 1000000 * 50 / 2; // divide by 2... signal is sent twice\n    } else if (config->led_model == LED_MODEL_WS2816) {\n        // different led strip might have its own timing requirements, following parameter is for WS2816\n        bytes_encoder_config = (rmt_bytes_encoder_config_t) {\n            .bit0 = {\n                .level0 = 1,\n                .duration0 = 0.3 * config->resolution / 1000000, // T0H=0.3us\n                .level1 = 0,\n                .duration1 = 0.95 * config->resolution / 1000000, // T0L=0.95us\n            },\n            .bit1 = {\n                .level0 = 1,\n                .duration0 = 0.75 * config->resolution / 1000000, // T1H=0.75us\n                .level1 = 0,\n                .duration1 = 0.5 * config->resolution / 1000000, // T1L=0.5us\n            },\n            .flags.msb_first = 1\n        };\n    } else {\n        assert(false);\n    }\n    ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder), err, TAG, \"create bytes encoder failed\");\n    rmt_copy_encoder_config_t copy_encoder_config = {};\n    ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(&copy_encoder_config, &led_encoder->copy_encoder), err, TAG, \"create copy encoder failed\");\n\n    led_encoder->reset_code = (rmt_symbol_word_t) {\n        .level0 = 0,\n        .duration0 = reset_ticks,\n        .level1 = 0,\n        .duration1 = reset_ticks,\n    };\n    *ret_encoder = &led_encoder->base;\n    return ESP_OK;\nerr:\n    if (led_encoder) {\n        if (led_encoder->bytes_encoder) {\n            rmt_del_encoder(led_encoder->bytes_encoder);\n        }\n        if (led_encoder->copy_encoder) {\n            rmt_del_encoder(led_encoder->copy_encoder);\n        }\n        free(led_encoder);\n    }\n    return ret;\n}\n"
  },
  {
    "path": "led_strip/src/led_strip_rmt_encoder.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdint.h>\n#include \"driver/rmt_encoder.h\"\n#include \"led_strip_types.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief Type of led strip encoder configuration\n */\ntypedef struct {\n    uint32_t resolution;   /*!< Encoder resolution, in Hz */\n    led_model_t led_model; /*!< LED model */\n} led_strip_encoder_config_t;\n\n/**\n * @brief Create RMT encoder for encoding LED strip pixels into RMT symbols\n *\n * @param[in] config Encoder configuration\n * @param[out] ret_encoder Returned encoder handle\n * @return\n *      - ESP_ERR_INVALID_ARG for any invalid arguments\n *      - ESP_ERR_NO_MEM out of memory when creating led strip encoder\n *      - ESP_OK if creating encoder successfully\n */\nesp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "led_strip/src/led_strip_spi_dev.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include <stdlib.h>\n#include <string.h>\n#include <sys/cdefs.h>\n#include \"esp_log.h\"\n#include \"esp_check.h\"\n#include \"esp_rom_gpio.h\"\n#include \"soc/spi_periph.h\"\n#include \"led_strip.h\"\n#include \"led_strip_interface.h\"\n#include \"esp_heap_caps.h\"\n\n#define LED_STRIP_SPI_DEFAULT_RESOLUTION (2.5 * 1000 * 1000) // 2.5MHz resolution\n#define LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE 4\n\n#define SPI_BYTES_PER_COLOR_BYTE 3\n#define SPI_BITS_PER_COLOR_BYTE (SPI_BYTES_PER_COLOR_BYTE * 8)\n\nstatic const char *TAG = \"led_strip_spi\";\n\ntypedef struct {\n    led_strip_t base;\n    spi_host_device_t spi_host;\n    spi_device_handle_t spi_device;\n    uint32_t strip_len;\n    uint8_t bytes_per_pixel;\n    led_color_component_format_t component_fmt;\n    uint8_t pixel_buf[];\n} led_strip_spi_obj;\n\n// please make sure to zero-initialize the buf before calling this function\nstatic void __led_strip_spi_bit(uint8_t data, uint8_t *buf)\n{\n    // Each color of 1 bit is represented by 3 bits of SPI, low_level:100 ,high_level:110\n    // So a color byte occupies 3 bytes of SPI.\n    *(buf + 2) |= data & BIT(0) ? BIT(2) | BIT(1) : BIT(2);\n    *(buf + 2) |= data & BIT(1) ? BIT(5) | BIT(4) : BIT(5);\n    *(buf + 2) |= data & BIT(2) ? BIT(7) : 0x00;\n    *(buf + 1) |= BIT(0);\n    *(buf + 1) |= data & BIT(3) ? BIT(3) | BIT(2) : BIT(3);\n    *(buf + 1) |= data & BIT(4) ? BIT(6) | BIT(5) : BIT(6);\n    *(buf + 0) |= data & BIT(5) ? BIT(1) | BIT(0) : BIT(1);\n    *(buf + 0) |= data & BIT(6) ? BIT(4) | BIT(3) : BIT(4);\n    *(buf + 0) |= data & BIT(7) ? BIT(7) | BIT(6) : BIT(7);\n}\n\nstatic esp_err_t led_strip_spi_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)\n{\n    led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);\n    ESP_RETURN_ON_FALSE(index < spi_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, \"index out of maximum number of LEDs\");\n    // 3 pixels take 72bits(9bytes)\n    uint32_t start = index * spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE;\n    uint8_t *pixel_buf = spi_strip->pixel_buf;\n    struct format_layout format = spi_strip->component_fmt.format;\n    memset(pixel_buf + start, 0, spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE);\n\n    uint8_t pos_bytes = format.bytes_per_color;\n    for (uint8_t i = 0; i < format.bytes_per_color; i++) {\n        uint8_t color_shift = 8 * (format.bytes_per_color - 1 - i);\n        __led_strip_spi_bit((red >> color_shift) & 0xFF, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * (format.r_pos * pos_bytes + i)]);\n        __led_strip_spi_bit((green >> color_shift) & 0xFF, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * (format.g_pos * pos_bytes + i)]);\n        __led_strip_spi_bit((blue >> color_shift) & 0xFF, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * (format.b_pos * pos_bytes + i)]);\n        if (format.num_components > 3) {\n            __led_strip_spi_bit(0, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * (format.w_pos * pos_bytes + i)]);\n        }\n    }\n    return ESP_OK;\n}\n\nstatic esp_err_t led_strip_spi_set_pixel_rgbw(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white)\n{\n    led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);\n    struct format_layout format = spi_strip->component_fmt.format;\n    ESP_RETURN_ON_FALSE(index < spi_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, \"index out of maximum number of LEDs\");\n    ESP_RETURN_ON_FALSE(format.num_components == 4, ESP_ERR_INVALID_ARG, TAG, \"led doesn't have 4 components\");\n\n    // LED_PIXEL_FORMAT_GRBW takes 96bits(12bytes)\n    uint32_t start = index * spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE;\n    uint8_t *pixel_buf = spi_strip->pixel_buf;\n    memset(pixel_buf + start, 0, spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE);\n\n    uint8_t pos_bytes = format.bytes_per_color;\n    for (uint8_t i = 0; i < format.bytes_per_color; i++) {\n        uint8_t color_shift = 8 * (format.bytes_per_color - 1 - i);\n        __led_strip_spi_bit((red >> color_shift) & 0xFF, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * (format.r_pos * pos_bytes + i)]);\n        __led_strip_spi_bit((green >> color_shift) & 0xFF, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * (format.g_pos * pos_bytes + i)]);\n        __led_strip_spi_bit((blue >> color_shift) & 0xFF, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * (format.b_pos * pos_bytes + i)]);\n        __led_strip_spi_bit((white >> color_shift) & 0xFF, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * (format.w_pos * pos_bytes + i)]);\n    }\n    return ESP_OK;\n}\n\nstatic esp_err_t led_strip_spi_refresh(led_strip_t *strip)\n{\n    led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);\n    spi_transaction_t tx_conf;\n    memset(&tx_conf, 0, sizeof(tx_conf));\n\n    tx_conf.length = spi_strip->strip_len * spi_strip->bytes_per_pixel * SPI_BITS_PER_COLOR_BYTE;\n    tx_conf.tx_buffer = spi_strip->pixel_buf;\n    tx_conf.rx_buffer = NULL;\n    ESP_RETURN_ON_ERROR(spi_device_transmit(spi_strip->spi_device, &tx_conf), TAG, \"transmit pixels by SPI failed\");\n\n    return ESP_OK;\n}\n\nstatic esp_err_t led_strip_spi_clear(led_strip_t *strip)\n{\n    led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);\n    //Write zero to turn off all leds\n    memset(spi_strip->pixel_buf, 0, spi_strip->strip_len * spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE);\n    uint8_t *buf = spi_strip->pixel_buf;\n    for (int index = 0; index < spi_strip->strip_len * spi_strip->bytes_per_pixel; index++) {\n        __led_strip_spi_bit(0, buf);\n        buf += SPI_BYTES_PER_COLOR_BYTE;\n    }\n\n    return led_strip_spi_refresh(strip);\n}\n\nstatic esp_err_t led_strip_spi_del(led_strip_t *strip)\n{\n    led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);\n\n    ESP_RETURN_ON_ERROR(spi_bus_remove_device(spi_strip->spi_device), TAG, \"delete spi device failed\");\n    ESP_RETURN_ON_ERROR(spi_bus_free(spi_strip->spi_host), TAG, \"free spi bus failed\");\n\n    free(spi_strip);\n    return ESP_OK;\n}\n\nesp_err_t led_strip_new_spi_device(const led_strip_config_t *led_config, const led_strip_spi_config_t *spi_config, led_strip_handle_t *ret_strip)\n{\n    led_strip_spi_obj *spi_strip = NULL;\n    esp_err_t ret = ESP_OK;\n    ESP_GOTO_ON_FALSE(led_config && spi_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, \"invalid argument\");\n    led_color_component_format_t component_fmt = led_config->color_component_format;\n    // If R/G/B order is not specified, set default GRB order as fallback\n    if (component_fmt.format_id == 0) {\n        component_fmt = LED_STRIP_COLOR_COMPONENT_FMT_GRB;\n    }\n    if (led_config->led_model == LED_MODEL_WS2816) {\n        component_fmt.format.bytes_per_color = 2;\n    }\n    if (component_fmt.format.bytes_per_color == 0) {\n        component_fmt.format.bytes_per_color = 1;\n    }\n    uint8_t mask = 0;\n    if (component_fmt.format.num_components == 3) {\n        mask = BIT(component_fmt.format.r_pos) | BIT(component_fmt.format.g_pos) | BIT(component_fmt.format.b_pos);\n        // Check for invalid values\n        ESP_RETURN_ON_FALSE(mask == 0x07, ESP_ERR_INVALID_ARG, TAG, \"invalid order argument\");\n    } else if (component_fmt.format.num_components == 4) {\n        mask = BIT(component_fmt.format.r_pos) | BIT(component_fmt.format.g_pos) | BIT(component_fmt.format.b_pos) | BIT(component_fmt.format.w_pos);\n        // Check for invalid values\n        ESP_RETURN_ON_FALSE(mask == 0x0F, ESP_ERR_INVALID_ARG, TAG, \"invalid order argument\");\n    } else {\n        ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_ARG, TAG, \"invalid number of color components: %d\", component_fmt.format.num_components);\n    }\n    uint8_t bytes_per_pixel = component_fmt.format.num_components;\n    if (component_fmt.format.bytes_per_color > 1) {\n        bytes_per_pixel *= component_fmt.format.bytes_per_color;\n    }\n    uint32_t mem_caps = MALLOC_CAP_DEFAULT;\n    if (spi_config->flags.with_dma) {\n        // DMA buffer must be placed in internal SRAM\n        mem_caps |= MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA;\n    }\n    spi_strip = heap_caps_calloc(1, sizeof(led_strip_spi_obj) + led_config->max_leds * bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE, mem_caps);\n\n    ESP_GOTO_ON_FALSE(spi_strip, ESP_ERR_NO_MEM, err, TAG, \"no mem for spi strip\");\n\n    spi_strip->spi_host = spi_config->spi_bus;\n    // for backward compatibility, if the user does not set the clk_src, use the default value\n    spi_clock_source_t clk_src = SPI_CLK_SRC_DEFAULT;\n    if (spi_config->clk_src) {\n        clk_src = spi_config->clk_src;\n    }\n\n    spi_bus_config_t spi_bus_cfg = {\n        .mosi_io_num = led_config->strip_gpio_num,\n        //Only use MOSI to generate the signal, set -1 when other pins are not used.\n        .miso_io_num = -1,\n        .sclk_io_num = -1,\n        .quadwp_io_num = -1,\n        .quadhd_io_num = -1,\n        .max_transfer_sz = led_config->max_leds * bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE,\n    };\n    ESP_GOTO_ON_ERROR(spi_bus_initialize(spi_strip->spi_host, &spi_bus_cfg, spi_config->flags.with_dma ? SPI_DMA_CH_AUTO : SPI_DMA_DISABLED), err, TAG, \"create SPI bus failed\");\n\n    if (led_config->flags.invert_out == true) {\n        esp_rom_gpio_connect_out_signal(led_config->strip_gpio_num, spi_periph_signal[spi_strip->spi_host].spid_out, true, false);\n    }\n\n    spi_device_interface_config_t spi_dev_cfg = {\n        .clock_source = clk_src,\n        .command_bits = 0,\n        .address_bits = 0,\n        .dummy_bits = 0,\n        .clock_speed_hz = LED_STRIP_SPI_DEFAULT_RESOLUTION,\n        .mode = 0,\n        //set -1 when CS is not used\n        .spics_io_num = -1,\n        .queue_size = LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE,\n    };\n\n    ESP_GOTO_ON_ERROR(spi_bus_add_device(spi_strip->spi_host, &spi_dev_cfg, &spi_strip->spi_device), err, TAG, \"Failed to add spi device\");\n    //ensure the reset time is enough\n    esp_rom_delay_us(10);\n    int clock_resolution_khz = 0;\n    spi_device_get_actual_freq(spi_strip->spi_device, &clock_resolution_khz);\n    // TODO: ideally we should decide the SPI_BYTES_PER_COLOR_BYTE by the real clock resolution\n    // But now, let's fixed the resolution, the downside is, we don't support a clock source whose frequency is not multiple of LED_STRIP_SPI_DEFAULT_RESOLUTION\n    // clock_resolution between 2.2MHz to 2.8MHz is supported\n    ESP_GOTO_ON_FALSE((clock_resolution_khz < LED_STRIP_SPI_DEFAULT_RESOLUTION / 1000 + 300) && (clock_resolution_khz > LED_STRIP_SPI_DEFAULT_RESOLUTION / 1000 - 300), ESP_ERR_NOT_SUPPORTED, err,\n                      TAG, \"unsupported clock resolution:%dKHz\", clock_resolution_khz);\n\n    if (led_config->led_model != LED_MODEL_WS2812) {\n        ESP_LOGW(TAG, \"Only support WS2812. The timing requirements for other models may not be met\");\n    }\n\n    spi_strip->component_fmt = component_fmt;\n    spi_strip->bytes_per_pixel = bytes_per_pixel;\n    spi_strip->strip_len = led_config->max_leds;\n    spi_strip->base.set_pixel = led_strip_spi_set_pixel;\n    spi_strip->base.set_pixel_rgbw = led_strip_spi_set_pixel_rgbw;\n    spi_strip->base.refresh = led_strip_spi_refresh;\n    spi_strip->base.clear = led_strip_spi_clear;\n    spi_strip->base.del = led_strip_spi_del;\n\n    *ret_strip = &spi_strip->base;\n    return ESP_OK;\nerr:\n    if (spi_strip) {\n        if (spi_strip->spi_device) {\n            spi_bus_remove_device(spi_strip->spi_device);\n        }\n        if (spi_strip->spi_host) {\n            spi_bus_free(spi_strip->spi_host);\n        }\n        free(spi_strip);\n    }\n    return ret;\n}\n"
  },
  {
    "path": "libjpeg-turbo/.build-test-rules.yml",
    "content": "libjpeg-turbo/examples/hello_jpeg:\n  enable:\n    - if: (IDF_VERSION_MAJOR >= 5) and (IDF_TARGET in [\"esp32\", \"esp32c3\"])\n      reason: \"Sufficient to test on one Xtensa and one RISC-V target\"\n"
  },
  {
    "path": "libjpeg-turbo/CMakeLists.txt",
    "content": "idf_component_register(\n                       # We need the dummy source file so that the component\n                       # library is not an interface library. This allows to\n                       # get the list of include directories from other components\n                       # via INCLUDE_DIRECTORIES property later on.\n                       SRCS dummy.c)\n\n# Determine compilation flags used for building Jpeg-turbo\n# Flags inherited from IDF build system and other IDF components:\nset(idf_include_directories $<TARGET_PROPERTY:idf::libjpeg-turbo,INCLUDE_DIRECTORIES>)\nset(includes \"-I$<JOIN:${idf_include_directories}, -I>\")\n\nset(c_flags \"${includes} ${extra_defines} \")\nset(cxx_flags \"${includes} ${extra_defines} \")\nset(common_flags \"-ggdb -ffunction-sections -fdata-sections -lm\")\n\nif(CONFIG_IDF_TARGET_ARCH_XTENSA)\n    set(assert_flags \"${assert_flags} -mlongcalls\")\nendif()\n\n# We redefine the flags to apply common flags,\n# like -ffunction-sections -fdata-sections.\nif(CONFIG_COMPILER_OPTIMIZATION_DEFAULT)\n    set(opt_flags \"-Og ${common_flags} ${assert_flags}\")\n    set(opt_args -DCMAKE_BUILD_TYPE=Release\n                 -DCMAKE_C_FLAGS_RELEASE=${opt_flags})\nelseif(CONFIG_COMPILER_OPTIMIZATION_SIZE)\n    set(opt_flags \"-Os ${common_flags} ${assert_flags}\")\n    set(opt_args -DCMAKE_BUILD_TYPE=MinSizeRel\n                 -DCMAKE_C_FLAGS_MINSIZEREL=${opt_flags})\nelseif(CONFIG_COMPILER_OPTIMIZATION_PERF)\n    set(opt_flags \"-O3 ${common_flags} ${assert_flags}\")\n    set(opt_args -DCMAKE_BUILD_TYPE=Release\n                 -DCMAKE_C_FLAGS_RELEASE=${opt_flags})\nelseif(COMPILER_OPTIMIZATION_NONE)\n    set(opt_flags \"-O0 ${common_flags} ${assert_flags}\")\n    set(opt_args -DCMAKE_BUILD_TYPE=Debug\n                 -DCMAKE_C_FLAGS_DEBUG=${opt_flags})\nelse()\n    message(FATAL_ERROR \"Unsupported optimization level\")\nendif()\n\ninclude(ExternalProject)\n\n# Build jpeg-turbo in this directory:\nset(BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/libjpeg-build)\n\nset(lib_path ${BINARY_DIR}/install/lib/libjpeg.a)\nadd_prebuilt_library(libjpeg-turbo ${lib_path})\n\n# Add jpeg-turbo as a subproject.\nExternalProject_Add(jpegturbo_proj\n    SOURCE_DIR ${COMPONENT_DIR}/libjpeg-turbo\n    BINARY_DIR ${BINARY_DIR}\n    BUILD_BYPRODUCTS ${lib_path}\n    # These two options are set so that Ninja immediately outputs\n    # the subproject build to the terminal. Otherwise it looks like the\n    # build process \"hangs\" for too long until jpeg-turbo build is complete.\n    USES_TERMINAL_CONFIGURE TRUE\n    USES_TERMINAL_BUILD TRUE\n    CMAKE_POSITION_INDEPENDENT_CODE ON\n    # Arguments to pass to jpeg-turbo CMake invocation:\n    CMAKE_ARGS\n        -DCMAKE_C_FLAGS=${c_flags}\n        -DCMAKE_CXX_FLAGS=${cxx_flags}\n        ${opt_args}\n        -DCMAKE_INSTALL_PREFIX=${BINARY_DIR}/install\n        -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}\n        -DWITH_TURBOJPEG=FALSE\n        -DWITH_SIMD=FALSE\n        -DCMAKE_SYSTEM_PROCESSOR=esp32 # Without this parameter the lib make an error\n        -DWITH_ARITH_DEC=TRUE\n        -DWITH_ARITH_ENC=TRUE\n        -DWITH_JPEG8=TRUE\n        -DWITH_JPEG7=TRUE\n        -DENABLE_SHARED=FALSE\n        -DENABLE_STATIC=TRUE\n        -DWITH_TOOLS=FALSE\n        -DWITH_TESTS=FALSE\n)\n\n# Attach header files to the component library:\nset_target_properties(${COMPONENT_LIB} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${BINARY_DIR}/install/include)\n\n# Make sure the subproject is built before the component library:\nadd_dependencies(${COMPONENT_LIB} jpegturbo_proj)\n\n# Finally, link the interface library to the component library:\n# Attach IDF component dependencies to jpeg libraries\nforeach(dep ${deps})\n    target_link_libraries(libjpeg-turbo INTERFACE idf::${dep})\nendforeach()\n# Attach jpeg-turbo libraries to the component library\ntarget_link_libraries(${COMPONENT_LIB} INTERFACE libjpeg-turbo)\n"
  },
  {
    "path": "libjpeg-turbo/LICENSE",
    "content": "libjpeg-turbo Licenses\n======================\n\nlibjpeg-turbo is covered by two compatible BSD-style open source licenses:\n\n- The IJG (Independent JPEG Group) License, which is listed in\n  [README.ijg](README.ijg)\n\n  This license applies to the libjpeg API library and associated programs,\n  including any code inherited from libjpeg and any modifications to that\n  code.  Note that the libjpeg-turbo SIMD source code bears the\n  [zlib License](https://opensource.org/licenses/Zlib), but in the context of\n  the overall libjpeg API library, the terms of the zlib License are subsumed\n  by the terms of the IJG License.\n\n- The Modified (3-clause) BSD License, which is listed below\n\n  This license applies to the TurboJPEG API library and associated programs, as\n  well as the build system.  Note that the TurboJPEG API library wraps the\n  libjpeg API library, so in the context of the overall TurboJPEG API library,\n  both the terms of the IJG License and the terms of the Modified (3-clause)\n  BSD License apply.\n\n\nComplying with the libjpeg-turbo Licenses\n=========================================\n\nThis section provides a roll-up of the libjpeg-turbo licensing terms, to the\nbest of our understanding.  This is not a license in and of itself.  It is\nintended solely for clarification.\n\n1.  If you are distributing a modified version of the libjpeg-turbo source,\n    then:\n\n    1.  You cannot alter or remove any existing copyright or license notices\n        from the source.\n\n        **Origin**\n        - Clause 1 of the IJG License\n        - Clause 1 of the Modified BSD License\n        - Clauses 1 and 3 of the zlib License\n\n    2.  You must add your own copyright notice to the header of each source\n        file you modified, so others can tell that you modified that file.  (If\n        there is not an existing copyright header in that file, then you can\n        simply add a notice stating that you modified the file.)\n\n        **Origin**\n        - Clause 1 of the IJG License\n        - Clause 2 of the zlib License\n\n    3.  You must include the IJG README file, and you must not alter any of the\n        copyright or license text in that file.\n\n        **Origin**\n        - Clause 1 of the IJG License\n\n2.  If you are distributing only libjpeg-turbo binaries without the source, or\n    if you are distributing an application that statically links with\n    libjpeg-turbo, then:\n\n    1.  Your product documentation must include a message stating:\n\n        This software is based in part on the work of the Independent JPEG\n        Group.\n\n        **Origin**\n        - Clause 2 of the IJG license\n\n    2.  If your binary distribution includes or uses the TurboJPEG API, then\n        your product documentation must include the text of the Modified BSD\n        License (see below.)\n\n        **Origin**\n        - Clause 2 of the Modified BSD License\n\n3.  You cannot use the name of the IJG or The libjpeg-turbo Project or the\n    contributors thereof in advertising, publicity, etc.\n\n    **Origin**\n    - IJG License\n    - Clause 3 of the Modified BSD License\n\n4.  The IJG and The libjpeg-turbo Project do not warrant libjpeg-turbo to be\n    free of defects, nor do we accept any liability for undesirable\n    consequences resulting from your use of the software.\n\n    **Origin**\n    - IJG License\n    - Modified BSD License\n    - zlib License\n\n\nThe Modified (3-clause) BSD License\n===================================\n\nCopyright (C)2009-2024 D. R. Commander.  All Rights Reserved.<br>\nCopyright (C)2015 Viktor Szathmáry.  All Rights Reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n- Redistributions of source code must retain the above copyright notice,\n  this list of conditions and the following disclaimer.\n- Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n- Neither the name of the libjpeg-turbo Project nor the names of its\n  contributors may be used to endorse or promote products derived from this\n  software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\",\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n\n\nWhy Two Licenses?\n=================\n\nThe zlib License could have been used instead of the Modified (3-clause) BSD\nLicense, and since the IJG License effectively subsumes the distribution\nconditions of the zlib License, this would have effectively placed\nlibjpeg-turbo binary distributions under the IJG License.  However, the IJG\nLicense specifically refers to the Independent JPEG Group and does not extend\nattribution and endorsement protections to other entities.  Thus, it was\ndesirable to choose a license that granted us the same protections for new code\nthat were granted to the IJG for code derived from their software.\n"
  },
  {
    "path": "libjpeg-turbo/README.md",
    "content": "# Jpeg-turbo for ESP-IDF\n\n[![Component Registry](https://components.espressif.com/components/espressif/libjpeg-turbo/badge.svg)](https://components.espressif.com/components/espressif/libjpeg-turbo)\n\nThis component ports libjpeg-turbo library into the esp-idf.\n\n**libjpeg-turbo is a JPEG image codec**\n\nFor more information go to https://github.com/libjpeg-turbo/libjpeg-turbo.\n\nFor ***pull request***, ***bug reports***, and ***feature requests***, go to https://github.com/libjpeg-turbo/libjpeg-turbo.\n\n"
  },
  {
    "path": "libjpeg-turbo/dummy.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */"
  },
  {
    "path": "libjpeg-turbo/examples/hello_jpeg/CMakeLists.txt",
    "content": "# The following lines of boilerplate have to be in your project's\n# CMakeLists in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nproject(hello-libjpeg)\n"
  },
  {
    "path": "libjpeg-turbo/examples/hello_jpeg/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"main.c\" \"decode_image.c\"\n                    INCLUDE_DIRS \".\"\n                    EMBED_FILES image32x32.jpg image.jpg \n                    REQUIRES esp_timer)\n"
  },
  {
    "path": "libjpeg-turbo/examples/hello_jpeg/main/decode_image.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n\n#include <string.h>\n#include \"decode_image.h\"\n#include \"esp_log.h\"\n#include \"esp_check.h\"\n#include \"freertos/FreeRTOS.h\"\n\n#include \"esp_cpu.h\"\n\n#include \"jpeglib.h\"\n#include \"jerror.h\"\n\n/* Reference the binary-included jpeg file */\nextern const uint8_t image_jpg_start[] asm(\"_binary_image_jpg_start\");\nextern const uint8_t image_jpg_end[] asm(\"_binary_image_jpg_end\");\nextern const uint8_t image32x32_jpg_start[] asm(\"_binary_image32x32_jpg_start\");\nextern const uint8_t image32x32_jpg_end[] asm(\"_binary_image32x32_jpg_end\");\n/* Define the height and width of the jpeg file. Make sure this matches the actual jpeg\n  dimensions. */\n\nconst char *TAG = \"ImageDec\";\n\nstruct my_error_mgr {\n    struct jpeg_error_mgr pub;    /* \"public\" fields */\n\n    void *setjmp_buffer;        /* for return to caller */\n};\n\ntypedef struct my_error_mgr *my_error_ptr;\n\n\nvoid my_error_exit(j_common_ptr cinfo)\n{\n    printf(\"Error - my_error_exit()! \\n\");\n}\n\n/* Decode the embedded image into pixel lines that can be used with the rest of the logic.\n*/\nesp_err_t decode_image(uint16_t **pixels)\n{\n    *pixels = NULL;\n    esp_err_t ret = ESP_OK;\n\n    struct my_error_mgr jerr;\n    JSAMPARRAY buffer = NULL;     /* Output row buffer */\n\n    struct jpeg_decompress_struct jpeg_info;\n    struct jpeg_decompress_struct *cinfo = &jpeg_info;\n\n    cinfo->err = jpeg_std_error(&jerr.pub);\n    jerr.pub.error_exit = my_error_exit;\n\n    struct jpeg_decompress_struct jpeg_info_print;\n    struct jpeg_decompress_struct *cinfo_print = &jpeg_info_print;\n\n    cinfo_print->err = jpeg_std_error(&jerr.pub);\n    jerr.pub.error_exit = my_error_exit;\n\n\n    jpeg_create_decompress(cinfo);\n\n    jpeg_mem_src(cinfo, image_jpg_start, (image_jpg_end - image_jpg_start));\n\n    (void)jpeg_read_header(cinfo, TRUE);\n    /* We can ignore the return value from jpeg_read_header since\n     *   (a) suspension is not possible with the stdio data source, and\n     *   (b) we passed TRUE to reject a tables-only JPEG file as an error.\n     * See libjpeg.txt for more info.\n     */\n\n    /* emit header for raw PPM format */\n    printf(\"P6\\n%u %u\\n%d\\n\", cinfo->image_width, cinfo->image_height,\n           cinfo->data_precision == 12 ? MAXJ12SAMPLE : MAXJSAMPLE);\n\n    printf(\"jpeg_start_decompress\\n\");\n    unsigned int start_b = esp_cpu_get_cycle_count();\n    jpeg_start_decompress(cinfo);\n\n    int row_stride = cinfo->output_width * cinfo->output_components;\n    buffer = (*cinfo->mem->alloc_sarray)\n             ((j_common_ptr)cinfo, JPOOL_IMAGE, row_stride, 1);\n\n    while (cinfo->output_scanline < cinfo->output_height) {\n        /* jpeg_read_scanlines expects an array of pointers to scanlines.\n         * Here the array is only one element long, but you could ask for\n         * more than one scanline at a time if that's more convenient.\n         */\n        (void)jpeg_read_scanlines(cinfo, buffer, 1);\n    }\n    unsigned int end_b = esp_cpu_get_cycle_count();\n    printf(\"jpeg_finish_decompress, time = %i\\n\", ((unsigned int)(end_b - start_b) / 100000) * 100000);\n    jpeg_finish_decompress(cinfo);\n\n    printf(\"jpeg_destroy_decompress\\n\");\n    jpeg_destroy_decompress(cinfo);\n\n    jpeg_create_decompress(cinfo_print);\n\n    jpeg_mem_src(cinfo_print, image32x32_jpg_start, (image32x32_jpg_end - image32x32_jpg_start));\n    jpeg_read_header(cinfo_print, TRUE);\n    printf(\"P6\\n%u %u\\n%d\\n\", cinfo_print->image_width, cinfo_print->image_height,\n           cinfo_print->data_precision == 12 ? MAXJ12SAMPLE : MAXJSAMPLE);\n\n    jpeg_start_decompress(cinfo_print);\n\n    row_stride = cinfo_print->output_width * cinfo_print->output_components;\n    buffer = (*cinfo_print->mem->alloc_sarray)\n             ((j_common_ptr)cinfo_print, JPOOL_IMAGE, row_stride, 1);\n\n    printf(\"Decoded image 32x32:\\n\");\n    while (cinfo_print->output_scanline < cinfo_print->output_height) {\n        (void)jpeg_read_scanlines(cinfo_print, buffer, 1);\n        for (int ix = 0; ix < cinfo_print->image_width; ix++) {\n            int val = 0;\n            for (int i = 0; i < cinfo_print->output_components; i++) {\n                val += buffer[0][ix * cinfo_print->output_components + i];\n            }\n            val = val / cinfo->output_components;\n            if (val > 127) {\n                putchar('#');\n            } else if (val > 64) {\n                putchar('+');\n            } else if (val > 32) {\n                putchar('.');\n            } else {\n                putchar(' ');\n            }\n        }\n        putchar('\\n');\n    }\n    jpeg_finish_decompress(cinfo_print);\n    jpeg_destroy_decompress(cinfo_print);\n    printf(\"done\\n\");\n\n    return ret;\n}\n"
  },
  {
    "path": "libjpeg-turbo/examples/hello_jpeg/main/decode_image.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n\n#pragma once\n#include <stdint.h>\n#include \"esp_err.h\"\n\n#define IMAGE_W 320\n#define IMAGE_H 240\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief Decode the jpeg ``image.jpg`` embedded into the program file into pixel data and measure the performance.\n *\n * @param pixels A pointer to a pointer for an array of rows, which themselves are an array of pixels.\n * @return - ESP_OK on successful decode\n */\nesp_err_t decode_image(uint16_t **pixels);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "libjpeg-turbo/examples/hello_jpeg/main/idf_component.yml",
    "content": "## IDF Component Manager Manifest File\ndependencies:\n  espressif/libjpeg-turbo: \n    version: \"^3.1.0\"\n    # This line define the local path of the jpeg-turbo component because this \n    # example is part of the jpeg-turbo component. This line is optional.\n    override_path: \"../../..\"\n  ## Required IDF version\n  idf:\n    version: \">=5.0.0\"\n"
  },
  {
    "path": "libjpeg-turbo/examples/hello_jpeg/main/main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdint.h>\n#include <esp_log.h>\n\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"esp_system.h\"\n\n#include \"decode_image.h\"\n\nuint16_t *pixels;\n\n\nvoid app_main(void)\n{\n    printf(\"app_main started\\n\");\n    decode_image(&pixels);\n}\n"
  },
  {
    "path": "libjpeg-turbo/idf_component.yml",
    "content": "\nversion: \"3.1.1~1\"\ndescription: Jpeg-turbo port to ESP\nurl: https://github.com/espressif/idf-extra-components/tree/master/libjpeg-turbo\ndependencies:\n  idf: \">=5.0.0\"\n"
  },
  {
    "path": "libjpeg-turbo/sbom_libjpeg.yml",
    "content": "name: libjpeg-turbo\nversion: 3.1.1\ncpe: cpe:3.1.1:a:libjpeg:libjpeg:{}:*:*:*:*:*:*:*\nsupplier: 'Organization: libjpeg-turbo'\ndescription: libjpeg-turbo is a JPEG image codec library\nurl: https://github.com/libjpeg-turbo/libjpeg-turbo\nhash: 98c458381f0938b2cea222f5b278b4ced6f70805\n"
  },
  {
    "path": "libpng/.build-test-rules.yml",
    "content": "libpng/test_apps:\n  enable:\n    - if: IDF_TARGET in [\"esp32\", \"esp32c3\"]\n      reason: \"Sufficient to test on one Xtensa and one RISC-V target\"\n"
  },
  {
    "path": "libpng/CMakeLists.txt",
    "content": "idf_component_register(INCLUDE_DIRS . libpng\n                       SRC_DIRS libpng)\n\ntarget_compile_options(${COMPONENT_LIB} PRIVATE -Wno-maybe-uninitialized)\n"
  },
  {
    "path": "libpng/LICENSE",
    "content": "COPYRIGHT NOTICE, DISCLAIMER, and LICENSE\n=========================================\n\nPNG Reference Library License version 2\n---------------------------------------\n\n * Copyright (c) 1995-2019 The PNG Reference Library Authors.\n * Copyright (c) 2018-2019 Cosmin Truta.\n * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.\n * Copyright (c) 1996-1997 Andreas Dilger.\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n\nThe software is supplied \"as is\", without warranty of any kind,\nexpress or implied, including, without limitation, the warranties\nof merchantability, fitness for a particular purpose, title, and\nnon-infringement.  In no event shall the Copyright owners, or\nanyone distributing the software, be liable for any damages or\nother liability, whether in contract, tort or otherwise, arising\nfrom, out of, or in connection with the software, or the use or\nother dealings in the software, even if advised of the possibility\nof such damage.\n\nPermission is hereby granted to use, copy, modify, and distribute\nthis software, or portions hereof, for any purpose, without fee,\nsubject to the following restrictions:\n\n 1. The origin of this software must not be misrepresented; you\n    must not claim that you wrote the original software.  If you\n    use this software in a product, an acknowledgment in the product\n    documentation would be appreciated, but is not required.\n\n 2. Altered source versions must be plainly marked as such, and must\n    not be misrepresented as being the original software.\n\n 3. This Copyright notice may not be removed or altered from any\n    source or altered source distribution.\n\n\nPNG Reference Library License version 1 (for libpng 0.5 through 1.6.35)\n-----------------------------------------------------------------------\n\nlibpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are\nCopyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are\nderived from libpng-1.0.6, and are distributed according to the same\ndisclaimer and license as libpng-1.0.6 with the following individuals\nadded to the list of Contributing Authors:\n\n    Simon-Pierre Cadieux\n    Eric S. Raymond\n    Mans Rullgard\n    Cosmin Truta\n    Gilles Vollant\n    James Yu\n    Mandar Sahastrabuddhe\n    Google Inc.\n    Vadim Barkov\n\nand with the following additions to the disclaimer:\n\n    There is no warranty against interference with your enjoyment of\n    the library or against infringement.  There is no warranty that our\n    efforts or the library will fulfill any of your particular purposes\n    or needs.  This library is provided with all faults, and the entire\n    risk of satisfactory quality, performance, accuracy, and effort is\n    with the user.\n\nSome files in the \"contrib\" directory and some configure-generated\nfiles that are distributed with libpng have other copyright owners, and\nare released under other open source licenses.\n\nlibpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are\nCopyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from\nlibpng-0.96, and are distributed according to the same disclaimer and\nlicense as libpng-0.96, with the following individuals added to the\nlist of Contributing Authors:\n\n    Tom Lane\n    Glenn Randers-Pehrson\n    Willem van Schaik\n\nlibpng versions 0.89, June 1996, through 0.96, May 1997, are\nCopyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88,\nand are distributed according to the same disclaimer and license as\nlibpng-0.88, with the following individuals added to the list of\nContributing Authors:\n\n    John Bowler\n    Kevin Bracey\n    Sam Bushell\n    Magnus Holmgren\n    Greg Roelofs\n    Tom Tanner\n\nSome files in the \"scripts\" directory have other copyright owners,\nbut are released under this license.\n\nlibpng versions 0.5, May 1995, through 0.88, January 1996, are\nCopyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n\nFor the purposes of this copyright and license, \"Contributing Authors\"\nis defined as the following set of individuals:\n\n    Andreas Dilger\n    Dave Martindale\n    Guy Eric Schalnat\n    Paul Schmidt\n    Tim Wegner\n\nThe PNG Reference Library is supplied \"AS IS\".  The Contributing\nAuthors and Group 42, Inc. disclaim all warranties, expressed or\nimplied, including, without limitation, the warranties of\nmerchantability and of fitness for any purpose.  The Contributing\nAuthors and Group 42, Inc. assume no liability for direct, indirect,\nincidental, special, exemplary, or consequential damages, which may\nresult from the use of the PNG Reference Library, even if advised of\nthe possibility of such damage.\n\nPermission is hereby granted to use, copy, modify, and distribute this\nsource code, or portions hereof, for any purpose, without fee, subject\nto the following restrictions:\n\n 1. The origin of this source code must not be misrepresented.\n\n 2. Altered versions must be plainly marked as such and must not\n    be misrepresented as being the original source.\n\n 3. This Copyright notice may not be removed or altered from any\n    source or altered source distribution.\n\nThe Contributing Authors and Group 42, Inc. specifically permit,\nwithout fee, and encourage the use of this source code as a component\nto supporting the PNG file format in commercial products.  If you use\nthis source code in a product, acknowledgment is not required but would\nbe appreciated.\n"
  },
  {
    "path": "libpng/README.md",
    "content": "# PNG image encoding and decoding library\n\n[![Component Registry](https://components.espressif.com/components/espressif/libpng/badge.svg)](https://components.espressif.com/components/espressif/libpng)\n\nThis is an IDF component for libpng library.\n\nFor usage instructions, please refer to the official documentation: http://www.libpng.org/pub/png/libpng.html\n"
  },
  {
    "path": "libpng/idf_component.yml",
    "content": "version: \"1.6.58\"\ndescription: Portable Network Graphics(png) C library\nurl: https://github.com/espressif/idf-extra-components/tree/master/libpng\nrepository: \"https://github.com/espressif/idf-extra-components.git\"\nrepository_info:\n  path: \"libpng\"\ndocumentation: \"http://www.libpng.org/pub/png/pngdocs.html\"\nissues: \"https://github.com/espressif/idf-extra-components/issues\"\ndependencies:\n  idf: \">=5.0\"\n  zlib:\n    version: \"^1.2.13\"\n    override_path: \"../zlib\"\nsbom:\n  manifests:\n    - path: sbom_libpng.yml\n      dest: libpng\n"
  },
  {
    "path": "libpng/pnglibconf.h",
    "content": "/* pnglibconf.h - library build configuration */\n\n/* libpng version 1.6.58 */\n\n/* Copyright (c) 2018-2025 Cosmin Truta */\n/* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */\n\n/* This code is released under the libpng license. */\n/* For conditions of distribution and use, see the disclaimer */\n/* and license in png.h */\n\n/* pnglibconf.h */\n/* Machine generated file: DO NOT EDIT */\n/* Derived from: scripts/pnglibconf.dfa */\n#ifndef PNGLCONF_H\n#define PNGLCONF_H\n/* options */\n#define PNG_16BIT_SUPPORTED\n#define PNG_ALIGNED_MEMORY_SUPPORTED\n/*#undef PNG_ARM_NEON_API_SUPPORTED*/\n/*#undef PNG_ARM_NEON_CHECK_SUPPORTED*/\n#define PNG_BENIGN_ERRORS_SUPPORTED\n#define PNG_BENIGN_READ_ERRORS_SUPPORTED\n/*#undef PNG_BENIGN_WRITE_ERRORS_SUPPORTED*/\n#define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED\n#define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED\n#define PNG_COLORSPACE_SUPPORTED\n#define PNG_CONSOLE_IO_SUPPORTED\n#define PNG_CONVERT_tIME_SUPPORTED\n/*#undef PNG_DISABLE_ADLER32_CHECK_SUPPORTED*/\n#define PNG_EASY_ACCESS_SUPPORTED\n/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/\n#define PNG_ERROR_TEXT_SUPPORTED\n#define PNG_FIXED_POINT_SUPPORTED\n#define PNG_FLOATING_ARITHMETIC_SUPPORTED\n#define PNG_FLOATING_POINT_SUPPORTED\n#define PNG_FORMAT_AFIRST_SUPPORTED\n#define PNG_FORMAT_BGR_SUPPORTED\n#define PNG_GAMMA_SUPPORTED\n#define PNG_GET_PALETTE_MAX_SUPPORTED\n#define PNG_HANDLE_AS_UNKNOWN_SUPPORTED\n#define PNG_INCH_CONVERSIONS_SUPPORTED\n#define PNG_INFO_IMAGE_SUPPORTED\n#define PNG_IO_STATE_SUPPORTED\n/*#undef PNG_MIPS_MMI_API_SUPPORTED*/\n/*#undef PNG_MIPS_MMI_CHECK_SUPPORTED*/\n/*#undef PNG_MIPS_MSA_API_SUPPORTED*/\n/*#undef PNG_MIPS_MSA_CHECK_SUPPORTED*/\n#define PNG_MNG_FEATURES_SUPPORTED\n#define PNG_POINTER_INDEXING_SUPPORTED\n/*#undef PNG_POWERPC_VSX_API_SUPPORTED*/\n/*#undef PNG_POWERPC_VSX_CHECK_SUPPORTED*/\n#define PNG_PROGRESSIVE_READ_SUPPORTED\n#define PNG_READ_16BIT_SUPPORTED\n#define PNG_READ_ALPHA_MODE_SUPPORTED\n#define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED\n#define PNG_READ_BACKGROUND_SUPPORTED\n#define PNG_READ_BGR_SUPPORTED\n#define PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED\n#define PNG_READ_COMPOSITE_NODIV_SUPPORTED\n#define PNG_READ_COMPRESSED_TEXT_SUPPORTED\n#define PNG_READ_EXPAND_16_SUPPORTED\n#define PNG_READ_EXPAND_SUPPORTED\n#define PNG_READ_FILLER_SUPPORTED\n#define PNG_READ_GAMMA_SUPPORTED\n#define PNG_READ_GET_PALETTE_MAX_SUPPORTED\n#define PNG_READ_GRAY_TO_RGB_SUPPORTED\n#define PNG_READ_INTERLACING_SUPPORTED\n#define PNG_READ_INT_FUNCTIONS_SUPPORTED\n#define PNG_READ_INVERT_ALPHA_SUPPORTED\n#define PNG_READ_INVERT_SUPPORTED\n#define PNG_READ_OPT_PLTE_SUPPORTED\n#define PNG_READ_PACKSWAP_SUPPORTED\n#define PNG_READ_PACK_SUPPORTED\n#define PNG_READ_QUANTIZE_SUPPORTED\n#define PNG_READ_RGB_TO_GRAY_SUPPORTED\n#define PNG_READ_SCALE_16_TO_8_SUPPORTED\n#define PNG_READ_SHIFT_SUPPORTED\n#define PNG_READ_STRIP_16_TO_8_SUPPORTED\n#define PNG_READ_STRIP_ALPHA_SUPPORTED\n#define PNG_READ_SUPPORTED\n#define PNG_READ_SWAP_ALPHA_SUPPORTED\n#define PNG_READ_SWAP_SUPPORTED\n#define PNG_READ_TEXT_SUPPORTED\n#define PNG_READ_TRANSFORMS_SUPPORTED\n#define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED\n#define PNG_READ_USER_CHUNKS_SUPPORTED\n#define PNG_READ_USER_TRANSFORM_SUPPORTED\n#define PNG_READ_bKGD_SUPPORTED\n#define PNG_READ_cHRM_SUPPORTED\n#define PNG_READ_cICP_SUPPORTED\n#define PNG_READ_cLLI_SUPPORTED\n#define PNG_READ_eXIf_SUPPORTED\n#define PNG_READ_gAMA_SUPPORTED\n#define PNG_READ_hIST_SUPPORTED\n#define PNG_READ_iCCP_SUPPORTED\n#define PNG_READ_iTXt_SUPPORTED\n#define PNG_READ_mDCV_SUPPORTED\n#define PNG_READ_oFFs_SUPPORTED\n#define PNG_READ_pCAL_SUPPORTED\n#define PNG_READ_pHYs_SUPPORTED\n#define PNG_READ_sBIT_SUPPORTED\n#define PNG_READ_sCAL_SUPPORTED\n#define PNG_READ_sPLT_SUPPORTED\n#define PNG_READ_sRGB_SUPPORTED\n#define PNG_READ_tEXt_SUPPORTED\n#define PNG_READ_tIME_SUPPORTED\n#define PNG_READ_tRNS_SUPPORTED\n#define PNG_READ_zTXt_SUPPORTED\n#define PNG_SAVE_INT_32_SUPPORTED\n#define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED\n#define PNG_SEQUENTIAL_READ_SUPPORTED\n#define PNG_SETJMP_SUPPORTED\n#define PNG_SET_OPTION_SUPPORTED\n#define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED\n#define PNG_SET_USER_LIMITS_SUPPORTED\n#define PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED\n#define PNG_SIMPLIFIED_READ_BGR_SUPPORTED\n#define PNG_SIMPLIFIED_READ_SUPPORTED\n#define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED\n#define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED\n#define PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED\n#define PNG_SIMPLIFIED_WRITE_SUPPORTED\n#define PNG_STDIO_SUPPORTED\n#define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED\n#define PNG_TEXT_SUPPORTED\n#define PNG_TIME_RFC1123_SUPPORTED\n#define PNG_UNKNOWN_CHUNKS_SUPPORTED\n#define PNG_USER_CHUNKS_SUPPORTED\n#define PNG_USER_LIMITS_SUPPORTED\n#define PNG_USER_MEM_SUPPORTED\n#define PNG_USER_TRANSFORM_INFO_SUPPORTED\n#define PNG_USER_TRANSFORM_PTR_SUPPORTED\n#define PNG_WARNINGS_SUPPORTED\n#define PNG_WRITE_16BIT_SUPPORTED\n#define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED\n#define PNG_WRITE_BGR_SUPPORTED\n#define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED\n#define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED\n#define PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED\n#define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED\n#define PNG_WRITE_FILLER_SUPPORTED\n#define PNG_WRITE_FILTER_SUPPORTED\n#define PNG_WRITE_FLUSH_SUPPORTED\n#define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED\n#define PNG_WRITE_INTERLACING_SUPPORTED\n#define PNG_WRITE_INT_FUNCTIONS_SUPPORTED\n#define PNG_WRITE_INVERT_ALPHA_SUPPORTED\n#define PNG_WRITE_INVERT_SUPPORTED\n#define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED\n#define PNG_WRITE_PACKSWAP_SUPPORTED\n#define PNG_WRITE_PACK_SUPPORTED\n#define PNG_WRITE_SHIFT_SUPPORTED\n#define PNG_WRITE_SUPPORTED\n#define PNG_WRITE_SWAP_ALPHA_SUPPORTED\n#define PNG_WRITE_SWAP_SUPPORTED\n#define PNG_WRITE_TEXT_SUPPORTED\n#define PNG_WRITE_TRANSFORMS_SUPPORTED\n#define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED\n#define PNG_WRITE_USER_TRANSFORM_SUPPORTED\n#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED\n#define PNG_WRITE_bKGD_SUPPORTED\n#define PNG_WRITE_cHRM_SUPPORTED\n#define PNG_WRITE_cICP_SUPPORTED\n#define PNG_WRITE_cLLI_SUPPORTED\n#define PNG_WRITE_eXIf_SUPPORTED\n#define PNG_WRITE_gAMA_SUPPORTED\n#define PNG_WRITE_hIST_SUPPORTED\n#define PNG_WRITE_iCCP_SUPPORTED\n#define PNG_WRITE_iTXt_SUPPORTED\n#define PNG_WRITE_mDCV_SUPPORTED\n#define PNG_WRITE_oFFs_SUPPORTED\n#define PNG_WRITE_pCAL_SUPPORTED\n#define PNG_WRITE_pHYs_SUPPORTED\n#define PNG_WRITE_sBIT_SUPPORTED\n#define PNG_WRITE_sCAL_SUPPORTED\n#define PNG_WRITE_sPLT_SUPPORTED\n#define PNG_WRITE_sRGB_SUPPORTED\n#define PNG_WRITE_tEXt_SUPPORTED\n#define PNG_WRITE_tIME_SUPPORTED\n#define PNG_WRITE_tRNS_SUPPORTED\n#define PNG_WRITE_zTXt_SUPPORTED\n#define PNG_bKGD_SUPPORTED\n#define PNG_cHRM_SUPPORTED\n#define PNG_cICP_SUPPORTED\n#define PNG_cLLI_SUPPORTED\n#define PNG_eXIf_SUPPORTED\n#define PNG_gAMA_SUPPORTED\n#define PNG_hIST_SUPPORTED\n#define PNG_iCCP_SUPPORTED\n#define PNG_iTXt_SUPPORTED\n#define PNG_mDCV_SUPPORTED\n#define PNG_oFFs_SUPPORTED\n#define PNG_pCAL_SUPPORTED\n#define PNG_pHYs_SUPPORTED\n#define PNG_sBIT_SUPPORTED\n#define PNG_sCAL_SUPPORTED\n#define PNG_sPLT_SUPPORTED\n#define PNG_sRGB_SUPPORTED\n#define PNG_tEXt_SUPPORTED\n#define PNG_tIME_SUPPORTED\n#define PNG_tRNS_SUPPORTED\n#define PNG_zTXt_SUPPORTED\n/* end of options */\n/* settings */\n#define PNG_API_RULE 0\n#define PNG_DEFAULT_READ_MACROS 1\n#define PNG_GAMMA_THRESHOLD_FIXED 5000\n#define PNG_IDAT_READ_SIZE PNG_ZBUF_SIZE\n#define PNG_INFLATE_BUF_SIZE 1024\n#define PNG_LINKAGE_API extern\n#define PNG_LINKAGE_CALLBACK extern\n#define PNG_LINKAGE_DATA extern\n#define PNG_LINKAGE_FUNCTION extern\n#define PNG_MAX_GAMMA_8 11\n#define PNG_QUANTIZE_BLUE_BITS 5\n#define PNG_QUANTIZE_GREEN_BITS 5\n#define PNG_QUANTIZE_RED_BITS 5\n#define PNG_TEXT_Z_DEFAULT_COMPRESSION (-1)\n#define PNG_TEXT_Z_DEFAULT_STRATEGY 0\n#define PNG_USER_CHUNK_CACHE_MAX 1000\n#define PNG_USER_CHUNK_MALLOC_MAX 8000000\n#define PNG_USER_HEIGHT_MAX 1000000\n#define PNG_USER_WIDTH_MAX 1000000\n#define PNG_ZBUF_SIZE 8192\n#define PNG_ZLIB_VERNUM 0 /* unknown */\n#define PNG_Z_DEFAULT_COMPRESSION (-1)\n#define PNG_Z_DEFAULT_NOFILTER_STRATEGY 0\n#define PNG_Z_DEFAULT_STRATEGY 1\n#define PNG_sCAL_PRECISION 5\n#define PNG_sRGB_PROFILE_CHECKS 2\n/* end of settings */\n#endif /* PNGLCONF_H */\n"
  },
  {
    "path": "libpng/sbom_libpng.yml",
    "content": "name: libpng\nversion: 1.6.58\ncpe:\n - cpe:2.3:a:pnggroup:libpng:{}:*:*:*:*:*:*:*\n - cpe:2.3:a:libpng:libpng:{}:*:*:*:*:*:*:*\nsupplier: 'Organization: pnggroup'\ndescription: Portable Network Graphics support, official PNG reference library\nurl: https://github.com/pnggroup/libpng\nhash: 3061454d980de7d53608f594194cfac722721d2a\ncve-exclude-list:\n  - cve: CVE-2026-33636\n    reason: Resolved in version 1.6.56\n  - cve: CVE-2026-33416\n    reason: Resolved in version 1.6.56\n  - cve: CVE-2026-3713\n    reason: Resolved in version 1.6.56\n  - cve: CVE-2026-34757\n    reason: Resolved in version 1.6.57\n\n"
  },
  {
    "path": "libpng/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(libpng_test)\n"
  },
  {
    "path": "libpng/test_apps/main/CMakeLists.txt",
    "content": "idf_component_register(\n    SRCS test_libpng.c test_main.c\n    PRIV_REQUIRES unity\n    WHOLE_ARCHIVE\n    EMBED_FILES \"in.png\" \"out.pgm\")\n"
  },
  {
    "path": "libpng/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/libpng:\n    version: \"*\"\n    override_path: \"../..\"\n"
  },
  {
    "path": "libpng/test_apps/main/out.pgm",
    "content": "P5\n522 52\n255\n¶঒۶_YYYYbYY|YYYkYYYYYYYYY]YYiYYkiYYZZ_ZgZpZkjZ_ZgYYYYnYYƸYYYZZZZZZZZZZZZZZYYYYYrYYYYfZZZZzZZZbc_t__jZ|ZZzYYcsYYZYYYYuZZӾZZZZZZZZZZӾkkbYYYkkkٝ|bY_溅iYYfkkYYYbkkYYZkk|YYّrYY]knґnYY]kkiYYckYY_kks_YYjZZjzZZZ_ZZgZbmZzYYYYYYYYY]YYYYYYY{YYYYYYYY]YYYYYYYYYYrYYbYYbYYYYYYbZYYZYYYYYYgYYwYYYYYYZYYYYYYY]ǠYYgYYYYYYYYZZ_Zjۺྺ⾼ܼZZ֌ZZննZZp²ٷྺͲZZõո²ܶnnYYYjnntYYYYbsZYYYzYYYffYYYnn_YY]nnnYYiYYYYYYYY_r]YYYfYYYYYYbr]YYYkYYYYY_r_YYYZvYYYYcr]YYb|YY]YYYYnkYYYYZZZZZZgZZZZ~ZZpZZZZvpZezZZZZziZZZZpiZnZ_ZZZZZZZZbZZZZw_ZZZZbtZZZZZZZkiZZZZZ}ZZgZZZ_ZZpZZZZv߃ZZZZZmpZuZZbZZZvpZZZZiZZZZZ}ZZZZpZZZ_YYYYYYiYYYYYYYYZYYjYYYYYYYYYtYYYYYYY|YYYwYYYfYYYYYY~YYYYYbYYYrYY]ZZZZZZmZZZZZZZpZZk_ZZZZZZcZZkeZZZZZZpZZZZZZZ_ZZ_ZZZZZZZZZiZZZZZZZg|ZZZZZZZZZZZZZZZZZZZZZZZZcZZvZZZZZZZzZZk_ZZZZZZcgZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZcZZZZzZZZZZZZYYkuYYnYYrYY_kkjYYYYYYYgYYYYYsYYY{YY]YYikYYZYYYYY_YYZ_YYkZZZZZZZZ˨_ZZZZZZʹgZZmZZZZʚZZZZZZ˭bZbZZZZɭZZ_ZZtζvZZjZZj٭_ZZpZZZZ_ƞiZZZZZZʤ_ZZZZZZʹgZZmZZ}ӖZZguZp{ZZZZZZ_ZwZZZZZ_ƞiZZZZZZZeăZZZYYYYYYY]YYYYYYYY_YYtYYfYYZiYYnYY_YYYYYYYbYYY{YYY檆ZZsuZZpZZ_ZZbZZZbZZZZ_ZZZZ__ZZZ_ZZZZZmZZZZZZbZgbbZZpgZZbZZiZZZbZZeZeZZZZbZZpZZZbZZbbZZpuZZZZjcZZtYYYYnYYYYYYZYYbYY{~YYZYYYYYYYYYYYYYbYYfYYbYYYY]ZZZZpZZZZZkZZZZZZZZw~ZZZZZZZZZZZcZZvZZZZbZgZZZvZZkZZZZZZbwZnZZcZZmZZbZgZZpcZZZZZYYrYYYYYYYYYYYYYYYYYYYwYY~YYbYYYYbYYYYYjYYZYYsYYYYYbYYYYZZZZZZwZZZZcZZiZZZZZZgZZv_ZiZ_ZZܼZZZZbZZZZzZZZZZZcZZgZZkZZZZZZZZZZzZZZZnZZYYZ_YYYYYYYYYYYYYZYYYYYY]~YYbYYYYYYYwYYbYYYYknYYZYYYYZYYYrYYZZZZZZZZZZZZZZwZZZZZZZZZZzZZZZZZZZZZZZ_ZZZZZZ㭃iZZZZZZZZZZZZZZZZZZZb|ZkZZ~ZZkZZ㭃iZZZZZZZZZZZZZYYtYYYٚiYYYYYbYYYYYYYnYYYYv~YYYYYYYYYZYYgYYicYYcZbZZZZ~ZZZZZZZZZZZZZZbZZZkZZZZZZZZZZZZvZZZZZjsZZgZZZZZZZZZZ|ZZuZZZZZZgZZZZZ~ZZsZZbZcZZugZZZZZZZZZZZZZZpZZYYYYYҊYYYbYYYYYfYYkYYrYYbYYiYYYY]YYsYY]YYbYYZZ{kZ_iZZgZ_ZZ~ZZZZwZZZZZZZZZZZZj˗iZZZcZZnbZZktZZbZbbZgZZ~ZZ彊bZZZ~ZiZZmZZ~ZZbZZktZZkZ_wZZZZpkYYYYYYYYYYiYYuYYYYYYYYYYYYYYYYwYYYYYYYYnYYZZZZzZZZZZzeZZZZc}ZZ_ZjZZZZccZ}ZZZZZbZZZZZZ_ZeZZ_ZZeZZZZcZZZZZZZZZZZZZ_ZeZZz_ZiZZYYYbYYpnsYYYYY|vYYZYYYYYZjYYYYY]cYYYYkYYiYY~gYYYYY_YYYZZZZZZZnZZZZZZZbZcZZZZiZZZZbZcgZZͺZZZZZZZZZZZgZZZZZZZú|ZZZeZZZZZZZZZZZZZZZZYYYYYYYYY]YYvYY]YY]ZYYYY]YYYYtcYYYYYYY|bYYZfYYYYYYYY{ͤZYYYZYZYYYpZYYwZZZZZZZp|ZZ}ZZZbZZgZZZZeZZwZZZeZZZ_ZZt{ZZZZvZZZZZZ_ZZZZZzuZZZZZbZZgZZjZZZZZZvZZeZbZZ_ZZZZZZZZZYYYtjYYYcbYYYZYYYbkYYYYYYbYYYYYwYY~YY]nYYYYuYYwYY_kYYYYYYYYYbvYYYYYYYYYYYsYYY_YYYZzbYYYY_ZgZZ}ZZcZjjZZ_ZZgZbtZZZZZZZZZZbujZZZZZZZZZZ_ZZknZZb_ZZ|ZZbZZbZZ_ZZZZsZZeZngZZcZZgZbtZZZZZZκpZZZcjZ__ZjZZ}ZZ_ZZZZZZZZiZ_YYYYYnYYYYYYYYbYYYYYYYYYZYYYY~YYnYYcYYԀYYYYYYYZZYYzYYYYYYY]YYbYY|pYYYYYYYYYYY_YYYYYYYYbZZeZebZuZZZZZZZiwZZ_ZZZZZZ_ZZmZZZZZZZZwZZiZ|ZZZZbZZZZZZZbZZZZZZZZbZZZZZsZZZZZZ_eZZZZmZZZZZZZnwZZ_ZZZZZZ_ZZZZZZZZpZZZZvZZZZsZZZZZZ_eZZeZepZZZZwZYYZiYYYYfjYYYY]tpYYYYYsYYYY_]YYYYzYYZZYYYY~YYYY䴅snYYYZ]YYYYfZZZZZZmZZZj_ZiwZZZczZZZZsԪ{_ZmZZۖkZŹbZZZez_ZZZc_Zg_ZZZjZmZZgZZZk_ZiwZZZcnZZZZiZbZZZZZZ_ZZZjZmZZZZpZZ˽YYsYYYϾZZZZjZ|ZZZZZZssssssssssssssYYrrYYrZZeebZZZZggggggggggggZZZZZbwYYYYYYYYYYYYYYkYYYYZYYYZZZZe{ZZmmZwZZZZZZZZZZZZZjZ_ZZZZ昊YYYZYYYfgYYY{pZZpZZZZniZZZcZZZZzpZZZ_YYbcYYYYYYYYYwc_zZZZZZZZ__c_zҙfYYYYYrӵľ"
  },
  {
    "path": "libpng/test_apps/main/test_libpng.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <string.h>\n#include \"unity.h\"\n#include \"png.h\"\n\nextern const uint8_t in_png_start[] asm(\"_binary_in_png_start\");\nextern const uint8_t in_png_end[]   asm(\"_binary_in_png_end\");\n\nextern const uint8_t out_pgm_start[] asm(\"_binary_out_pgm_start\");\nextern const uint8_t out_pgm_end[]   asm(\"_binary_out_pgm_end\");\n\nTEST_CASE(\"load a png image\", \"[libpng]\")\n{\n    png_image image;\n    memset(&image, 0, (sizeof image));\n    image.version = PNG_IMAGE_VERSION;\n\n    const uint8_t *buf = &in_png_start[0];\n    const size_t buf_len = in_png_end - in_png_start;\n\n    const size_t expected_width = 522;\n    const size_t expected_height = 52;\n\n    TEST_ASSERT(png_image_begin_read_from_memory(&image, buf, buf_len));\n\n    image.format = PNG_FORMAT_GRAY;\n    int stride = PNG_IMAGE_ROW_STRIDE(image);\n    int buf_size = PNG_IMAGE_SIZE(image);\n\n    TEST_ASSERT_EQUAL(expected_width, image.width);\n    TEST_ASSERT_EQUAL(expected_height, image.height);\n\n    png_bytep buffer = malloc(buf_size);\n    TEST_ASSERT_NOT_NULL(buffer);\n\n    TEST_ASSERT(png_image_finish_read(&image, NULL, buffer, stride, NULL));\n\n    FILE *expected = fmemopen((void *)out_pgm_start, out_pgm_end - out_pgm_start, \"r\");\n    TEST_ASSERT_NOT_NULL(expected);\n    // skip the header\n    fscanf(expected, \"P5\\n%*d %*d\\n%*d\\n\");\n    // check the binary data\n    for (int i = 0; i < buf_size; i++) {\n        uint8_t expected_byte;\n        TEST_ASSERT_EQUAL(1, fread(&expected_byte, 1, 1, expected));\n        TEST_ASSERT_EQUAL(expected_byte, buffer[i]);\n    }\n    fclose(expected);\n\n    free(buffer);\n}"
  },
  {
    "path": "libpng/test_apps/main/test_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"unity.h\"\n#include \"unity_test_runner.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_newlib.h\"\n#include \"unity_test_utils_memory.h\"\n\nvoid setUp(void)\n{\n    unity_utils_record_free_mem();\n}\n\nvoid tearDown(void)\n{\n    esp_reent_cleanup();    //clean up some of the newlib's lazy allocations\n    unity_utils_evaluate_leaks_direct(0);\n}\n\nvoid app_main(void)\n{\n    printf(\"Running libpng component tests\\n\");\n    unity_run_menu();\n}\n"
  },
  {
    "path": "libpng/test_apps/pytest_libpng.py",
    "content": "import pytest\n\n\n@pytest.mark.generic\ndef test_libpng(dut) -> None:\n    dut.run_all_single_board_cases()\n"
  },
  {
    "path": "libpng/test_apps/sdkconfig.defaults",
    "content": "# This file was generated using idf.py save-defconfig. It can be edited manually.\n# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration\n#\nCONFIG_ESP_TASK_WDT_INIT=n\n"
  },
  {
    "path": "libsodium/.build-test-rules.yml",
    "content": "libsodium/test_apps:\n  enable:\n    - if: IDF_TARGET in [\"esp32\", \"esp32c3\"]\n      reason: \"Sufficient to test on one Xtensa and one RISC-V target\"\n"
  },
  {
    "path": "libsodium/CMakeLists.txt",
    "content": "set(SRC libsodium/src/libsodium)\n# Derived from libsodium/src/libsodium/Makefile.am\n# (ignoring the !MINIMAL set)\nset(srcs\n    \"${SRC}/crypto_aead/chacha20poly1305/aead_chacha20poly1305.c\"\n    \"${SRC}/crypto_aead/xchacha20poly1305/aead_xchacha20poly1305.c\"\n    \"${SRC}/crypto_aead/aegis256/aead_aegis256.c\"\n    \"${SRC}/crypto_aead/aegis256/aegis256_soft.c\"\n    \"${SRC}/crypto_aead/aegis128l/aead_aegis128l.c\"\n    \"${SRC}/crypto_aead/aegis128l/aegis128l_soft.c\"\n    \"${SRC}/crypto_auth/crypto_auth.c\"\n    \"${SRC}/crypto_auth/hmacsha256/auth_hmacsha256.c\"\n    \"${SRC}/crypto_auth/hmacsha512/auth_hmacsha512.c\"\n    \"${SRC}/crypto_auth/hmacsha512256/auth_hmacsha512256.c\"\n    \"${SRC}/crypto_box/crypto_box.c\"\n    \"${SRC}/crypto_box/crypto_box_easy.c\"\n    \"${SRC}/crypto_box/crypto_box_seal.c\"\n    \"${SRC}/crypto_box/curve25519xchacha20poly1305/box_curve25519xchacha20poly1305.c\"\n    \"${SRC}/crypto_box/curve25519xchacha20poly1305/box_seal_curve25519xchacha20poly1305.c\"\n    \"${SRC}/crypto_box/curve25519xsalsa20poly1305/box_curve25519xsalsa20poly1305.c\"\n    \"${SRC}/crypto_core/ed25519/core_ed25519.c\"\n    \"${SRC}/crypto_core/ed25519/core_ristretto255.c\"\n    \"${SRC}/crypto_core/ed25519/ref10/ed25519_ref10.c\"\n    \"${SRC}/crypto_core/hchacha20/core_hchacha20.c\"\n    \"${SRC}/crypto_core/hsalsa20/core_hsalsa20.c\"\n    \"${SRC}/crypto_core/hsalsa20/ref2/core_hsalsa20_ref2.c\"\n    \"${SRC}/crypto_core/keccak1600/keccak1600.c\"\n    \"${SRC}/crypto_core/keccak1600/ref/keccak1600_ref.c\"\n    \"${SRC}/crypto_core/salsa/ref/core_salsa_ref.c\"\n    \"${SRC}/crypto_core/softaes/softaes.c\"\n    \"${SRC}/crypto_generichash/blake2b/generichash_blake2.c\"\n    \"${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-avx2.c\"\n    \"${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-ref.c\"\n    \"${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-ssse3.c\"\n    \"${SRC}/crypto_generichash/blake2b/ref/blake2b-ref.c\"\n    \"${SRC}/crypto_generichash/blake2b/ref/generichash_blake2b.c\"\n    \"${SRC}/crypto_generichash/crypto_generichash.c\"\n    \"${SRC}/crypto_ipcrypt/crypto_ipcrypt.c\"\n    \"${SRC}/crypto_ipcrypt/ipcrypt_soft.c\"\n    \"${SRC}/crypto_hash/crypto_hash.c\"\n    \"${SRC}/crypto_hash/sha256/hash_sha256.c\"\n    \"${SRC}/crypto_hash/sha512/hash_sha512.c\"\n    \"${SRC}/crypto_kdf/blake2b/kdf_blake2b.c\"\n    \"${SRC}/crypto_kdf/crypto_kdf.c\"\n    \"${SRC}/crypto_kdf/hkdf/kdf_hkdf_sha256.c\"\n    \"${SRC}/crypto_kdf/hkdf/kdf_hkdf_sha512.c\"\n    \"${SRC}/crypto_kx/crypto_kx.c\"\n    \"${SRC}/crypto_onetimeauth/crypto_onetimeauth.c\"\n    \"${SRC}/crypto_onetimeauth/poly1305/donna/poly1305_donna.c\"\n    \"${SRC}/crypto_onetimeauth/poly1305/onetimeauth_poly1305.c\"\n    \"${SRC}/crypto_pwhash/argon2/argon2-core.c\"\n    \"${SRC}/crypto_pwhash/argon2/argon2-encoding.c\"\n    \"${SRC}/crypto_pwhash/argon2/argon2-fill-block-avx2.c\"\n    \"${SRC}/crypto_pwhash/argon2/argon2-fill-block-avx512f.c\"\n    \"${SRC}/crypto_pwhash/argon2/argon2-fill-block-ref.c\"\n    \"${SRC}/crypto_pwhash/argon2/argon2-fill-block-ssse3.c\"\n    \"${SRC}/crypto_pwhash/argon2/argon2.c\"\n    \"${SRC}/crypto_pwhash/argon2/blake2b-long.c\"\n    \"${SRC}/crypto_pwhash/argon2/pwhash_argon2i.c\"\n    \"${SRC}/crypto_pwhash/argon2/pwhash_argon2id.c\"\n    \"${SRC}/crypto_pwhash/crypto_pwhash.c\"\n    \"${SRC}/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt-common.c\"\n    \"${SRC}/crypto_pwhash/scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c\"\n    \"${SRC}/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.c\"\n    \"${SRC}/crypto_pwhash/scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c\"\n    \"${SRC}/crypto_pwhash/scryptsalsa208sha256/scrypt_platform.c\"\n    \"${SRC}/crypto_scalarmult/crypto_scalarmult.c\"\n    \"${SRC}/crypto_scalarmult/curve25519/ref10/x25519_ref10.c\"\n    \"${SRC}/crypto_scalarmult/curve25519/sandy2x/consts.S\"\n    \"${SRC}/crypto_scalarmult/curve25519/sandy2x/curve25519_sandy2x.c\"\n    \"${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_invert.c\"\n    \"${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_mul.S\"\n    \"${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_nsquare.S\"\n    \"${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_pack.S\"\n    \"${SRC}/crypto_scalarmult/curve25519/sandy2x/fe_frombytes_sandy2x.c\"\n    \"${SRC}/crypto_scalarmult/curve25519/sandy2x/ladder.S\"\n    \"${SRC}/crypto_scalarmult/curve25519/sandy2x/sandy2x.S\"\n    \"${SRC}/crypto_scalarmult/curve25519/scalarmult_curve25519.c\"\n    \"${SRC}/crypto_scalarmult/ed25519/ref10/scalarmult_ed25519_ref10.c\"\n    \"${SRC}/crypto_scalarmult/ristretto255/ref10/scalarmult_ristretto255_ref10.c\"\n    \"${SRC}/crypto_secretbox/crypto_secretbox.c\"\n    \"${SRC}/crypto_secretbox/crypto_secretbox_easy.c\"\n    \"${SRC}/crypto_secretbox/xchacha20poly1305/secretbox_xchacha20poly1305.c\"\n    \"${SRC}/crypto_secretbox/xsalsa20poly1305/secretbox_xsalsa20poly1305.c\"\n    \"${SRC}/crypto_secretstream/xchacha20poly1305/secretstream_xchacha20poly1305.c\"\n    \"${SRC}/crypto_shorthash/crypto_shorthash.c\"\n    \"${SRC}/crypto_shorthash/siphash24/ref/shorthash_siphash24_ref.c\"\n    \"${SRC}/crypto_shorthash/siphash24/ref/shorthash_siphashx24_ref.c\"\n    \"${SRC}/crypto_shorthash/siphash24/shorthash_siphash24.c\"\n    \"${SRC}/crypto_shorthash/siphash24/shorthash_siphashx24.c\"\n    \"${SRC}/crypto_sign/crypto_sign.c\"\n    \"${SRC}/crypto_sign/ed25519/ref10/keypair.c\"\n    \"${SRC}/crypto_sign/ed25519/ref10/obsolete.c\"\n    \"${SRC}/crypto_sign/ed25519/ref10/open.c\"\n    \"${SRC}/crypto_sign/ed25519/ref10/sign.c\"\n    \"${SRC}/crypto_sign/ed25519/sign_ed25519.c\"\n    \"${SRC}/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-avx2.c\"\n    \"${SRC}/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-ssse3.c\"\n    \"${SRC}/crypto_stream/chacha20/ref/chacha20_ref.c\"\n    \"${SRC}/crypto_stream/chacha20/stream_chacha20.c\"\n    \"${SRC}/crypto_stream/crypto_stream.c\"\n    \"${SRC}/crypto_stream/salsa20/ref/salsa20_ref.c\"\n    \"${SRC}/crypto_stream/salsa20/stream_salsa20.c\"\n    \"${SRC}/crypto_stream/salsa20/xmm6/salsa20_xmm6-asm.S\"\n    \"${SRC}/crypto_stream/salsa20/xmm6/salsa20_xmm6.c\"\n    \"${SRC}/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-avx2.c\"\n    \"${SRC}/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-sse2.c\"\n    \"${SRC}/crypto_stream/salsa2012/ref/stream_salsa2012_ref.c\"\n    \"${SRC}/crypto_stream/salsa2012/stream_salsa2012.c\"\n    \"${SRC}/crypto_stream/salsa208/ref/stream_salsa208_ref.c\"\n    \"${SRC}/crypto_stream/salsa208/stream_salsa208.c\"\n    \"${SRC}/crypto_stream/xchacha20/stream_xchacha20.c\"\n    \"${SRC}/crypto_stream/xsalsa20/stream_xsalsa20.c\"\n    \"${SRC}/crypto_verify/verify.c\"\n    \"${SRC}/crypto_xof/shake128/xof_shake128.c\"\n    \"${SRC}/crypto_xof/shake128/ref/shake128_ref.c\"\n    \"${SRC}/crypto_xof/shake256/xof_shake256.c\"\n    \"${SRC}/crypto_xof/shake256/ref/shake256_ref.c\"\n    \"${SRC}/crypto_xof/turboshake128/xof_turboshake128.c\"\n    \"${SRC}/crypto_xof/turboshake128/ref/turboshake128_ref.c\"\n    \"${SRC}/crypto_xof/turboshake256/xof_turboshake256.c\"\n    \"${SRC}/crypto_xof/turboshake256/ref/turboshake256_ref.c\"\n    \"${SRC}/randombytes/randombytes.c\"\n    \"${SRC}/sodium/codecs.c\"\n    \"${SRC}/sodium/core.c\"\n    \"${SRC}/sodium/runtime.c\"\n    \"${SRC}/sodium/utils.c\"\n    \"${SRC}/sodium/version.c\"\n    \"port/randombytes_esp32.c\")\n\nif(CONFIG_LIBSODIUM_USE_MBEDTLS_SHA)\n    list(APPEND srcs\n        \"port/crypto_hash_mbedtls/crypto_hash_sha256_mbedtls.c\"\n        \"port/crypto_hash_mbedtls/crypto_hash_sha512_mbedtls.c\")\n    set(include_dirs port_include ${SRC}/include)\n    set(priv_include_dirs port port_include/sodium ${SRC}/include/sodium)\nelse()\n    list(APPEND srcs\n        \"${SRC}/crypto_hash/sha256/cp/hash_sha256_cp.c\"\n        \"${SRC}/crypto_hash/sha512/cp/hash_sha512_cp.c\")\n    set(include_dirs ${SRC}/include port_include)\n    set(priv_include_dirs ${SRC}/include/sodium port_include/sodium port)\nendif()\n\nidf_component_register(SRCS \"${srcs}\"\n                    INCLUDE_DIRS \"${include_dirs}\"\n                    PRIV_INCLUDE_DIRS \"${priv_include_dirs}\"\n                    REQUIRES mbedtls)\n\ntarget_compile_definitions(${COMPONENT_LIB} PRIVATE\n    CONFIGURED\n    NATIVE_LITTLE_ENDIAN\n    HAVE_WEAK_SYMBOLS\n    __STDC_LIMIT_MACROS\n    __STDC_CONSTANT_MACROS\n    )\n\n# patch around warnings in third-party files\nset_source_files_properties(\n    ${SRC}/crypto_pwhash/argon2/pwhash_argon2i.c\n    ${SRC}/crypto_pwhash/argon2/pwhash_argon2id.c\n    ${SRC}/crypto_pwhash/argon2/argon2-core.c\n    ${SRC}/crypto_pwhash/scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c\n    PROPERTIES COMPILE_FLAGS\n    -Wno-type-limits\n    )\nset_source_files_properties(\n    ${SRC}/sodium/utils.c\n    PROPERTIES COMPILE_FLAGS\n    -Wno-unused-variable\n    )\nset_source_files_properties(\n    ${SRC}/crypto_pwhash/argon2/argon2-fill-block-ref.c\n    PROPERTIES COMPILE_FLAGS\n    -Wno-unknown-pragmas\n    )\n\n# Temporary suppress \"fallthrough\" warnings until they are fixed in libsodium repo\nset_source_files_properties(\n    ${SRC}/crypto_shorthash/siphash24/ref/shorthash_siphashx24_ref.c\n    ${SRC}/crypto_shorthash/siphash24/ref/shorthash_siphash24_ref.c\n    PROPERTIES COMPILE_FLAGS\n    -Wno-implicit-fallthrough\n    )\n\nset_source_files_properties(\n    ${SRC}/randombytes/randombytes.c\n    PROPERTIES COMPILE_FLAGS\n    -DRANDOMBYTES_DEFAULT_IMPLEMENTATION\n)\n\ntarget_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-function)\n\nif(CONFIG_LIBSODIUM_USE_MBEDTLS_SHA)\n    target_compile_options(${COMPONENT_LIB} PRIVATE\n        \"$<$<COMPILE_LANGUAGE:C>:SHELL:-include ${CMAKE_CURRENT_SOURCE_DIR}/port_include/sodium/crypto_hash_sha256.h>\"\n        \"$<$<COMPILE_LANGUAGE:C>:SHELL:-include ${CMAKE_CURRENT_SOURCE_DIR}/port_include/sodium/crypto_hash_sha512.h>\")\nendif()\n\nif(CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE)\n    # some libsodium variables are only used for asserts\n    target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-but-set-variable)\nendif()\n\nif(CONFIG_COMPILER_STATIC_ANALYZER AND CMAKE_C_COMPILER_ID STREQUAL \"GNU\")\n    # GCC's -fanalyzer causes the compiler to hang on libsodium's elliptic curve code\n    # due to combinatorial state explosion in the interprocedural analysis\n    target_compile_options(${COMPONENT_LIB} PRIVATE \"-fno-analyzer\")\nendif()\n"
  },
  {
    "path": "libsodium/Kconfig",
    "content": "menu \"libsodium\"\n\n    config LIBSODIUM_USE_MBEDTLS_SHA\n        bool \"Use mbedTLS SHA256 & SHA512 implementations\"\n        default y\n        help\n            If this option is enabled, libsodium will use thin wrappers\n            around mbedTLS for SHA256 & SHA512 operations.\n            This saves some code size if mbedTLS is also used.\nendmenu # libsodium\n"
  },
  {
    "path": "libsodium/idf_component.yml",
    "content": "version: \"1.0.21\"\ndescription: libsodium port to ESP\nurl: https://github.com/espressif/idf-extra-components/tree/master/libsodium\ndependencies:\n  idf: \">=4.2\"\nsbom:\n  manifests:\n    - path: sbom_libsodium.yml\n      dest: libsodium\n"
  },
  {
    "path": "libsodium/port/crypto_hash_mbedtls/crypto_hash_sha256_mbedtls.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2017-2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <mbedtls/version.h>\n\n/* Keep forward-compatibility with Mbed TLS 3.x */\n#if (MBEDTLS_VERSION_NUMBER < 0x03000000)\n#define MBEDTLS_2_X_COMPAT\n#else /* !(MBEDTLS_VERSION_NUMBER < 0x03000000) */\n/* Macro wrapper for struct's private members */\n#ifndef MBEDTLS_ALLOW_PRIVATE_ACCESS\n#define MBEDTLS_ALLOW_PRIVATE_ACCESS\n#endif /* MBEDTLS_ALLOW_PRIVATE_ACCESS */\n#endif /* !(MBEDTLS_VERSION_NUMBER < 0x03000000) */\n\n/* For MbedTLS 4.x support using PSA Crypto */\n#if (MBEDTLS_VERSION_NUMBER >= 0x04000000)\n#define MBEDTLS_PSA_CRYPTO\n#endif\n\n#include \"crypto_hash_sha256.h\"\n#include <string.h>\n\nint\ncrypto_hash_sha256_init(crypto_hash_sha256_state *state)\n{\n#ifdef MBEDTLS_PSA_CRYPTO\n    psa_status_t status;\n\n    status = psa_crypto_init();\n    if (status != PSA_SUCCESS) {\n        return -1;\n    }\n\n    state->_psa_op = psa_hash_operation_init();\n\n    status = psa_hash_setup(&state->_psa_op, PSA_ALG_SHA_256);\n    if (status != PSA_SUCCESS) {\n        return -1;\n    }\n    return 0;\n#else\n    mbedtls_sha256_init(&state->ctx);\n#ifdef MBEDTLS_2_X_COMPAT\n    int ret = mbedtls_sha256_starts_ret(&state->ctx, 0);\n#else\n    int ret = mbedtls_sha256_starts(&state->ctx, 0);\n#endif /* MBEDTLS_2_X_COMPAT */\n    if (ret != 0) {\n        return ret;\n    }\n    return 0;\n#endif /* !MBEDTLS_PSA_CRYPTO */\n}\n\nint\ncrypto_hash_sha256_update(crypto_hash_sha256_state *state,\n                          const unsigned char *in, unsigned long long inlen)\n{\n    if (in == NULL && inlen > 0) {\n        return -1;\n    }\n#ifdef MBEDTLS_PSA_CRYPTO\n    psa_status_t status;\n\n    status = psa_hash_update(&state->_psa_op, in, inlen);\n    if (status != PSA_SUCCESS) {\n        psa_hash_abort(&state->_psa_op);\n        return -1;\n    }\n    return 0;\n#else\n#ifdef MBEDTLS_2_X_COMPAT\n    int ret = mbedtls_sha256_update_ret(&state->ctx, in, inlen);\n#else\n    int ret = mbedtls_sha256_update(&state->ctx, in, inlen);\n#endif /* MBEDTLS_2_X_COMPAT */\n    if (ret != 0) {\n        return ret;\n    }\n    return 0;\n#endif /* !MBEDTLS_PSA_CRYPTO */\n}\n\nint\ncrypto_hash_sha256_final(crypto_hash_sha256_state *state, unsigned char *out)\n{\n#ifdef MBEDTLS_PSA_CRYPTO\n    psa_status_t status;\n    size_t hash_len;\n\n    status = psa_hash_finish(&state->_psa_op, out, crypto_hash_sha256_BYTES, &hash_len);\n    if (status != PSA_SUCCESS || hash_len != crypto_hash_sha256_BYTES) {\n        psa_hash_abort(&state->_psa_op);\n        return -1;\n    }\n    return 0;\n#else\n#ifdef MBEDTLS_2_X_COMPAT\n    return mbedtls_sha256_finish_ret(&state->ctx, out);\n#else\n    return mbedtls_sha256_finish(&state->ctx, out);\n#endif /* MBEDTLS_2_X_COMPAT */\n#endif /* !MBEDTLS_PSA_CRYPTO */\n}\n\nint\ncrypto_hash_sha256(unsigned char *out, const unsigned char *in,\n                   unsigned long long inlen)\n{\n    if (in == NULL && inlen > 0) {\n        return -1;\n    }\n#ifdef MBEDTLS_PSA_CRYPTO\n    psa_status_t status;\n    size_t hash_len;\n\n    status = psa_hash_compute(PSA_ALG_SHA_256, in, inlen, out,\n                              crypto_hash_sha256_BYTES, &hash_len);\n    if (status != PSA_SUCCESS || hash_len != crypto_hash_sha256_BYTES) {\n        return -1;\n    }\n    return 0;\n#else\n#ifdef MBEDTLS_2_X_COMPAT\n    return mbedtls_sha256_ret(in, inlen, out, 0);\n#else\n    return mbedtls_sha256(in, inlen, out, 0);\n#endif /* MBEDTLS_2_X_COMPAT */\n#endif /* !MBEDTLS_PSA_CRYPTO */\n}\n"
  },
  {
    "path": "libsodium/port/crypto_hash_mbedtls/crypto_hash_sha512_mbedtls.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2017-2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <mbedtls/version.h>\n\n/* Keep forward-compatibility with Mbed TLS 3.x */\n#if (MBEDTLS_VERSION_NUMBER < 0x03000000)\n#define MBEDTLS_2_X_COMPAT\n#else /* !(MBEDTLS_VERSION_NUMBER < 0x03000000) */\n/* Macro wrapper for struct's private members */\n#ifndef MBEDTLS_ALLOW_PRIVATE_ACCESS\n#define MBEDTLS_ALLOW_PRIVATE_ACCESS\n#endif /* MBEDTLS_ALLOW_PRIVATE_ACCESS */\n#endif /* !(MBEDTLS_VERSION_NUMBER < 0x03000000) */\n\n/* For MbedTLS 4.x support using PSA crypto */\n#if (MBEDTLS_VERSION_NUMBER >= 0x04000000)\n#define MBEDTLS_PSA_CRYPTO\n#endif\n\n#include \"crypto_hash_sha512.h\"\n#include <string.h>\n\nint\ncrypto_hash_sha512_init(crypto_hash_sha512_state *state)\n{\n#ifdef MBEDTLS_PSA_CRYPTO\n    psa_status_t status;\n\n    status = psa_crypto_init();\n    if (status != PSA_SUCCESS) {\n        return -1;\n    }\n\n    state->_psa_op = psa_hash_operation_init();\n\n    status = psa_hash_setup(&state->_psa_op, PSA_ALG_SHA_512);\n    if (status != PSA_SUCCESS) {\n        return -1;\n    }\n    return 0;\n#else\n    mbedtls_sha512_init(&state->ctx);\n#ifdef MBEDTLS_2_X_COMPAT\n    int ret = mbedtls_sha512_starts_ret(&state->ctx, 0);\n#else\n    int ret = mbedtls_sha512_starts(&state->ctx, 0);\n#endif /* MBEDTLS_2_X_COMPAT */\n    if (ret != 0) {\n        return ret;\n    }\n    return 0;\n#endif /* !MBEDTLS_PSA_CRYPTO */\n}\n\nint\ncrypto_hash_sha512_update(crypto_hash_sha512_state *state,\n                          const unsigned char *in, unsigned long long inlen)\n{\n    if (inlen > 0 && in == NULL) {\n        return -1;\n    }\n#ifdef MBEDTLS_PSA_CRYPTO\n    psa_status_t status;\n\n    status = psa_hash_update(&state->_psa_op, in, inlen);\n    if (status != PSA_SUCCESS) {\n        psa_hash_abort(&state->_psa_op);\n        return -1;\n    }\n    return 0;\n#else\n#ifdef MBEDTLS_2_X_COMPAT\n    int ret = mbedtls_sha512_update_ret(&state->ctx, in, inlen);\n#else\n    int ret = mbedtls_sha512_update(&state->ctx, in, inlen);\n#endif /* MBEDTLS_2_X_COMPAT */\n    if (ret != 0) {\n        return ret;\n    }\n    return 0;\n#endif /* !MBEDTLS_PSA_CRYPTO */\n}\n\nint\ncrypto_hash_sha512_final(crypto_hash_sha512_state *state, unsigned char *out)\n{\n#ifdef MBEDTLS_PSA_CRYPTO\n    psa_status_t status;\n    size_t hash_len;\n\n    status = psa_hash_finish(&state->_psa_op, out, crypto_hash_sha512_BYTES, &hash_len);\n    if (status != PSA_SUCCESS || hash_len != crypto_hash_sha512_BYTES) {\n        psa_hash_abort(&state->_psa_op);\n        return -1;\n    }\n    return 0;\n#else\n#ifdef MBEDTLS_2_X_COMPAT\n    return mbedtls_sha512_finish_ret(&state->ctx, out);\n#else\n    return mbedtls_sha512_finish(&state->ctx, out);\n#endif /* MBEDTLS_2_X_COMPAT */\n#endif /* !MBEDTLS_PSA_CRYPTO */\n}\n\nint\ncrypto_hash_sha512(unsigned char *out, const unsigned char *in,\n                   unsigned long long inlen)\n{\n    if (inlen > 0 && in == NULL) {\n        return -1;\n    }\n#ifdef MBEDTLS_PSA_CRYPTO\n    psa_status_t status;\n    size_t hash_len;\n\n    status = psa_hash_compute(PSA_ALG_SHA_512, in, inlen, out,\n                              crypto_hash_sha512_BYTES, &hash_len);\n    if (status != PSA_SUCCESS || hash_len != crypto_hash_sha512_BYTES) {\n        return -1;\n    }\n    return 0;\n#else\n#ifdef MBEDTLS_2_X_COMPAT\n    return mbedtls_sha512_ret(in, inlen, out, 0);\n#else\n    return mbedtls_sha512(in, inlen, out, 0);\n#endif /* MBEDTLS_2_X_COMPAT */\n#endif /* !MBEDTLS_PSA_CRYPTO */\n}\n"
  },
  {
    "path": "libsodium/port/randombytes_esp32.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include \"sdkconfig.h\"\n#if __has_include(\"esp_random.h\")\n#include \"esp_random.h\"\n#else\n#include \"esp_system.h\"\n#endif\n#include \"randombytes_internal.h\"\n\nstatic const char *randombytes_esp32xx_implementation_name(void)\n{\n    return CONFIG_IDF_TARGET;\n}\n\n/*\n  Plug the ESP32 hardware RNG into libsodium's custom RNG support, as per\n  https://download.libsodium.org/doc/advanced/custom_rng.html\n\n  Note that this RNG is selected by default (see randombytes_default.h), so there\n  is no need to call randombytes_set_implementation().\n*/\nconst struct randombytes_implementation randombytes_esp32_implementation = {\n    .implementation_name = randombytes_esp32xx_implementation_name,\n    .random = esp_random,\n    .stir = NULL,\n    .uniform = NULL,\n    .buf = esp_fill_random,\n    .close = NULL,\n};\n"
  },
  {
    "path": "libsodium/port/randombytes_internal.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n# include \"export.h\"\n# include \"randombytes.h\"\n\nSODIUM_EXPORT\nextern const struct randombytes_implementation randombytes_esp32_implementation;\n\n/* Defining RANDOMBYTES_DEFAULT_IMPLEMENTATION here allows us to compile with the ESP32 hardware\n   implementation as the default. No need to call randombytes_set_implementation().\n\n   Doing it in the header like this is easier than passing it via a -D argument to gcc.\n*/\n#undef RANDOMBYTES_DEFAULT_IMPLEMENTATION\n#define RANDOMBYTES_DEFAULT_IMPLEMENTATION &randombytes_esp32_implementation\n"
  },
  {
    "path": "libsodium/port_include/sodium/crypto_hash_sha256.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#ifndef crypto_hash_sha256_H\n#define crypto_hash_sha256_H\n\n#include <mbedtls/version.h>\n#include <sodium/export.h>\n\n/* For MbedTLS 4.x support using PSA Crypto */\n#if (MBEDTLS_VERSION_NUMBER >= 0x04000000)\n#define MBEDTLS_PSA_CRYPTO\n#endif\n\n#ifdef MBEDTLS_PSA_CRYPTO\n#include \"psa/crypto.h\"\n#else\n#include \"mbedtls/sha256.h\"\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct crypto_hash_sha256_state {\n#ifdef MBEDTLS_PSA_CRYPTO\n    psa_hash_operation_t _psa_op;\n#else\n    mbedtls_sha256_context ctx;\n#endif /* MBEDTLS_PSA_CRYPTO */\n} crypto_hash_sha256_state;\n\nSODIUM_EXPORT\nsize_t crypto_hash_sha256_statebytes(void);\n\n#define crypto_hash_sha256_BYTES 32U\nSODIUM_EXPORT\nsize_t crypto_hash_sha256_bytes(void);\n\nSODIUM_EXPORT\nint crypto_hash_sha256(unsigned char *out, const unsigned char *in,\n                       unsigned long long inlen) __attribute__ ((nonnull(1)));\n\nSODIUM_EXPORT\nint crypto_hash_sha256_init(crypto_hash_sha256_state *state)\n__attribute__ ((nonnull));\n\nSODIUM_EXPORT\nint crypto_hash_sha256_update(crypto_hash_sha256_state *state,\n                              const unsigned char *in,\n                              unsigned long long inlen)\n__attribute__ ((nonnull(1)));\n\nSODIUM_EXPORT\nint crypto_hash_sha256_final(crypto_hash_sha256_state *state,\n                             unsigned char *out)\n__attribute__ ((nonnull));\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* crypto_hash_sha256_H */"
  },
  {
    "path": "libsodium/port_include/sodium/crypto_hash_sha512.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#ifndef crypto_hash_sha512_H\n#define crypto_hash_sha512_H\n\n#include <mbedtls/version.h>\n#include <sodium/export.h>\n\n/* For MbedTLS 4.x support using PSA Crypto */\n#if (MBEDTLS_VERSION_NUMBER >= 0x04000000)\n#define MBEDTLS_PSA_CRYPTO\n#endif\n\n#ifdef MBEDTLS_PSA_CRYPTO\n#include \"psa/crypto.h\"\n#else\n#include \"mbedtls/sha512.h\"\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct crypto_hash_sha512_state {\n#ifdef MBEDTLS_PSA_CRYPTO\n    psa_hash_operation_t _psa_op;\n#else\n    mbedtls_sha512_context ctx;\n#endif /* MBEDTLS_PSA_CRYPTO */\n} crypto_hash_sha512_state;\n\nSODIUM_EXPORT\nsize_t crypto_hash_sha512_statebytes(void);\n\n#define crypto_hash_sha512_BYTES 64U\nSODIUM_EXPORT\nsize_t crypto_hash_sha512_bytes(void);\n\nSODIUM_EXPORT\nint crypto_hash_sha512(unsigned char *out, const unsigned char *in,\n                       unsigned long long inlen) __attribute__ ((nonnull(1)));\n\nSODIUM_EXPORT\nint crypto_hash_sha512_init(crypto_hash_sha512_state *state)\n__attribute__ ((nonnull));\n\nSODIUM_EXPORT\nint crypto_hash_sha512_update(crypto_hash_sha512_state *state,\n                              const unsigned char *in,\n                              unsigned long long inlen)\n__attribute__ ((nonnull(1)));\n\nSODIUM_EXPORT\nint crypto_hash_sha512_final(crypto_hash_sha512_state *state,\n                             unsigned char *out)\n__attribute__ ((nonnull));\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* crypto_hash_sha512_H */"
  },
  {
    "path": "libsodium/port_include/sodium/version.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#ifndef sodium_version_H\n#define sodium_version_H\n\n#include <sodium/export.h>\n\n/* IMPORTANT: As we don't use autotools, these version are not automatically\n   updated if we change submodules. They need to be changed manually.\n*/\n\n#define SODIUM_VERSION_STRING \"1.0.21\"\n\n/* Note: these are not the same as the overall version, see\n   configure.ac for the relevant macros */\n#define SODIUM_LIBRARY_VERSION_MAJOR 26\n#define SODIUM_LIBRARY_VERSION_MINOR 3\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nSODIUM_EXPORT\nconst char *sodium_version_string(void);\n\nSODIUM_EXPORT\nint         sodium_library_version_major(void);\n\nSODIUM_EXPORT\nint         sodium_library_version_minor(void);\n\nSODIUM_EXPORT\nint         sodium_library_minimal(void);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "libsodium/port_include/sodium.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#ifndef port_sodium_wrapper_H\n#define port_sodium_wrapper_H\n\n/* Pre-include port-specific hash state headers via angle brackets.\n* Angle brackets search -I paths directly, so port_include/sodium/\n* is found before the original. Once included, their guards are set,\n* so when the original sodium.h tries to include them via relative\n* double-quote paths, they are silently skipped. */\n#include <sodium/crypto_hash_sha256.h>\n#include <sodium/crypto_hash_sha512.h>\n\n/* Delegate to the original sodium.h. #include_next skips port_include/\n* and finds the next sodium.h in the search path. */\n#include_next \"sodium.h\"\n\n#endif /* port_sodium_wrapper_H */\n"
  },
  {
    "path": "libsodium/sbom_libsodium.yml",
    "content": "name: libsodium\nversion: \"1.0.21\"\ncpe: cpe:2.3:a:jedisct1:libsodium:{}:*:*:*:*:*:*:*\nsupplier: 'Person: Frank Denis (jedisct1)'\ndescription: A modern, portable, easy to use crypto library\nurl: https://github.com/jedisct1/libsodium\nhash: d24faf56214469b354b01c8ba36257e04737101e\ncve-exclude-list:\n  - cve: CVE-2025-69277\n    reason: Resolved in version 1.0.21 with commit f2da4cd8cb26\n"
  },
  {
    "path": "libsodium/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(libsodium_test)\n"
  },
  {
    "path": "libsodium/test_apps/main/CMakeLists.txt",
    "content": "get_filename_component(LS_TESTDIR \"${CMAKE_CURRENT_LIST_DIR}/../../libsodium/test/default\" ABSOLUTE)\n\nset(TEST_CASES \"aead_aegis128l;aead_aegis256;chacha20;aead_chacha20poly1305;box;box2;ed25519_convert;sign;hash\")\n\nforeach(test_case ${TEST_CASES})\n    file(GLOB test_case_file \"${LS_TESTDIR}/${test_case}.c\")\n    list(APPEND TEST_CASES_FILES ${test_case_file})\n    file(GLOB test_case_expected_output \"${LS_TESTDIR}/${test_case}.exp\")\n    list(APPEND TEST_CASES_EXP_FILES ${test_case_expected_output})\nendforeach()\n\nidf_component_register(SRCS \"${TEST_CASES_FILES}\" \"test_sodium.c\" \"test_main.c\"\n                    PRIV_INCLUDE_DIRS \".\" \"${LS_TESTDIR}/../quirks\"\n                    PRIV_REQUIRES unity\n                    EMBED_TXTFILES ${TEST_CASES_EXP_FILES}\n                    WHOLE_ARCHIVE)\n\n# The libsodium test suite is designed to be run each test case as an executable on a desktop computer and uses\n# filesystem to write & then compare contents of each file.\n#\n# For now, use their \"BROWSER_TEST\" mode with these hacks so that\n# multiple test cases can be combined into one ELF file.\n#\n# Run each test case from test_sodium.c as CASENAME_xmain().\nforeach(test_case_file ${TEST_CASES_FILES})\n    get_filename_component(test_case ${test_case_file} NAME_WE)\n    set_source_files_properties(${test_case_file}\n                                PROPERTIES COMPILE_FLAGS\n                                # This would generate 'warning \"main\" redefined' warnings at runtime, which are\n                                # silenced here. Only other solution involves patching libsodium's cmptest.h.\n                                \"-Dxmain=${test_case}_xmain -Dmain=${test_case}_main -Wp,-w\")\nendforeach()\n\n# this seems odd, but it prevents the libsodium test harness from\n# trying to write to a file!\nadd_definitions(-DBROWSER_TESTS)\n"
  },
  {
    "path": "libsodium/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/libsodium:\n    version: \"*\"\n    override_path: \"../..\"\n"
  },
  {
    "path": "libsodium/test_apps/main/test_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"unity.h\"\n#include \"unity_test_runner.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_newlib.h\"\n#include \"unity_test_utils_memory.h\"\n\nvoid setUp(void)\n{\n    unity_utils_record_free_mem();\n}\n\nvoid tearDown(void)\n{\n    esp_reent_cleanup();    //clean up some of the newlib's lazy allocations\n    unity_utils_evaluate_leaks_direct(0);\n}\n\nvoid app_main(void)\n{\n    printf(\"Running libsodium component tests\\n\");\n    unity_run_menu();\n}\n"
  },
  {
    "path": "libsodium/test_apps/main/test_sodium.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include <stdio.h>\n#include \"unity.h\"\n#include \"sodium/crypto_hash_sha256.h\"\n#include \"sodium/crypto_hash_sha512.h\"\n\n\n#ifdef CONFIG_LIBSODIUM_USE_MBEDTLS_SHA\n/*\n * Added these static assert checks to verify that the port headers are being included\n * and the state structs are the expected size. If these fail, it likely means that the\n * port headers are not included correctly\n */\n#ifdef MBEDTLS_PSA_CRYPTO\n_Static_assert(sizeof(crypto_hash_sha256_state) == sizeof(psa_hash_operation_t),\n               \"crypto_hash_sha256_state must wrap psa_hash_operation_t on PSA path\");\n_Static_assert(sizeof(crypto_hash_sha512_state) == sizeof(psa_hash_operation_t),\n               \"crypto_hash_sha512_state must wrap psa_hash_operation_t on PSA path\");\n#else\n_Static_assert(sizeof(crypto_hash_sha256_state) == sizeof(mbedtls_sha256_context),\n               \"crypto_hash_sha256_state must wrap mbedtls_sha256_context on MbedTLS path\");\n_Static_assert(sizeof(crypto_hash_sha512_state) == sizeof(mbedtls_sha512_context),\n               \"crypto_hash_sha512_state must wrap mbedtls_sha512_context on MbedTLS path\");\n#endif /* MBEDTLS_PSA_CRYPTO */\n#endif /* CONFIG_LIBSODIUM_USE_MBEDTLS_SHA */\n\n\n#define LIBSODIUM_TEST(name_) \\\n    extern int name_ ## _xmain(void);   \\\n    extern const uint8_t name_ ## _exp_start[] asm(\"_binary_\" #name_ \"_exp_start\"); \\\n    extern const uint8_t name_ ## _exp_end[]   asm(\"_binary_\" #name_ \"_exp_end\"); \\\n    TEST_CASE(\"\" #name_ \" test vectors\", \"[libsodium]\") { \\\n        printf(\"Running \" #name_ \"\\n\"); \\\n        FILE* old_stdout = stdout; \\\n        char* test_output; \\\n        size_t test_output_size; \\\n        FILE* test_output_stream = open_memstream(&test_output, &test_output_size); \\\n        stdout = test_output_stream; \\\n        TEST_ASSERT_EQUAL(0, name_ ## _xmain()); \\\n        fclose(test_output_stream); \\\n        stdout = old_stdout; \\\n        const char *expected = (const char*) &name_ ## _exp_start[0]; \\\n        TEST_ASSERT_EQUAL_STRING(expected, test_output); \\\n        free(test_output); \\\n    }\n\n\nLIBSODIUM_TEST(aead_aegis128l)\nLIBSODIUM_TEST(aead_aegis256)\nLIBSODIUM_TEST(aead_chacha20poly1305)\nLIBSODIUM_TEST(chacha20)\nLIBSODIUM_TEST(box)\nLIBSODIUM_TEST(box2)\nLIBSODIUM_TEST(ed25519_convert)\nLIBSODIUM_TEST(hash)\nLIBSODIUM_TEST(sign)\n\n\nTEST_CASE(\"sha256 sanity check\", \"[libsodium]\")\n{\n    const uint8_t expected[] = { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41,\n                                 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03,\n                                 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff,\n                                 0x61, 0xf2, 0x00, 0x15, 0xad,\n                               };\n    uint8_t calculated[32];\n    crypto_hash_sha256_state state;\n\n    const uint8_t *in = (const uint8_t *)\"abc\";\n    const size_t inlen = 3;\n\n    // One-liner version\n    crypto_hash_sha256(calculated, in, inlen);\n    TEST_ASSERT_EQUAL(sizeof(calculated), sizeof(expected));\n    TEST_ASSERT_EQUAL(sizeof(calculated), crypto_hash_sha256_bytes());\n    TEST_ASSERT_EQUAL_MEMORY(expected, calculated, crypto_hash_sha256_bytes());\n\n    // Multi-line version\n    crypto_hash_sha256_init(&state);\n    crypto_hash_sha256_update(&state, in, inlen - 1); // split into two updates\n    crypto_hash_sha256_update(&state, in + (inlen - 1), 1);\n    crypto_hash_sha256_final(&state, calculated);\n    TEST_ASSERT_EQUAL_MEMORY(expected, calculated, crypto_hash_sha256_bytes());\n}\n\nTEST_CASE(\"sha512 sanity check\", \"[libsodium]\")\n{\n    const uint8_t expected[] = { 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc,\n                                 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6,\n                                 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, 0x0a, 0x9e, 0xee,\n                                 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a,\n                                 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3,\n                                 0xfe, 0xeb, 0xbd, 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c,\n                                 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4,\n                                 0x9f\n                               };\n\n    uint8_t calculated[64];\n    crypto_hash_sha512_state state;\n\n    const uint8_t *in = (const uint8_t *)\"abc\";\n    const size_t inlen = 3;\n\n    // One-liner version\n    crypto_hash_sha512(calculated, in, inlen);\n    TEST_ASSERT_EQUAL(sizeof(calculated), sizeof(expected));\n    TEST_ASSERT_EQUAL(sizeof(calculated), crypto_hash_sha512_bytes());\n    TEST_ASSERT_EQUAL_MEMORY(expected, calculated, crypto_hash_sha512_bytes());\n\n    // Multi-line version\n    crypto_hash_sha512_init(&state);\n    crypto_hash_sha512_update(&state, in, inlen - 1); // split into two updates\n    crypto_hash_sha512_update(&state, in + (inlen - 1), 1);\n    crypto_hash_sha512_final(&state, calculated);\n    TEST_ASSERT_EQUAL_MEMORY(expected, calculated, crypto_hash_sha512_bytes());\n}\n"
  },
  {
    "path": "libsodium/test_apps/partitions.csv",
    "content": "# Name,   Type, SubType, Offset,  Size, Flags\n# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap\nnvs,      data, nvs,     ,        0x6000,\nphy_init, data, phy,     ,        0x1000,\nfactory,  app,  factory, ,        1500K,\n"
  },
  {
    "path": "libsodium/test_apps/pytest_libsodium.py",
    "content": "import pytest\n\n\n@pytest.mark.generic\ndef test_libsodium(dut) -> None:\n    dut.run_all_single_board_cases(timeout=120)\n"
  },
  {
    "path": "libsodium/test_apps/sdkconfig.defaults",
    "content": "# This file was generated using idf.py save-defconfig. It can be edited manually.\n# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration\n#\nCONFIG_ESP_MAIN_TASK_STACK_SIZE=8192\nCONFIG_ESP_TASK_WDT_INIT=n\nCONFIG_PARTITION_TABLE_CUSTOM=y\n"
  },
  {
    "path": "network_provisioning/CHANGELOG.md",
    "content": "# 1.2.4 (14-April-2026)\n\n- Fix incorrect fail reason reported in `NETWORK_PROV_WIFI_CRED_FAIL` event.\n\n# 1.2.3 (2-April-2026)\n- Fix possible NULL pointer dereference with malformed protobuf messages\n- Fix possible buffer overflow in Thread provisioning\n- Fix potential memory leaks\n\n# 1.2.2 (18-Dec-2025)\n\n- Fix connection attempts counter not being reset on state reset or new credentials\n  - Reset `connection_attempts_completed` to 0 in `network_prov_mgr_reset_wifi_sm_state_on_failure()`\n    and `network_prov_mgr_configure_wifi_sta()` to ensure full `wifi_conn_attempts` retries\n    after reset or when applying new credentials.\n\n# 1.2.1 (15-Dec-2025)\n\n- Fix prov-ctrl reset handler to return success when device is already in provisioning mode\n  - If firmware has already called `network_prov_mgr_reset_wifi_sm_state_on_failure()` or\n    `network_prov_mgr_reset_thread_sm_state_on_failure()`, the device state is already reset\n    to provisioning mode. The prov-ctrl handler now returns success in this case instead of\n    an invalid state error, allowing phone apps to successfully reset even if firmware has\n    already performed the reset operation.\n\n# 07-October-2025\n\n- Use managed cJSON component for IDF v6.0 and above\n\n# 01-April-2025\n\n- Extend provisioning check for `ESP_WIFI_REMOTE_ENABLED` as well along with existing `ESP_WIFI_ENABLED`\n- This enables provisioning for the devices not having native Wi-Fi (e.g., ESP32-P4) and using external/remote Wi-Fi solution such as esp-hosted for Wi-Fi connectivity.\n\n# 17-March-2025\n\n- Update the network provisioning component to work with the protocomm component which fixes incorrect AES-GCM IV usage in security2 scheme.\n\n# 19-June-2024\n\n- Change the proto files to make the network provisioning component stay backward compatible with the wifi_provisioing\n\n# 23-April-2024\n\n- Add `wifi_prov` or `thread_prov` in provision capabilities in the network provisioning manager for the provisioner to distinguish Thread or Wi-Fi devices\n\n# 16-April-2024\n\n- Move wifi_provisioning component from ESP-IDF at commit 5a40bb8746 and rename it to network_provisioning with the addition of Thread provisioning support.\n- Update esp_prov tool to support both Wi-Fi provisioning and Thread provisioning.\n- Create thread_prov and wifi_prov examples\n"
  },
  {
    "path": "network_provisioning/CMakeLists.txt",
    "content": "idf_build_get_property(target IDF_TARGET)\n\nif(${target} STREQUAL \"linux\")\n    return() # This component is not supported by the POSIX/Linux simulator\nendif()\n\nset(srcs \"src/network_config.c\"\n        \"src/network_scan.c\"\n        \"src/network_ctrl.c\"\n        \"src/manager.c\"\n        \"src/handlers.c\"\n        \"src/scheme_console.c\"\n        \"proto-c/network_config.pb-c.c\"\n        \"proto-c/network_scan.pb-c.c\"\n        \"proto-c/network_ctrl.pb-c.c\"\n        \"proto-c/network_constants.pb-c.c\")\n\nif((CONFIG_ESP_WIFI_ENABLED OR CONFIG_ESP_WIFI_REMOTE_ENABLED) AND CONFIG_ESP_WIFI_SOFTAP_SUPPORT)\n    list(APPEND srcs \"src/scheme_softap.c\")\nendif()\n\nif(CONFIG_BT_ENABLED)\n    if(CONFIG_BT_BLUEDROID_ENABLED OR CONFIG_BT_NIMBLE_ENABLED)\n        list(APPEND srcs\n            \"src/scheme_ble.c\")\n    endif()\nendif()\n\nset(priv_requires protobuf-c bt esp_timer esp_wifi openthread)\n\n# For IDF < 6.0, use IDF's built-in json component; for IDF >= 6.0 use managed cJSON component\nif(\"${IDF_VERSION_MAJOR}\" VERSION_LESS \"6\")\n    list(APPEND priv_requires json)\nendif()\n\nidf_component_register(SRCS \"${srcs}\"\n                    INCLUDE_DIRS include\n                    PRIV_INCLUDE_DIRS src proto-c\n                    REQUIRES lwip protocomm\n                    PRIV_REQUIRES ${priv_requires})\n"
  },
  {
    "path": "network_provisioning/Kconfig",
    "content": "menu \"Network Provisioning Manager\"\n\n    choice NETWORK_PROV_NETWORK_TYPE\n        prompt \"Network Type\"\n        default NETWORK_PROV_NETWORK_TYPE_WIFI if (ESP_WIFI_ENABLED || ESP_WIFI_REMOTE_ENABLED)\n        default NETWORK_PROV_NETWORK_TYPE_THREAD if !ESP_WIFI_ENABLE && OPENTHREAD_ENABLED\n\n        config NETWORK_PROV_NETWORK_TYPE_WIFI\n            bool \"Network Type - Wi-Fi\"\n            depends on ESP_WIFI_ENABLED || ESP_WIFI_REMOTE_ENABLED\n\n        config NETWORK_PROV_NETWORK_TYPE_THREAD\n            bool \"Network Type - Thread\"\n            depends on OPENTHREAD_ENABLED\n\n    endchoice\n\n    config NETWORK_PROV_SCAN_MAX_ENTRIES\n        int \"Max Network Scan Result Entries\"\n        default 16\n        range 1 255\n        help\n            This sets the maximum number of entries of network scan results that will be kept by the\n            provisioning manager\n\n    config NETWORK_PROV_AUTOSTOP_TIMEOUT\n        int \"Provisioning auto-stop timeout\"\n        default 30\n        range 5 600\n        help\n            Time (in seconds) after which the network provisioning manager will auto-stop after connecting to\n            a network successfully.\n\n    config NETWORK_PROV_BLE_BONDING\n        bool\n        prompt \"Enable BLE bonding\"\n        depends on BT_ENABLED\n        help\n            This option is applicable only when provisioning transport is BLE. Used to enable BLE bonding process\n            where the information from the pairing process will be stored on the devices.\n\n    config NETWORK_PROV_BLE_SEC_CONN\n        bool\n        prompt \"Enable BLE Secure connection flag\"\n        depends on  BT_NIMBLE_ENABLED\n        default y\n        help\n            Used to enable Secure connection support when provisioning transport is BLE.\n\n    config NETWORK_PROV_BLE_FORCE_ENCRYPTION\n        bool\n        prompt \"Force Link Encryption during characteristic Read / Write\"\n        depends on BT_ENABLED\n        help\n            Used to enforce link encryption when attempting to read / write characteristic\n\n    config NETWORK_PROV_BLE_NOTIFY\n        bool\n        prompt \"Add support for Notification for provisioning BLE descriptors\"\n        depends on BT_ENABLED\n        help\n            Used to enable support Notification in BLE descriptors of prov* characteristics\n\n    config NETWORK_PROV_KEEP_BLE_ON_AFTER_PROV\n        bool \"Keep BT on after provisioning is done\"\n        depends on BT_ENABLED\n        select ESP_PROTOCOMM_KEEP_BLE_ON_AFTER_BLE_STOP\n\n    config NETWORK_PROV_DISCONNECT_AFTER_PROV\n        bool \"Terminate connection after provisioning is done\"\n        depends on NETWORK_PROV_KEEP_BLE_ON_AFTER_PROV\n        default y\n        select ESP_PROTOCOMM_DISCONNECT_AFTER_BLE_STOP\n\n    choice NETWORK_PROV_WIFI_STA_SCAN_METHOD\n        bool \"Wifi Provisioning Scan Method\"\n        depends on NETWORK_PROV_NETWORK_TYPE_WIFI\n        default NETWORK_PROV_WIFI_STA_ALL_CHANNEL_SCAN\n        config NETWORK_PROV_WIFI_STA_ALL_CHANNEL_SCAN\n            bool \"All Channel Scan\"\n            help\n                    Scan will end after scanning the entire channel. This option is useful in Mesh WiFi Systems.\n        config NETWORK_PROV_WIFI_STA_FAST_SCAN\n            bool \"Fast Scan\"\n            help\n                    Scan will end after an AP matching with the SSID has been detected.\n    endchoice\nendmenu\n"
  },
  {
    "path": "network_provisioning/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2020 Piyush Shah <shahpiyushv@gmail.com>\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "network_provisioning/README.md",
    "content": "# Network Provisioning component\n\n[![Component Registry](https://components.espressif.com/components/espressif/network_provisioning/badge.svg)](https://components.espressif.com/components/espressif/network_provisioning)\n\nThe network provisioning component provides APIs that control the network provisioning service for receiving and configuring network credentials via secure [Protocol Communication](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/provisioning/protocomm.html) sessions.\n\nIt currently supports both Wi-Fi and Thread network provisioning:\n- Provision Wi-Fi credentials over SoftAP or Bluetooth LE\n- Provision Thread credentials over Bluetooth LE\n"
  },
  {
    "path": "network_provisioning/examples/README.md",
    "content": "# Provisioning Application Examples\n\nThis primarily consists of two examples `wifi_prov` and `thread_prov`.\n\n* wifi_prov\n    Abstracts out most of the complexity of Wi-Fi provisioning and allows easy switching between the SoftAP (using HTTP) and BLE transports. It also demonstrates how applications can register and use additional custom data endpoints.\n\n* thread_prov\n    Abstracts out most of the complexity of Thread provisioning over BLE transport. It also demonstrates how applications can register and use additional custom data endpoints.\n\nProvisioning applications are available for `Linux / Windows / macOS` platform as `esp_prov.py` [script](../tool/esp_prov/esp_prov.py)\n"
  },
  {
    "path": "network_provisioning/examples/thread_prov/CMakeLists.txt",
    "content": "# The following lines of boilerplate have to be in your project's CMakeLists\n# in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nproject(thread_prov)\n"
  },
  {
    "path": "network_provisioning/examples/thread_prov/README.md",
    "content": "| Supported Targets | ESP32-C6 | ESP32-H2 |\n| ----------------- | -------- | -------- |\n\n# Network Provisioning Manager Example for Thread Provisioning\n\n(See the README.md file in the upper level 'examples' directory for more information about examples.)\n\n`thread_prov` example demonstrates the usage of `network_provisioning` manager component for building a Thread provisioning application.\n\nFor this example, Bluetooth LE is chosen as the mode of transport, over which the provisioning related communication is to take place. NimBLE has been configured as the host.\n\nIn the provisioning process the device is configured as a Thread FTD with specified dataset. Once configured, the device will retain the Thread configuration, until a flash erase is performed.\n\nRight after the provisioning is complete, Bluetooth LE is turned off and disabled to free the memory used by the Bluetooth LE stack. Though, that is specific to this example, and the user can choose to keep Bluetooth LE stack intact in their own application.\n\n`thread_prov` uses the following components :\n* `network_provisioning` : Provides provisioning manager, data structures and protocomm endpoint handlers for Thread configuration\n* `protocomm` : For protocol based communication and secure session establishment\n* `protobuf` : Google's protocol buffer library for serialization of protocomm data structures\n* `bt` : ESP-IDF's Bluetooth LE stack for transport of protobuf packets\n\nThis example can be used, as it is, for adding a provisioning service to any application intended for IoT.\n\n> Note: If you use this example code in your own project, in Bluetooth LE mode, then remember to enable the BT stack and BTDM BLE control settings in your SDK configuration (e.g. by using the `sdkconfig.defaults` file from this project).\n\n## Security Scheme\n\nThe `protocomm` component is used for establishing secure communication channel at the time of provisioning. It supports two security schemes for establishing secure communication which are [Security 1 Scheme](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/provisioning/provisioning.html#security-1-scheme) and [Security 2 Scheme](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/provisioning/provisioning.html#security-2-scheme). The example uses `Security 2 Scheme` (latest) by default.\n\n## How to use example\n\n### Hardware Required\n\nExample should be able to run on any commonly available ESP32-H2/ESP32-C6 development board.\n\n### Script Required\n\nCurrently, provisioning script is available for `Linux / Windows / macOS` platforms.\n\n#### Platform : Linux / Windows / macOS\n\nTo install the dependency packages needed, please refer to the ESP-IDF examples [README file](https://github.com/espressif/esp-idf/blob/master/examples/README.md#running-test-python-script-ttfw).\n\n`esp_prov` supports Bluetooth LE and SoftAP transport for Linux, MacOS and Windows platforms. For Bluetooth LE, however, if dependencies are not met, the script falls back to console mode and requires another application through which the communication can take place. The `esp_prov` console will guide you through the provisioning process of locating the correct Bluetooth LE GATT services and characteristics, the values to write, and input read values.\n\n### Configure the project\n\n```\nidf.py menuconfig\n```\n\n### Build and Flash\n\nBuild the project and flash it to the board, then run monitor tool to view serial output:\n\n```\nidf.py -p PORT flash monitor\n```\n\n(To exit the serial monitor, type ``Ctrl-]``.)\n\nSee the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.\n\n## Example Output\n\n```\nI (445) app: Starting provisioning\nI (1035) app: Provisioning started\nI (1045) network_prov_mgr: Provisioning started with service name : PROV_F72E6B\n```\n\nMake sure to note down the Bluetooth LE device name (starting with `PROV_`) displayed in the serial monitor log (eg. PROV_F72E6B). This will depend on the MAC ID and will be unique for every device.\n\nIn a separate terminal run the `esp_prov.py` script under [directory](../../tool/esp_prov/) (make sure to replace `dataset_tlvs` with the dataset of the Thread network to which the device is supposed to connect to after provisioning). Assuming default example configuration, which uses the protocomm security version 2:\n\n```\npython esp_prov.py --transport ble --service_name PROV_F72E6B --sec_ver 2 --sec2_username threadprov --sec2_pwd abcd1234 --dataset_tlvs <dataset_tlvs>\n```\n\nFor security scheme 1 with PoP-based (proof-of-possession) authentication, the following command can be used:\n```\npython esp_prov.py --transport ble --service_name PROV_F72E6B --sec_ver 1 --pop abcd1234 --dataset_tlvs <dataset_tlvs>\n```\n\nAbove command will perform the provisioning steps, and the monitor log should display something like this :\n\n```\nI(125493) OPENTHREAD:[N] Mle-----------: Role disabled -> detached\nI (125503) OT_STATE: netif up\nI(125883) OPENTHREAD:[N] Mle-----------: Attach attempt 1, AnyPartition reattaching with Active Dataset\nI(126793) OPENTHREAD:[N] Mle-----------: RLOC16 fffe -> a40d\nI(126793) OPENTHREAD:[N] Mle-----------: Role detached -> child\nI (126813) OT_STATE: Set dns server address: FDE6:8626:404B:2::808:808\nI (126823) network_prov_mgr: Thread attached\nI (126823) app: Provisioning successful\nI (126823) app: Hello World!\nI (127833) app: Hello World!\nI (128833) app: Hello World!\n.\n.\n.\nI (131883) network_prov_mgr: Provisioning stopped\n.\n.\n.\nI (52355) app: Hello World!\nI (53355) app: Hello World!\nI (54355) app: Hello World!\nI (55355) app: Hello World!\n```\n\n**Note:** For generating the credentials for security version 2 (`SRP6a` salt and verifier) for the device-side, the following example command can be used. The output can then directly be used in this example.\n\nThe config option `CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE` should be enabled for the example and in `main/app_main.c`, the macro `EXAMPLE_PROV_SEC2_USERNAME` should be set to the same username used in the salt-verifier generation.\n\n```log\n$ python esp_prov.py --transport ble --sec_ver 2 --sec2_gen_cred --sec2_username threadprov --sec2_pwd abcd1234\n==== Salt-verifier for security scheme 2 (SRP6a) ====\nstatic const char sec2_salt[] = {\n    0x1f, 0xff, 0x29, 0xf5, 0xc7, 0x7e, 0x07, 0x48, 0x02, 0xe9, 0x93, 0x3e, 0xa3, 0xa2, 0x26, 0x73\n};\n\nstatic const char sec2_verifier[] = {\n    0xa7, 0x29, 0xe6, 0xa5, 0x4d, 0x20, 0x57, 0x71, 0x7c, 0x9d, 0x78, 0x2d, 0x0a, 0xb0, 0x9f, 0xec,\n    0x7e, 0x8b, 0xab, 0xf5, 0xe6, 0xc3, 0x36, 0x41, 0x93, 0xfd, 0xb9, 0x49, 0x67, 0xe7, 0x7f, 0x79,\n    0x66, 0x25, 0x2e, 0xac, 0x89, 0x19, 0xb2, 0xb3, 0x14, 0xb1, 0x16, 0xb0, 0xb0, 0xe4, 0x34, 0xd4,\n    0x99, 0x40, 0x85, 0xa4, 0x99, 0x2b, 0x84, 0x21, 0xa1, 0xfb, 0x15, 0x48, 0x04, 0x91, 0xf5, 0x74,\n    .\n    .\n    .\n    0x80, 0x86, 0xf4, 0xd5, 0x08, 0xbc, 0xb0, 0xdd, 0x6b, 0x50, 0xfa, 0xdd, 0x16, 0x10, 0x23, 0x4b\n};\n\n```\n\n### QR Code Scanning\n\nEnabling `CONFIG_EXAMPLE_PROV_SHOW_QR` will display a QR code on the serial terminal, which can be scanned from the ESP Provisioning phone apps to start the Thread provisioning process. The ESP Provisioning phone apps will be released later.\n\nThe monitor log should display something like this :\n\n```\nI (673) app: Provisioning started\nI (673) app: Scan this QR code from the provisioning application for Provisioning.\nI (693) QRCODE: Encoding below text with ECC LVL 0 & QR Code Version 10\nI (774) QRCODE: {\"ver\":\"v1\",\"name\":\"PROV_F72E6B\",\"username\":\"threadprov\",\"pop\":\"abcd1234\",\"transport\":\"ble\",\"network\":\"thread\"}\n>\n  █▀▀▀▀▀█ ▄▄▄█ ██▄▀█▀▀▀▀ ▀▄ ▄█▀█▄▀  █▀▀▀▀▀█\n  █ ███ █ ▄▄██ ▀▄▄▄▀▀▀▄▀▄▀▀▄▄▄▄▄█▀▄ █ ███ █\n  █ ▀▀▀ █ ▄  █   █▄ ▀ ▄ ▄▀▄ █▄███▀  █ ▀▀▀ █\n  ▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀▄▀ ▀ ▀▄▀ █ █▄█ █▄▀ ▀▀▀▀▀▀▀\n  ▀▀▀██▄▀██▄▀██▀▀▀ ▀▄▄█▄▀█ ▀▄▀▀▀█▄ █▄▀▄█ ▀▄\n  ██▄ ▀ ▀  ▀▄▄█ ▄█▄ ▀  ██  ▀█▀█▀█ █▀ ▀█▄▀█▄\n  ▄█▀▀▄▄▀█▄▀▀ ▀▄▄▄▄ ▀▀▄▄▀▄▀▀▀▀▄▀▄▄ ▄▄▄▄ ▀▀▄\n  ▀ █▄▄ ▀  ▀▀█▀▀█ ▄ ▀█▄█▄ ▀▀▀▀▄▀█ ▄█▄ ▄▀▀▄▄\n  ▀█▄█▀▀▀ ▄ ▀█▀██  █▄█▄▄▀▄▀▄▀ ▀  ▄▄█▄▀▄█▀▀▄\n  █ ▀██ ▀▀▄▄▄▄██▀▀ █▄ ▄█▄▄▄▀█▀▄▀█ █▄█▄▄█ ▀\n  ▀▀▄ ▄ ▀▄ ▄█ ▄ ▀█▀ ▄ ▀ ▀▄ ▀█▀▄▀▄██ ▄█▄█▀█▄\n   █▄▄  ▀▀ ▄▀ ▄  █▀ ▄ ▀██▄█▀ ▀  █▄ ▄▀▄█  ▀▄\n  ▄▄ ██▄▀▄█▀█▄▀▀ ▀ ▀ ▄█▄▀▄ ▀ █▄▄ ▄▄█▄█▄ ▀▀█\n  █▄█ ▄▄▀▀ ▀  ▄ ▄▀▄ ▀▄ █▀  ▀ ▀█ ▄ ▀▀▄ ▄ ▀█\n  █ ▄▀▀▀▀█▄▄  ▀ ▄█▄ ▀ ▄▄ ▄█▀▀  ▀▄▄█ ▄█▄ ▀ ▄\n  █ █▀█ ▀█▄ ██▀▀  ▄ ██▄██▄█▀ █▄▀█▄██▄ ▄ ▀ ▄\n  ▀ ▀▀  ▀ ▄ ▀█▀█▄ ██ █ ▄ █ █ ▄█ ▄▀█▀▀▀█ ▀▄█\n  █▀▀▀▀▀█ ▀▄ ▄██▀▀██▄▄ ▄ ▄█▀▄▀▄  ██ ▀ █ ▀ ▄\n  █ ███ █ █▀▀ ▄▄▀▄▀ ▄▀ ▄█▄▄█ ▀ ██ █▀▀▀▀███▄\n  █ ▀▀▀ █ ███ ▄▀ █▀▀█ █▄ ▄█ ▀▀ ▀ ▀██▀ ▀  ▄\n  ▀▀▀▀▀▀▀ ▀   ▀▀ ▀ ▀ ▀▀   ▀▀ ▀▀  ▀ ▀    ▀\n\nI (1134) app: If QR code is not visible, copy paste the below URL in a browser.\nhttps://espressif.github.io/esp-jumpstart/qrcode.html?data={\"ver\":\"v1\",\"name\":\"PROV_F72E6B\",\"username\":\"threadprov\",\"pop\":\"abcd1234\",\"transport\":\"ble\",\"network\":\"thread\"}\n\n```\n\n### Thread Scanning\n\nProvisioning manager also supports providing real-time Thread scan results (performed on the device) during provisioning. This allows the client side applications to choose the Thread network for which the device is to be configured. Various information about the visible Thread networks is available, like signal strength (RSSI) and link quality (LQI), etc. Also, the manager now provides capabilities information which can be used by client applications to determine availability of specific features (like `thread_scan`).\n\nWhen using the scan based provisioning, we don't need to specify the `--dataset_tlvs` fields explicitly:\n\n```\npython esp_prov.py --transport ble --service_name PROV_F72E6B --pop abcd1234\n```\n\nSee below the sample output from `esp_prov` tool on running above command:\n\n```\nConnecting...\nConnected\nGetting Services...\nSecurity scheme determined to be : 1\n\n==== Starting Session ====\n==== Session Established ====\n\n==== Scanning Thread Networks ====\n++++ Scan process executed in 6.247516632080078 sec\n++++ Scan results : 12\n\n++++ Scan finished in 7.349079132080078 sec\n==== Thread Scan results ====\nS.N. PAN ID   EXT PAN ID         NAME               EXT ADDR           CHN  RSSI LQI\n[ 1] 34121    9a6526ce2aaf4383   ST-34EW            e2848e0e9e315357   11   -53  9\n[ 2] 14311    7e010e5a22beb040   OpenThread-37e7    02a2ab187a4fb728   21   -47  10\n[ 3] 14311    7e010e5a22beb040   OpenThread-37e7    22bfc4ba63cf3bb8   21   -44  9\n[ 4] 4660     dead00beef00cafe   OpenThread-13b4    1e4d2bb3a614163f   22   -40  10\n[ 5] 48989    516f754f983e50c6   OpenThread-bf5d    be64e2845dc1d21a   22   -46  9\n[ 6] 4660     dead00beef00cafe   OpenThread-79c0    3e19ed4f89be20ee   22   -53  10\n[ 7] 31233    6c5105b3cb215393   qqqQQQQQQQQ        86ba2d8a2ded00d0   24   -47  8\n[ 8] 32231    0458ef52172c21d6   OpenThread-7de7    deca5eddda6da2a7   25   -50  10\n[ 9] 32231    0458ef52172c21d6   OpenThread-7de7    0e085d0f1d89db89   25   -45  10\n[10] 10299    07f592f684bc4266   MyHome1926416771   b268d0525d81f5c4   25   -59  9\n[11] 10299    07f592f684bc4266   MyHome1926416771   6ee0445b8d49d4b8   25   -56  9\n[12] 51344    7899e5214acf64db   OpenThread-c890    b22f21bc5ce8a058   26   -40  10\nSelect Network by number (0 to rescan) : 4\nEnter Thread network key string :\n\n==== Sending Thread Dataset to Target ====\n==== Thread Dataset sent successfully ====\n\n==== Applying Thread Config to Target ====\n==== Apply config sent successfully ====\n\n==== Thread connection state  ====\n==== Thread state: Attaching ====\n\n==== Thread connection state  ====\n==== Thread state: Attaching ====\n\n==== Thread connection state  ====\n==== Thread state: Attached ====\n==== Provisioning was successful ====\n\n```\n\n### Interactive Provisioning\n\n`esp_prov` supports interactive provisioning. You can trigger the script with a simplified command and input the necessary details\n(`Proof-of-possession` for security scheme 1 and `SRP6a username`, `SRP6a password` for security scheme 2) as the provisioning process advances.\n\nThe command `python esp_prov.py --transport ble --sec_ver 2` gives out the following sample output:\n\n```\nDiscovering...\n==== BLE Discovery results ====\nS.N. Name                              Address\n.\n.\n.\n[35] PROV_F73E7E                       60:55:F9:F7:3E:7E\n[36] 62-37-56-08-AA-64                 62:37:56:08:AA:64\n.\n.\n.\nSelect device by number (0 to rescan) : 35\nConnecting...\nGetting Services..\nSecurity Scheme 2 - SRP6a Username required: threadprov\nSecurity Scheme 2 - SRP6a Password required:\n\n==== Starting Session ====\n==== Session Established ====\n\n==== Scanning Thread Networks ====\n++++ Scan process executed in 6.247041702270508 sec\n++++ Scan results : 14\n\n++++ Scan finished in 7.40191650390625 sec\n==== Thread Scan results ====\nS.N. PAN ID   EXT PAN ID         NAME               EXT ADDR           CHN  RSSI LQI\n[ 1] 34121    9a6526ce2aaf4383   ST-34EW            e2848e0e9e315357   11   -53  9\n[ 2] 14311    7e010e5a22beb040   OpenThread-37e7    02a2ab187a4fb728   21   -45  9\n[ 3] 14311    7e010e5a22beb040   OpenThread-37e7    22bfc4ba63cf3bb8   21   -40  10\n[ 4] 4660     dead00beef00cafe   OpenThread-79c0    3e19ed4f89be20ee   22   -59  10\n[ 5] 4660     dead00beef00cafe   OpenThread-13b4    1e4d2bb3a614163f   22   -43  9\n[ 6] 48989    516f754f983e50c6   OpenThread-bf5d    be64e2845dc1d21a   22   -47  10\n[ 7] 23427    5b83dead5b83beef   5b83               8a1e30a60615c16c   24   -57  8\n[ 8] 31233    6c5105b3cb215393   qqqQQQQQQQQ        86ba2d8a2ded00d0   24   -48  10\n[ 9] 10299    07f592f684bc4266   MyHome1926416771   6ee0445b8d49d4b8   25   -55  9\n[10] 32231    0458ef52172c21d6   OpenThread-7de7    deca5eddda6da2a7   25   -50  10\n[11] 10299    07f592f684bc4266   MyHome1926416771   b268d0525d81f5c4   25   -55  9\n[12] 32231    0458ef52172c21d6   OpenThread-7de7    0e085d0f1d89db89   25   -47  10\n[13] 10299    07f592f684bc4266   MyHome1926416771   7e06f10b32fe678f   25   -54  10\n[14] 51344    7899e5214acf64db   OpenThread-c890    b22f21bc5ce8a058   26   -42  10\nSelect Network by number (0 to rescan) : 5\nEnter Thread network key string :\n\n==== Sending Thread Dataset to Target ====\n==== Thread Dataset sent successfully ====\n\n==== Applying Thread Config to Target ====\n==== Apply config sent successfully ====\n\n==== Thread connection state  ====\n==== Thread state: Attaching ====\n\n==== Thread connection state  ====\n==== Thread state: Attaching ====\n\n==== Thread connection state  ====\n==== Thread state: Attached ====\n==== Provisioning was successful ====\n```\n\n### Sending Custom Data\n\nThe provisioning manager allows applications to send some custom data during provisioning, which may be\nrequired for some other operations like connecting to some cloud service. This is achieved by creating\nand registering additional endpoints using the below APIs\n\n```\nnetwork_prov_mgr_endpoint_create();\nnetwork_prov_mgr_endpoint_register();\n```\n\nIn this particular example, we have added an endpoint named \"custom-data\" which can be tested\nby passing the `--custom_data <MyCustomData>` option to the esp\\_prov tool. Following output is\nexpected on success:\n\n```\n==== Sending Custom data to esp32 ====\nCustomData response: SUCCESS\n```\n\n## Troubleshooting\n\n### Provisioning failed\n\nIt is possible that the Thread dataset provided were incorrect, or the device was not able to establish connection to the network, in which the the `esp_prov` script will notify failure (with reason). Serial monitor log will display the failure along with disconnect reason :\n\n```\nE (367015) app: Provisioning failed!\n    Reason : Thread network not found\n    Please reset to factory and retry provisioning\n```\n\nOnce dataset have been applied, even though wrong dataset were provided, the device will no longer go into provisioning mode on subsequent reboots until NVS is erased (see following section).\n\n### Provisioning does not start\n\nIf the serial monitor log shows the following :\n\n```\nI (465) app: Already provisioned, enabling netif and starting Thread\n```\n\nit means either the device has been provisioned earlier with or without success (e.g. scenario covered in above section), or that the Thread dataset was already set by some other application flashed previously onto your device.\n\nTo fix this we simple need to erase the NVS partition from flash. First we need to find out its address and size. This can be seen from the monitor log on the top right after reboot.\n\n```\nI (47) boot: Partition Table:\nI (50) boot: ## Label            Usage          Type ST Offset   Length\nI (58) boot:  0 nvs              WiFi data        01 02 00009000 00006000\nI (65) boot:  1 phy_init         RF data          01 01 0000f000 00001000\nI (73) boot:  2 factory          factory app      00 00 00010000 00124f80\nI (80) boot: End of partition table\n```\n\nNow erase NVS partition by running the following commands :\n\n```\n$IDF_PATH/components/esptool_py/esptool/esptool.py erase_region 0x9000 0x6000\n```\n\n### Bluetooth Pairing Request during provisioning\n\nESP-IDF now has functionality to enforce link encryption requirement while performing GATT write on characteristics of provisioning service. This will however result in a pairing pop-up dialog, if link is not encrypted. This feature is disabled by default. In order to enable this feature, please set `CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION=y` in the sdkconfig or select the configuration using \"idf.py menuconfig\" .\n\n```\nComponent Config --> Network Provisioning Manager --> Force Link Encryption during Characteristic Read/Write\n\n```\nRecompiling the application with above changes should suffice to enable this functionality.\n\n"
  },
  {
    "path": "network_provisioning/examples/thread_prov/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"app_main.c\"\n                    INCLUDE_DIRS \".\")\n"
  },
  {
    "path": "network_provisioning/examples/thread_prov/main/Kconfig.projbuild",
    "content": "menu \"Example Configuration\"\n\n    choice EXAMPLE_PROV_SECURITY_VERSION\n        bool \"Protocomm security version\"\n        default EXAMPLE_PROV_SECURITY_VERSION_2\n        help\n            Network provisioning component offers 3 security versions.\n            The example offers a choice between security version 1 and 2.\n\n        config EXAMPLE_PROV_SECURITY_VERSION_1\n            bool \"Security version 1\"\n            select ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1\n\n        config EXAMPLE_PROV_SECURITY_VERSION_2\n            bool \"Security version 2\"\n            select ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2\n    endchoice\n\n    choice EXAMPLE_PROV_MODE\n        bool \"Security version 2 mode\"\n        depends on EXAMPLE_PROV_SECURITY_VERSION_2\n        default EXAMPLE_PROV_SEC2_DEV_MODE\n\n        config EXAMPLE_PROV_SEC2_DEV_MODE\n            bool \"Security version 2 development mode\"\n            depends on EXAMPLE_PROV_SECURITY_VERSION_2\n            help\n                This enables the development mode for\n                security version 2.\n                Please note that this mode is NOT recommended for production purpose.\n\n        config EXAMPLE_PROV_SEC2_PROD_MODE\n            bool \"Security version 2 production mode\"\n            depends on EXAMPLE_PROV_SECURITY_VERSION_2\n            help\n                This enables the production mode for\n                security version 2.\n    endchoice\n\n    config EXAMPLE_PROV_TRANSPORT\n        int\n        default 1 if EXAMPLE_PROV_TRANSPORT_BLE\n\n    config EXAMPLE_RESET_PROVISIONED\n        bool\n        default n\n        prompt \"Reset provisioned status of the device\"\n        help\n            This erases the NVS to reset provisioned status of the device on every reboot.\n            Provisioned status is determined by the Wi-Fi STA configuration, saved on the NVS.\n\n    config EXAMPLE_RESET_PROV_MGR_ON_FAILURE\n        bool\n        default y\n        prompt \"Reset provisioned credentials and state machine after session failure\"\n        help\n            Enable resetting provisioned credentials and state machine after session failure.\n            This will restart the provisioning service after retries are exhausted.\n\n    config EXAMPLE_PROV_MGR_MAX_RETRY_CNT\n        int\n        default 5\n        prompt \"Max retries before resetting provisioning state machine\"\n        depends on EXAMPLE_RESET_PROV_MGR_ON_FAILURE\n        help\n            Set the Maximum retry to avoid reconnecting to an inexistent AP or if credentials\n            are misconfigured. Provisioned credentials are erased and internal state machine\n            is reset after this threshold is reached.\n\n    config EXAMPLE_PROV_SHOW_QR\n        bool \"Show provisioning QR code\"\n        default y\n        help\n            Show the QR code for provisioning.\n\n    config EXAMPLE_REPROVISIONING\n        bool \"Re-provisioning\"\n        help\n            Enable re-provisioning - allow the device to provision for new credentials\n            after previous successful provisioning.\n\nendmenu\n"
  },
  {
    "path": "network_provisioning/examples/thread_prov/main/app_main.c",
    "content": "/* Network Provisioning Manager Example for Thread network\n\n   This example code is in the Public Domain (or CC0 licensed, at your option.)\n\n   Unless required by applicable law or agreed to in writing, this\n   software is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n   CONDITIONS OF ANY KIND, either express or implied.\n*/\n\n#include <stdio.h>\n#include <string.h>\n\n#include <freertos/FreeRTOS.h>\n#include <freertos/task.h>\n#include <freertos/event_groups.h>\n\n#include <esp_log.h>\n#include <esp_openthread.h>\n#include \"esp_openthread_cli.h\"\n#include \"esp_openthread_netif_glue.h\"\n#include \"esp_openthread_types.h\"\n#include <esp_ot_config.h>\n#include <esp_netif.h>\n#include <esp_event.h>\n#include <esp_mac.h>\n#include <esp_vfs_eventfd.h>\n#include <nvs_flash.h>\n\n#include <network_provisioning/manager.h>\n\n#include \"openthread/cli.h\"\n#include \"openthread/instance.h\"\n#include \"openthread/logging.h\"\n#include \"openthread/tasklet.h\"\n#include \"openthread/thread.h\"\n\n#include <network_provisioning/scheme_ble.h>\n\n#include \"qrcode.h\"\n\nstatic const char *TAG = \"app\";\n\n#if CONFIG_EXAMPLE_PROV_SECURITY_VERSION_2\n#if CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE\n#define EXAMPLE_PROV_SEC2_USERNAME          \"threadprov\"\n#define EXAMPLE_PROV_SEC2_PWD               \"abcd1234\"\n\n/* This salt,verifier has been generated for username = \"threadprov\" and password = \"abcd1234\"\n * IMPORTANT NOTE: For production cases, this must be unique to every device\n * and should come from device manufacturing partition.*/\nstatic const char sec2_salt[] = {\n    0x1f, 0xff, 0x29, 0xf5, 0xc7, 0x7e, 0x07, 0x48, 0x02, 0xe9, 0x93, 0x3e, 0xa3, 0xa2, 0x26, 0x73\n};\n\nstatic const char sec2_verifier[] = {\n    0xa7, 0x29, 0xe6, 0xa5, 0x4d, 0x20, 0x57, 0x71, 0x7c, 0x9d, 0x78, 0x2d, 0x0a, 0xb0, 0x9f, 0xec,\n    0x7e, 0x8b, 0xab, 0xf5, 0xe6, 0xc3, 0x36, 0x41, 0x93, 0xfd, 0xb9, 0x49, 0x67, 0xe7, 0x7f, 0x79,\n    0x66, 0x25, 0x2e, 0xac, 0x89, 0x19, 0xb2, 0xb3, 0x14, 0xb1, 0x16, 0xb0, 0xb0, 0xe4, 0x34, 0xd4,\n    0x99, 0x40, 0x85, 0xa4, 0x99, 0x2b, 0x84, 0x21, 0xa1, 0xfb, 0x15, 0x48, 0x04, 0x91, 0xf5, 0x74,\n    0x95, 0x8a, 0x88, 0xd4, 0x4e, 0x25, 0xf6, 0xf3, 0x8e, 0x5c, 0xf9, 0x3c, 0xda, 0xbb, 0x4f, 0xa2,\n    0x47, 0xe1, 0x01, 0x8f, 0x1c, 0xf5, 0xe0, 0x34, 0x41, 0x0c, 0x88, 0x76, 0x46, 0xd0, 0x16, 0xd9,\n    0xfa, 0x57, 0x3d, 0x78, 0x46, 0xf1, 0xcb, 0xb1, 0x05, 0x16, 0xab, 0xf7, 0xbf, 0x9d, 0xeb, 0x05,\n    0x2e, 0xc1, 0xd5, 0xe1, 0xde, 0x92, 0xe6, 0x20, 0x5f, 0xe4, 0x27, 0xda, 0xe3, 0x59, 0x91, 0x27,\n    0x7b, 0x40, 0x83, 0x4c, 0xe8, 0xb5, 0xe0, 0x75, 0xe6, 0xbf, 0x26, 0xa9, 0x67, 0x06, 0xa3, 0x15,\n    0x2d, 0x20, 0x81, 0xd5, 0x2a, 0x2e, 0x30, 0x84, 0xdf, 0xa2, 0x82, 0x62, 0xc4, 0x47, 0x25, 0xb6,\n    0x93, 0x73, 0x87, 0x3c, 0xa7, 0x57, 0x2a, 0x47, 0x96, 0x1d, 0x89, 0xce, 0x49, 0xc6, 0x9d, 0x4f,\n    0x6b, 0x39, 0x38, 0x67, 0xbb, 0x85, 0x24, 0xdf, 0xcd, 0xf5, 0xf1, 0x9f, 0x0a, 0x9e, 0x1c, 0x31,\n    0xfa, 0xf1, 0x01, 0xa5, 0x30, 0xf0, 0xcb, 0x5e, 0x1c, 0xd6, 0xa0, 0x11, 0x3f, 0xf8, 0xdd, 0x07,\n    0x09, 0x53, 0x62, 0x9f, 0x76, 0x5c, 0x69, 0xd1, 0x5e, 0x5b, 0xc7, 0xb0, 0x0e, 0x53, 0xeb, 0x8c,\n    0x67, 0x88, 0xc7, 0x45, 0xc0, 0x26, 0xd9, 0xfa, 0xf8, 0x63, 0x0c, 0x64, 0xcb, 0x9e, 0xf4, 0x1b,\n    0xb3, 0xfd, 0x78, 0x0c, 0x47, 0x0f, 0x66, 0xf3, 0xf7, 0xcd, 0xe9, 0xc6, 0x36, 0xa5, 0x58, 0xe5,\n    0x9d, 0x31, 0x53, 0xb2, 0xe4, 0x8e, 0xdd, 0xd0, 0x8d, 0x13, 0xe8, 0xc6, 0x96, 0x60, 0x30, 0x50,\n    0xbc, 0xef, 0xce, 0xbc, 0x23, 0xe3, 0x60, 0x63, 0x54, 0x11, 0x24, 0xba, 0x68, 0x47, 0x6a, 0xb2,\n    0x5e, 0x70, 0xa3, 0xa6, 0xc3, 0xad, 0x58, 0xd1, 0x3b, 0xce, 0xce, 0x90, 0xe9, 0x90, 0x7e, 0x7a,\n    0xfb, 0x4f, 0x69, 0xa2, 0x81, 0xdf, 0x15, 0xec, 0xa7, 0x8f, 0xd6, 0x5a, 0xb8, 0x1f, 0x42, 0x18,\n    0x0e, 0x4f, 0x3e, 0x45, 0x2d, 0x08, 0xf2, 0xd6, 0x51, 0x90, 0xef, 0x64, 0x77, 0xee, 0xcc, 0x3c,\n    0xb4, 0xa6, 0x6f, 0x0b, 0x10, 0xb2, 0xce, 0x31, 0x19, 0x10, 0x8d, 0x75, 0x8f, 0xa8, 0xa2, 0x6e,\n    0x7a, 0x00, 0x92, 0x91, 0xe2, 0x16, 0xe3, 0x7a, 0xf9, 0x1d, 0x4e, 0x39, 0xe5, 0xd0, 0xd1, 0x7e,\n    0x80, 0x86, 0xf4, 0xd5, 0x08, 0xbc, 0xb0, 0xdd, 0x6b, 0x50, 0xfa, 0xdd, 0x16, 0x10, 0x23, 0x4b\n};\n#endif\n\nstatic esp_err_t example_get_sec2_salt(const char **salt, uint16_t *salt_len)\n{\n#if CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE\n    ESP_LOGI(TAG, \"Development mode: using hard coded salt\");\n    *salt = sec2_salt;\n    *salt_len = sizeof(sec2_salt);\n    return ESP_OK;\n#elif CONFIG_EXAMPLE_PROV_SEC2_PROD_MODE\n    ESP_LOGE(TAG, \"Not implemented!\");\n    return ESP_FAIL;\n#endif\n}\n\nstatic esp_err_t example_get_sec2_verifier(const char **verifier, uint16_t *verifier_len)\n{\n#if CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE\n    ESP_LOGI(TAG, \"Development mode: using hard coded verifier\");\n    *verifier = sec2_verifier;\n    *verifier_len = sizeof(sec2_verifier);\n    return ESP_OK;\n#elif CONFIG_EXAMPLE_PROV_SEC2_PROD_MODE\n    /* This code needs to be updated with appropriate implementation to provide verifier */\n    ESP_LOGE(TAG, \"Not implemented!\");\n    return ESP_FAIL;\n#endif\n}\n#endif\n\n/* Signal Thread events on this event-group */\nconst int THREAD_ATTACHED_EVENT = BIT0;\nstatic EventGroupHandle_t thread_event_group;\n\n#define PROV_QR_VERSION         \"v1\"\n#define PROV_TRANSPORT_BLE      \"ble\"\n#define QRCODE_BASE_URL         \"https://espressif.github.io/esp-jumpstart/qrcode.html\"\n\n/* Event handler for catching system events */\nstatic void event_handler(void *arg, esp_event_base_t event_base,\n                          int32_t event_id, void *event_data)\n{\n    if (event_base == NETWORK_PROV_EVENT) {\n        switch (event_id) {\n        case NETWORK_PROV_START:\n            ESP_LOGI(TAG, \"Provisioning started\");\n            break;\n        case NETWORK_PROV_THREAD_DATASET_RECV: {\n            // TODO Log thread dataset\n            break;\n        }\n        case NETWORK_PROV_THREAD_DATASET_FAIL: {\n            network_prov_thread_fail_reason_t *reason = (network_prov_thread_fail_reason_t *)event_data;\n            ESP_LOGE(TAG, \"Provisioning failed!\\n\\tReason : %s\"\n                     \"\\n\\tPlease reset to factory and retry provisioning\",\n                     (*reason == NETWORK_PROV_THREAD_DATASET_INVALID) ?\n                     \"Invalid Thread dataset\" : \"Thread network not found\");\n            break;\n        }\n        case NETWORK_PROV_THREAD_DATASET_SUCCESS:\n            ESP_LOGI(TAG, \"Provisioning successful\");\n            break;\n        case NETWORK_PROV_END:\n            /* De-initialize manager once provisioning is finished */\n            network_prov_mgr_deinit();\n            break;\n        default:\n            break;\n        }\n    } else if (event_base == OPENTHREAD_EVENT && event_id == OPENTHREAD_EVENT_ATTACHED) {\n        xEventGroupSetBits(thread_event_group, THREAD_ATTACHED_EVENT);\n    } else if (event_base == PROTOCOMM_SECURITY_SESSION_EVENT) {\n        switch (event_id) {\n        case PROTOCOMM_SECURITY_SESSION_SETUP_OK:\n            ESP_LOGI(TAG, \"Secured session established!\");\n            break;\n        case PROTOCOMM_SECURITY_SESSION_INVALID_SECURITY_PARAMS:\n            ESP_LOGE(TAG, \"Received invalid security parameters for establishing secure session!\");\n            break;\n        case PROTOCOMM_SECURITY_SESSION_CREDENTIALS_MISMATCH:\n            ESP_LOGE(TAG, \"Received incorrect username and/or PoP for establishing secure session!\");\n            break;\n        default:\n            break;\n        }\n    }\n}\n\nstatic void get_device_service_name(char *service_name, size_t max)\n{\n    uint8_t ieee802154_mac[8];\n    const char *ssid_prefix = \"PROV_\";\n    esp_read_mac(ieee802154_mac, ESP_MAC_IEEE802154);\n    snprintf(service_name, max, \"%s%02X%02X%02X\",\n             ssid_prefix, ieee802154_mac[5], ieee802154_mac[6], ieee802154_mac[7]);\n}\n\n/* Handler for the optional provisioning endpoint registered by the application.\n * The data format can be chosen by applications. Here, we are using plain ascii text.\n * Applications can choose to use other formats like protobuf, JSON, XML, etc.\n */\nesp_err_t custom_prov_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,\n                                   uint8_t **outbuf, ssize_t *outlen, void *priv_data)\n{\n    if (inbuf) {\n        ESP_LOGI(TAG, \"Received data: %.*s\", inlen, (char *)inbuf);\n    }\n    char response[] = \"SUCCESS\";\n    *outbuf = (uint8_t *)strdup(response);\n    if (*outbuf == NULL) {\n        ESP_LOGE(TAG, \"System out of memory\");\n        return ESP_ERR_NO_MEM;\n    }\n    *outlen = strlen(response) + 1; /* +1 for NULL terminating byte */\n\n    return ESP_OK;\n}\n\nstatic void network_prov_print_qr(const char *name, const char *username, const char *pop, const char *transport)\n{\n    if (!name || !transport) {\n        ESP_LOGW(TAG, \"Cannot generate QR code payload. Data missing.\");\n        return;\n    }\n    char payload[150] = {0};\n    if (pop) {\n#if CONFIG_EXAMPLE_PROV_SECURITY_VERSION_1\n        snprintf(payload, sizeof(payload), \"{\\\"ver\\\":\\\"%s\\\",\\\"name\\\":\\\"%s\\\"\" \\\n                 \",\\\"pop\\\":\\\"%s\\\",\\\"transport\\\":\\\"%s\\\"}\",\n                 PROV_QR_VERSION, name, pop, transport);\n#elif CONFIG_EXAMPLE_PROV_SECURITY_VERSION_2\n        snprintf(payload, sizeof(payload), \"{\\\"ver\\\":\\\"%s\\\",\\\"name\\\":\\\"%s\\\"\" \\\n                 \",\\\"username\\\":\\\"%s\\\",\\\"pop\\\":\\\"%s\\\",\\\"transport\\\":\\\"%s\\\"}\",\n                 PROV_QR_VERSION, name, username, pop, transport);\n#endif\n    } else {\n        snprintf(payload, sizeof(payload), \"{\\\"ver\\\":\\\"%s\\\",\\\"name\\\":\\\"%s\\\"\" \\\n                 \",\\\"transport\\\":\\\"%s\\\"}\",\n                 PROV_QR_VERSION, name, transport);\n    }\n#ifdef CONFIG_EXAMPLE_PROV_SHOW_QR\n    ESP_LOGI(TAG, \"Scan this QR code from the provisioning application for Provisioning.\");\n    esp_qrcode_config_t cfg = ESP_QRCODE_CONFIG_DEFAULT();\n    esp_qrcode_generate(&cfg, payload);\n    //TODO: Add the network protocol type to the QR code payload\n#endif /* CONFIG EXAMPLE_PROV_SHOW_QR */\n    ESP_LOGI(TAG, \"If QR code is not visible, copy paste the below URL in a browser.\\n%s?data=%s\", QRCODE_BASE_URL, payload);\n}\n\nstatic esp_netif_t *init_openthread_netif(const esp_openthread_platform_config_t *config)\n{\n    esp_netif_config_t cfg = ESP_NETIF_DEFAULT_OPENTHREAD();\n    esp_netif_t *netif = esp_netif_new(&cfg);\n    assert(netif != NULL);\n    ESP_ERROR_CHECK(esp_netif_attach(netif, esp_openthread_netif_glue_init(config)));\n\n    return netif;\n}\n\nstatic void ot_task_worker(void *aContext)\n{\n    esp_openthread_platform_config_t config = {\n        .radio_config = ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG(),\n        .host_config = ESP_OPENTHREAD_DEFAULT_HOST_CONFIG(),\n        .port_config = ESP_OPENTHREAD_DEFAULT_PORT_CONFIG(),\n    };\n\n    // Initialize the OpenThread stack\n    ESP_ERROR_CHECK(esp_openthread_init(&config));\n#if CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC\n    // The OpenThread log level directly matches ESP log level\n    (void)otLoggingSetLevel(CONFIG_LOG_DEFAULT_LEVEL);\n#endif\n#if CONFIG_OPENTHREAD_CLI\n    // Initialize the OpenThread cli\n    esp_openthread_cli_init();\n#endif\n    esp_netif_t *openthread_netif = init_openthread_netif(&config);\n    // Initialize the esp_netif bindings\n    esp_netif_set_default_netif(openthread_netif);\n\n    // Run the main loop\n#if CONFIG_OPENTHREAD_CLI\n    esp_openthread_cli_create_task();\n#endif\n    esp_openthread_launch_mainloop();\n\n    // Clean up\n    esp_netif_destroy(openthread_netif);\n    esp_openthread_netif_glue_deinit();\n\n    esp_vfs_eventfd_unregister();\n    vTaskDelete(NULL);\n}\n\nvoid app_main(void)\n{\n    /* Initialize NVS partition */\n    esp_err_t ret = nvs_flash_init();\n    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {\n        /* NVS partition was truncated\n         * and needs to be erased */\n        ESP_ERROR_CHECK(nvs_flash_erase());\n\n        /* Retry nvs_flash_init */\n        ESP_ERROR_CHECK(nvs_flash_init());\n    }\n\n    /* Initialize TCP/IP */\n    ESP_ERROR_CHECK(esp_netif_init());\n\n    /* Initialize the event loop */\n    ESP_ERROR_CHECK(esp_event_loop_create_default());\n\n    thread_event_group = xEventGroupCreate();\n\n    /* Register our event handler for OpenThread and Provisioning related events */\n    ESP_ERROR_CHECK(esp_event_handler_register(NETWORK_PROV_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));\n#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE\n    ESP_ERROR_CHECK(esp_event_handler_register(PROTOCOMM_TRANSPORT_BLE_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));\n#endif\n    ESP_ERROR_CHECK(esp_event_handler_register(PROTOCOMM_SECURITY_SESSION_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));\n    ESP_ERROR_CHECK(esp_event_handler_register(OPENTHREAD_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));\n\n    esp_vfs_eventfd_config_t eventfd_config = {\n        .max_fds = 3,\n    };\n    ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config));\n    xTaskCreate(ot_task_worker, \"ot_task\", 6144, xTaskGetCurrentTaskHandle(), 5, NULL);\n\n    /* Configuration for the provisioning manager */\n    network_prov_mgr_config_t config = {\n        /* Use network_prov_scheme_ble as the Provisioning Scheme */\n        .scheme = network_prov_scheme_ble,\n\n        /* Any default scheme specific event handler that you would\n         * like to choose. Since our example application requires\n         * neither BT nor BLE, we can choose to release the associated\n         * memory once provisioning is complete, or not needed\n         * (in case when device is already provisioned). Choosing\n         * appropriate scheme specific event handler allows the manager\n         * to take care of this automatically. */\n        .scheme_event_handler = NETWORK_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BLE\n    };\n\n    /* Initialize provisioning manager with the\n     * configuration parameters set above */\n    ESP_ERROR_CHECK(network_prov_mgr_init(config));\n\n    bool provisioned = false;\n#ifdef CONFIG_EXAMPLE_RESET_PROVISIONED\n    network_prov_mgr_reset_thread_provisioning();\n#else\n    /* Let's find out if the device is provisioned */\n    ESP_ERROR_CHECK(network_prov_mgr_is_thread_provisioned(&provisioned));\n\n#endif\n    /* If device is not yet provisioned start provisioning service */\n    if (!provisioned) {\n        ESP_LOGI(TAG, \"Starting provisioning\");\n\n        /* What is the Device Service Name that we want\n         * This translates to :\n         *     - device name when scheme is network_prov_scheme_ble\n         */\n        char service_name[12];\n        get_device_service_name(service_name, sizeof(service_name));\n\n#ifdef CONFIG_EXAMPLE_PROV_SECURITY_VERSION_1\n        /* What is the security level that we want (0, 1, 2):\n         *      - NETWORK_PROV_SECURITY_0 is simply plain text communication.\n         *      - NETWORK_PROV_SECURITY_1 is secure communication which consists of secure handshake\n         *          using X25519 key exchange and proof of possession (pop) and AES-CTR\n         *          for encryption/decryption of messages.\n         *      - NETWORK_PROV_SECURITY_2 SRP6a based authentication and key exchange\n         *        + AES-GCM encryption/decryption of messages\n         */\n        network_prov_security_t security = NETWORK_PROV_SECURITY_1;\n\n        /* Do we want a proof-of-possession (ignored if Security 0 is selected):\n         *      - this should be a string with length > 0\n         *      - NULL if not used\n         */\n        const char *pop = \"abcd1234\";\n\n        /* This is the structure for passing security parameters\n         * for the protocomm security 1.\n         */\n        network_prov_security1_params_t *sec_params = pop;\n\n        const char *username  = NULL;\n\n#elif CONFIG_EXAMPLE_PROV_SECURITY_VERSION_2\n        network_prov_security_t security = NETWORK_PROV_SECURITY_2;\n        /* The username must be the same one, which has been used in the generation of salt and verifier */\n\n#if CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE\n        /* This pop field represents the password that will be used to generate salt and verifier.\n         * The field is present here in order to generate the QR code containing password.\n         * In production this password field shall not be stored on the device */\n        const char *username  = EXAMPLE_PROV_SEC2_USERNAME;\n        const char *pop = EXAMPLE_PROV_SEC2_PWD;\n#elif CONFIG_EXAMPLE_PROV_SEC2_PROD_MODE\n        /* The username and password shall not be embedded in the firmware,\n         * they should be provided to the user by other means.\n         * e.g. QR code sticker */\n        const char *username  = NULL;\n        const char *pop = NULL;\n#endif\n        /* This is the structure for passing security parameters\n         * for the protocomm security 2.\n         * If dynamically allocated, sec2_params pointer and its content\n         * must be valid till WIFI_PROV_END event is triggered.\n         */\n        network_prov_security2_params_t sec2_params = {};\n\n        ESP_ERROR_CHECK(example_get_sec2_salt(&sec2_params.salt, &sec2_params.salt_len));\n        ESP_ERROR_CHECK(example_get_sec2_verifier(&sec2_params.verifier, &sec2_params.verifier_len));\n\n        network_prov_security2_params_t *sec_params = &sec2_params;\n#endif\n        /* What is the service key (could be NULL)\n         * This translates to :\n         *     - simply ignored when scheme is network_prov_scheme_ble\n         */\n        const char *service_key = NULL;\n\n#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE\n        /* This step is only useful when scheme is network_prov_scheme_ble. This will\n         * set a custom 128 bit UUID which will be included in the BLE advertisement\n         * and will correspond to the primary GATT service that provides provisioning\n         * endpoints as GATT characteristics. Each GATT characteristic will be\n         * formed using the primary service UUID as base, with different auto assigned\n         * 12th and 13th bytes (assume counting starts from 0th byte). The client side\n         * applications must identify the endpoints by reading the User Characteristic\n         * Description descriptor (0x2901) for each characteristic, which contains the\n         * endpoint name of the characteristic */\n        uint8_t custom_service_uuid[] = {\n            /* LSB <---------------------------------------\n             * ---------------------------------------> MSB */\n            0xb4, 0xdf, 0x5a, 0x1c, 0x3f, 0x6b, 0xf4, 0xbf,\n            0xea, 0x4a, 0x82, 0x03, 0x04, 0x90, 0x1a, 0x02,\n        };\n\n        /* If your build fails with linker errors at this point, then you may have\n         * forgotten to enable the BT stack or BTDM BLE settings in the SDK (e.g. see\n         * the sdkconfig.defaults in the example project) */\n        network_prov_scheme_ble_set_service_uuid(custom_service_uuid);\n#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_BLE */\n\n        /* An optional endpoint that applications can create if they expect to\n         * get some additional custom data during provisioning workflow.\n         * The endpoint name can be anything of your choice.\n         * This call must be made before starting the provisioning.\n         */\n        network_prov_mgr_endpoint_create(\"custom-data\");\n\n        /* Do not stop and de-init provisioning even after success,\n         * so that we can restart it later. */\n#ifdef CONFIG_EXAMPLE_REPROVISIONING\n        network_prov_mgr_disable_auto_stop(1000);\n#endif\n        /* Start provisioning service */\n        ESP_ERROR_CHECK(network_prov_mgr_start_provisioning(security, (const void *) sec_params, service_name, service_key));\n\n        /* The handler for the optional endpoint created above.\n         * This call must be made after starting the provisioning, and only if the endpoint\n         * has already been created above.\n         */\n        network_prov_mgr_endpoint_register(\"custom-data\", custom_prov_data_handler, NULL);\n\n        /* Uncomment the following to wait for the provisioning to finish and then release\n         * the resources of the manager. Since in this case de-initialization is triggered\n         * by the default event loop handler, we don't need to call the following */\n        // network_prov_mgr_wait();\n        // network_prov_mgr_deinit();\n        /* Print QR code for provisioning */\n        network_prov_print_qr(service_name, username, pop, PROV_TRANSPORT_BLE);\n    } else {\n        ESP_LOGI(TAG, \"Already provisioned, enabling netif and starting Thread\");\n\n        /* We don't need the manager as device is already provisioned,\n         * so let's release it's resources */\n        network_prov_mgr_deinit();\n\n        otInstance *instance = esp_openthread_get_instance();\n        (void)otIp6SetEnabled(instance, true);\n        (void)otThreadSetEnabled(instance, true);\n    }\n\n    /* Wait for Thread connection */\n    xEventGroupWaitBits(thread_event_group, THREAD_ATTACHED_EVENT, true, true, portMAX_DELAY);\n\n    /* Start main application now */\n#if CONFIG_EXAMPLE_REPROVISIONING\n    while (1) {\n        for (int i = 0; i < 10; i++) {\n            ESP_LOGI(TAG, \"Hello World!\");\n            vTaskDelay(1000 / portTICK_PERIOD_MS);\n        }\n\n        /* Resetting provisioning state machine to enable re-provisioning */\n        network_prov_mgr_reset_thread_sm_state_for_reprovision();\n\n        /* Wait for thread connection */\n        xEventGroupWaitBits(thread_event_group, THREAD_ATTACHED_EVENT, true, true, portMAX_DELAY);\n    }\n#else\n    while (1) {\n        ESP_LOGI(TAG, \"Hello World!\");\n        vTaskDelay(1000 / portTICK_PERIOD_MS);\n    }\n#endif\n\n}\n"
  },
  {
    "path": "network_provisioning/examples/thread_prov/main/esp_ot_config.h",
    "content": "/* Network Provisioning Manager Example for Thread network\n *\n * This example code is in the Public Domain (or CC0 licensed, at your option.)\n *\n * Unless required by applicable law or agreed to in writing, this\n * software is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n * CONDITIONS OF ANY KIND, either express or implied.\n */\n\n#pragma once\n\n#include \"esp_openthread_types.h\"\n\n#if SOC_IEEE802154_SUPPORTED\n#define ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG()              \\\n    {                                                      \\\n        .radio_mode = RADIO_MODE_NATIVE,                   \\\n    }\n\n#else\n#define ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG()                 \\\n    {                                                         \\\n        .radio_mode = RADIO_MODE_UART_RCP,                    \\\n        .radio_uart_config = {                                \\\n            .port = 1,                                        \\\n            .uart_config =                                    \\\n                {                                             \\\n                    .baud_rate = 115200,                      \\\n                    .data_bits = UART_DATA_8_BITS,            \\\n                    .parity = UART_PARITY_DISABLE,            \\\n                    .stop_bits = UART_STOP_BITS_1,            \\\n                    .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,    \\\n                    .rx_flow_ctrl_thresh = 0,                 \\\n                    .source_clk = UART_SCLK_DEFAULT,          \\\n                },                                            \\\n            .rx_pin = 4,                                      \\\n            .tx_pin = 5,                                      \\\n        },                                                    \\\n    }\n#endif\n\n#define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG()                    \\\n    {                                                           \\\n        .host_connection_mode = HOST_CONNECTION_MODE_CLI_UART,  \\\n        .host_uart_config = {                                   \\\n            .port = 0,                                          \\\n            .uart_config =                                      \\\n                {                                               \\\n                    .baud_rate = 115200,                        \\\n                    .data_bits = UART_DATA_8_BITS,              \\\n                    .parity = UART_PARITY_DISABLE,              \\\n                    .stop_bits = UART_STOP_BITS_1,              \\\n                    .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,      \\\n                    .rx_flow_ctrl_thresh = 0,                   \\\n                    .source_clk = UART_SCLK_DEFAULT,            \\\n                },                                              \\\n            .rx_pin = UART_PIN_NO_CHANGE,                       \\\n            .tx_pin = UART_PIN_NO_CHANGE,                       \\\n        },                                                      \\\n    }\n\n#define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG()    \\\n    {                                           \\\n        .storage_partition_name = \"nvs\",        \\\n        .netif_queue_size = 10,                 \\\n        .task_queue_size = 10,                  \\\n    }\n"
  },
  {
    "path": "network_provisioning/examples/thread_prov/main/idf_component.yml",
    "content": "version: \"1.0.0\"\ndependencies:\n  espressif/qrcode:\n      version: \"^0.1.0\"\n  espressif/network_provisioning:\n      version: \"^1.0.0\"\n      override_path: '../../../'\n\n"
  },
  {
    "path": "network_provisioning/examples/thread_prov/partitions.csv",
    "content": "# Name,   Type, SubType, Offset,  Size, Flags\n# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap\nnvs,      data, nvs,     ,      0x6000,\nphy_init, data, phy,     ,      0x1000,\nfactory,  app,  factory, ,      0x180000,\n"
  },
  {
    "path": "network_provisioning/examples/thread_prov/sdkconfig.defaults",
    "content": "# Override some defaults so BT stack is enabled\nCONFIG_BT_ENABLED=y\nCONFIG_BT_NIMBLE_ENABLED=y\n\n## For Bluedroid as binary is larger than default size\nCONFIG_PARTITION_TABLE_CUSTOM=y\nCONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions.csv\"\nCONFIG_PARTITION_TABLE_FILENAME=\"partitions.csv\"\n\n# mbedTLS\nCONFIG_MBEDTLS_CMAC_C=y\nCONFIG_MBEDTLS_SSL_PROTO_DTLS=y\nCONFIG_MBEDTLS_KEY_EXCHANGE_ECJPAKE=y\nCONFIG_MBEDTLS_ECJPAKE_C=y\n\n# OpenThread\nCONFIG_OPENTHREAD_ENABLED=y\nCONFIG_OPENTHREAD_BORDER_ROUTER=n\nCONFIG_OPENTHREAD_DNS64_CLIENT=y\n\n# Network type\nCONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD=y\n\n# LwIP\nCONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096\nCONFIG_LWIP_IPV6_NUM_ADDRESSES=8\nCONFIG_LWIP_MULTICAST_PING=y\nCONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_CUSTOM=y\n\n# IEEE 802.15.4\nCONFIG_IEEE802154_ENABLED=y\n"
  },
  {
    "path": "network_provisioning/examples/thread_prov/sdkconfig.defaults.esp32",
    "content": "# ESP32 specific default configurations\n\nCONFIG_BTDM_CTRL_MODE_BLE_ONLY=y\nCONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n\nCONFIG_BTDM_CTRL_MODE_BTDM=n\n"
  },
  {
    "path": "network_provisioning/examples/wifi_prov/CMakeLists.txt",
    "content": "# The following lines of boilerplate have to be in your project's CMakeLists\n# in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(wifi_prov)\n"
  },
  {
    "path": "network_provisioning/examples/wifi_prov/README.md",
    "content": "| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-S2 | ESP32-S3 |\n| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |\n\n# Wi-Fi Provisioning Example\n\n(See the README.md file in the upper level 'examples' directory for more information about examples.)\n\n`wifi_prov` example demonstrates the usage of `network_provisioning` manager component for building a Wi-Fi provisioning application.\n\nFor this example, Bluetooth LE is chosen as the default mode of transport, over which the provisioning related communication is to take place. NimBLE has been configured as the default host, but you can also switch to Bluedroid using menuconfig -> Components -> Bluetooth -> Bluetooth Host.\n\n> Note: Since ESP32-S2 does not support Bluetooth LE, the SoftAP will be the default mode of transport in that case. Even for ESP32, you can change to SoftAP transport from menuconfig.\n\nIn the provisioning process the device is configured as a Wi-Fi station with specified credentials. Once configured, the device will retain the Wi-Fi configuration, until a flash erase is performed.\n\nRight after provisioning is complete, Bluetooth LE is turned off and disabled to free the memory used by the Bluetooth LE stack. Though, that is specific to this example, and the user can choose to keep Bluetooth LE stack intact in their own application.\n\n`wifi_prov` uses the following components :\n* `network_provisioning` : Provides provisioning manager, data structures and protocomm endpoint handlers for Wi-Fi configuration\n* `protocomm` : For protocol based communication and secure session establishment\n* `protobuf` : Google's protocol buffer library for serialization of protocomm data structures\n* `bt` : ESP-IDF's Bluetooth LE stack for transport of protobuf packets\n\nThis example can be used, as it is, for adding a provisioning service to any application intended for IoT.\n\n> Note: If you use this example code in your own project, in Bluetooth LE mode, then remember to enable the BT stack and BTDM BLE control settings in your SDK configuration (e.g. by using the `sdkconfig.defaults` file from this project).\n\n## How to use example\n\n### Hardware Required\n\nExample should be able to run on any commonly available ESP32/ESP32-C2/ESP32-C3/ESP32-C6/ESP32-S2/ESP32-S3 development board.\n\n### Script Required\n\nCurrently, Provisioning script is available for `Linux / Windows / macOS` platforms.\n\n#### Platform : Linux / Windows / macOS\n\nTo install the dependency packages needed, please refer to the ESP-IDF examples [README file](https://github.com/espressif/esp-idf/blob/master/examples/README.md#running-test-python-script-ttfw).\n\n`esp_prov` supports Bluetooth LE and SoftAP transport for Linux, MacOS and Windows platforms. For Bluetooth LE, however, if dependencies are not met, the script falls back to console mode and requires another application through which the communication can take place. The `esp_prov` console will guide you through the provisioning process of locating the correct Bluetooth LE GATT services and characteristics, the values to write, and input read values.\n\n### Configure the project\n\n```\nidf.py menuconfig\n```\n* Set the Bluetooth LE/Soft AP transport under \"Example Configuration\" options. ESP32-S2 will have only SoftAP option (SoftAP option cannot be used if IPv4 is disabled in lwIP)\n\n### Build and Flash\n\nBuild the project and flash it to the board, then run monitor tool to view serial output:\n\n```\nidf.py -p PORT flash monitor\n```\n\n(To exit the serial monitor, type ``Ctrl-]``.)\n\nSee the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.\n\n## Example Output\n\n```\nI (445) app: Starting provisioning\nI (1035) app: Provisioning started\nI (1045) network_prov_mgr: Provisioning started with service name : PROV_01B1E8\n```\n\nMake sure to note down the Bluetooth LE device name (starting with `PROV_`) displayed in the serial monitor log (eg. PROV_01B1E8). This will depend on the MAC ID and will be unique for every device.\n\nIn a separate terminal run the `esp_prov.py` script under [directory](../../tool/esp_prov) (make sure to replace `myssid` and `mypassword` with the credentials of the AP to which the device is supposed to connect to after provisioning). Assuming default example configuration, which uses the protocomm security version 2 with username and password authentication:\n\n```\npython esp_prov.py --transport ble --service_name PROV_01B1E8 --sec_ver 2 --sec2_username wifiprov --sec2_pwd abcd1234 --ssid myssid --passphrase mypassword\n```\n\nFor security scheme 1 with PoP-based (proof-of-possession) authentication, the following command can be used:\n```\npython esp_prov.py --transport ble --service_name PROV_01B1E8 --sec_ver 1 --pop abcd1234 --ssid myssid --passphrase mypassword\n```\n\nAbove command will perform the provisioning steps, and the monitor log should display something like this :\n\n```\nI (39725) app: Received Wi-Fi credentials\n    SSID     : myssid\n    Password : mypassword\n.\n.\n.\nI (45335) esp_netif_handlers: sta ip: 192.168.43.243, mask: 255.255.255.0, gw: 192.168.43.1\nI (45345) app: Provisioning successful\nI (45345) app: Connected with IP Address:192.168.43.243\nI (46355) app: Hello World!\nI (47355) app: Hello World!\nI (48355) app: Hello World!\nI (49355) app: Hello World!\n.\n.\n.\nI (52315) network_prov_mgr: Provisioning stopped\n.\n.\n.\nI (52355) app: Hello World!\nI (53355) app: Hello World!\nI (54355) app: Hello World!\nI (55355) app: Hello World!\n```\n\n**Note:** For generating the credentials for security version 2 (`SRP6a` salt and verifier) for the device-side, the following example command can be used. The output can then directly be used in this example.\n\nThe config option `CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE` should be enabled for the example and in `main/app_main.c`, the macro `EXAMPLE_PROV_SEC2_USERNAME` should be set to the same username used in the salt-verifier generation.\n\n```log\n$ python esp_prov.py --transport softap --sec_ver 2 --sec2_gen_cred --sec2_username wifiprov --sec2_pwd abcd1234\n==== Salt-verifier for security scheme 2 (SRP6a) ====\nstatic const char sec2_salt[] = {\n    0x03, 0x6e, 0xe0, 0xc7, 0xbc, 0xb9, 0xed, 0xa8, 0x4c, 0x9e, 0xac, 0x97, 0xd9, 0x3d, 0xec, 0xf4\n};\n\nstatic const char sec2_verifier[] = {\n    0x7c, 0x7c, 0x85, 0x47, 0x65, 0x08, 0x94, 0x6d, 0xd6, 0x36, 0xaf, 0x37, 0xd7, 0xe8, 0x91, 0x43,\n    0x78, 0xcf, 0xfd, 0x61, 0x6c, 0x59, 0xd2, 0xf8, 0x39, 0x08, 0x12, 0x72, 0x38, 0xde, 0x9e, 0x24,\n    .\n    .\n    .\n    0xe6, 0xf6, 0x53, 0xc8, 0x31, 0xa8, 0x78, 0xde, 0x50, 0x40, 0xf7, 0x62, 0xde, 0x36, 0xb2, 0xba\n};\n\n```\n\n### QR Code Scanning\n\nEnabling `CONFIG_EXAMPLE_PROV_SHOW_QR` will display a QR code on the serial terminal, which can be scanned from the ESP Provisioning phone apps to start the Wi-Fi provisioning process.\n\nThe monitor log should display something like this :\n\n```\nI (690) app: Provisioning started\nI (690) app: Scan this QR code from the provisioning application for Provisioning.\nI (700) QRCODE: Encoding below text with ECC LVL 0 & QR Code Version 10\nI (710) QRCODE: {\"ver\":\"v1\",\"name\":\"PROV_01B1E8\",\"username\":\"wifiprov\",\"pop\":\"abcd1234\",\"transport\":\"ble\",\"network\":\"wifi\"}\n\n  █▀▀▀▀▀█ ▄▀▀████▄██▀▀▀▀ ▀▄██▄ ▄▄▀  █▀▀▀▀▀█\n  █ ███ █ ▄▀ ▀▀▀▄ █▀▀▀█▀▄▀█▄█▄ ▄▀▀  █ ███ █\n  █ ▀▀▀ █ ▄█▄▀▄  █▄▀█ ▄ █▀▀ ▀▄███▀▀ █ ▀▀▀ █\n  ▀▀▀▀▀▀▀ ▀▄▀ █ ▀▄▀ ▀ ▀▄▀ █ █ █ █▄▀ ▀▀▀▀▀▀▀\n  ▀▀█▀▀ ▀█▀ ██▀▀ ▀▄▀ ▄▄ ▀█  ▀█▄██▄ █▄▀▄█ █▄\n   ▀  █▀▀██▄█▀▀ ▄█  ▀ ▀██  ▀ █▀ ▄ █▀▄▀█▄▀█\n  ▀▄ ▀▄ ▀█ ██ ▀ ▄█▄ ▀▀▄█ ▄▀▀▀▀█▀▄▄  ▄█▄ ▀ ▄\n  █▄▄█ ▄▀▀▀  █▀▀  ▄ ██▄█▄▄▀ ██▄▀█▄ █▄▄  ▀▄▄\n  ▀██▀█▄▀ █▄▀█▄█▄ ██ █▄ ▀▄▀█▄▀▀  █▄█▄▀▄▄▀▀▄\n  ▄▄▀▀▄ ▀▄▄▀▀ ▀█▀▀ █▄▄█ ▀▄▄▀▄█    ██ ▄▄█ ▀▄\n   █▀█▄▀▀ █▀  ▄▄▀█▀ ▄ ▀▀▀▄▀█ ▀█▀██▀▄▄▄▄███▄\n  █▄▀▄▀▀▀▀▄█  ▄▀ █▀▀█ ▀██ ▄  ██ █▄ ▄▀▀█  ▀▄\n  ▀▄█▀▀ ▀ ▀ ▄▄▀▀ ▀ ▀▄▄█▄▀█ ▀ ▀▀  ▄▄█▄█▄ ▀▀█\n  ▀ █▀▀█▀▄▀ ▄▄▄ ▄█▄ ▀▄ █▄  ▀ ▀█▀█ ▀ █ ▄ ▀█▄\n  █▀▀█▄▄▀█  ▄ ▀ ▄▄▄▄▀ ▄█▄▄▀▀▄ ▄▀█▄  ▄▄▄ ▀▀▄\n  █ ▄ █▀▀▄█▀▄█▀▀  ▄▀ █▄██▄ ▀ ▀▄▀█ ▄█▄ ▄▄▀ ▄\n  ▀ ▀ ▀ ▀▀█▄██▀█▀  █ █   ▄ █ ▄█▄▄ █▀▀▀█▀▀▀█\n  █▀▀▀▀▀█ ▀▀█▄██▀▀ █▄▄  ▀▄█▀ ▀▄ ▄██ ▀ █ ▀▀\n  █ ███ █ █▀▀ ▄ ▀█▀ ▄▀▀█▀▄ █ ▀▄██ █▀▀▀▀█▀█▄\n  █ ▀▀▀ █ █▄  ▄ ▄█▀▀▄ ▀▄ ▄█ ▀▀ ▀ ███▀ ▀▄ ▄\n  ▀▀▀▀▀▀▀ ▀▀▀ ▀▀▀▀ ▀▀ ▀   ▀▀ ▀▀  ▀ ▀▀  ▀▀\n\nI (1000) app: If QR code is not visible, copy paste the below URL in a browser.\nhttps://espressif.github.io/esp-jumpstart/qrcode.html?data={\"ver\":\"v1\",\"name\":\"PROV_01B1E8\",\"username\":\"wifiprov\",\"pop\":\"abcd1234\",\"transport\":\"ble\",\"network\":\"wifi\"}\n```\n\n### Wi-Fi Scanning\n\nProvisioning manager also supports providing real-time Wi-Fi scan results (performed on the device) during provisioning. This allows the client side applications to choose the AP for which the device Wi-Fi station is to be configured. Various information about the visible APs is available, like signal strength (RSSI) and security type, etc. Also, the manager now provides capabilities information which can be used by client applications to determine the security type and availability of specific features (like `wifi_scan`).\n\nWhen using the scan based provisioning, we don't need to specify the `--ssid` and `--passphrase` fields explicitly:\n\n```\npython esp_prov.py --transport ble --service_name PROV_01B1E8 --pop abcd1234\n```\n\nSee below the sample output from `esp_prov` tool on running above command:\n\n```\nConnecting...\nConnected\nGetting Services...\nSecurity scheme determined to be : 1\n\n==== Starting Session ====\n==== Session Established ====\n\n==== Scanning Wi-Fi APs ====\n++++ Scan process executed in 1.9967520237 sec\n++++ Scan results : 5\n\n++++ Scan finished in 2.7374596596 sec\n==== Wi-Fi Scan results ====\nS.N. SSID                              BSSID         CHN RSSI AUTH\n[ 1] MyHomeWiFiAP                      788a20841996    1 -45  WPA2_PSK\n[ 2] MobileHotspot                     7a8a20841996   11 -46  WPA2_PSK\n[ 3] MyHomeWiFiAP                      788a208daa26   11 -54  WPA2_PSK\n[ 4] NeighborsWiFiAP                   8a8a20841996    6 -61  WPA2_PSK\n[ 5] InsecureWiFiAP                    dca4caf1227c    7 -74  Open\n\nSelect AP by number (0 to rescan) : 1\nEnter passphrase for MyHomeWiFiAP :\n\n==== Sending Wi-Fi Credentials to Target ====\n==== Wi-Fi Credentials sent successfully ====\n\n==== Applying Wi-Fi Config to Target ====\n==== Apply config sent successfully ====\n\n==== Wi-Fi connection state  ====\n==== WiFi state: Connected ====\n==== Provisioning was successful ====\n```\n\n### Interactive Provisioning\n\n`esp_prov` supports interactive provisioning. You can trigger the script with a simplified command and input the necessary details\n(`Proof-of-possession` for security scheme 1 and `SRP6a username`, `SRP6a password` for security scheme 2) as the provisioning process advances.\n\nThe command `python esp_prov.py --transport ble --sec_ver 1` gives out the following sample output:\n\n```\nDiscovering...\n==== BLE Discovery results ====\nS.N. Name                              Address\n[ 1] PROV_4C33E8                       01:02:03:04:05:06\n[ 1] BT_DEVICE_SBC                     0A:0B:0C:0D:0E:0F\nSelect device by number (0 to rescan) : 1\nConnecting...\nGetting Services...\nProof of Possession required:\n\n==== Starting Session ====\n==== Session Established ====\n\n==== Scanning Wi-Fi APs ====\n++++ Scan process executed in 3.8695244789123535 sec\n++++ Scan results : 2\n\n++++ Scan finished in 4.4132080078125 sec\n==== Wi-Fi Scan results ====\nS.N. SSID                              BSSID         CHN RSSI AUTH\n[ 1] MyHomeWiFiAP                      788a20841996    1 -45  WPA2_PSK\n[ 2] MobileHotspot                     7a8a20841996   11 -46  WPA2_PSK\n\nSelect AP by number (0 to rescan) : 1\nEnter passphrase for myssid :\n\n==== Sending Wi-Fi Credentials to Target ====\n==== Wi-Fi Credentials sent successfully ====\n\n==== Applying Wi-Fi Config to Target ====\n==== Apply config sent successfully ====\n\n==== Wi-Fi connection state  ====\n==== WiFi state: Connected ====\n==== Provisioning was successful ====\n```\n\n### Sending Custom Data\n\nThe provisioning manager allows applications to send some custom data during provisioning, which may be\nrequired for some other operations like connecting to some cloud service. This is achieved by creating\nand registering additional endpoints using the below APIs\n\n```\nnetwork_prov_mgr_endpoint_create();\nnetwork_prov_mgr_endpoint_register();\n```\n\nIn this particular example, we have added an endpoint named \"custom-data\" which can be tested\nby passing the `--custom_data <MyCustomData>` option to the esp\\_prov tool. Following output is\nexpected on success:\n\n```\n==== Sending Custom data to esp32 ====\nCustomData response: SUCCESS\n```\n\n## Troubleshooting\n\n### Provisioning failed\n\nIt is possible that the Wi-Fi credentials provided were incorrect, or the device was not able to establish connection to the network, in which the the `esp_prov` script will notify failure (with reason). Serial monitor log will display the failure along with disconnect reason :\n\n```\nE (367015) app: Provisioning failed!\n    Reason : Wi-Fi AP password incorrect\n    Please reset to factory and retry provisioning\n```\n\nOnce credentials have been applied, even though wrong credentials were provided, the device will no longer go into provisioning mode on subsequent reboots until NVS is erased (see following section).\n\n### Provisioning does not start\n\nIf the serial monitor log shows the following :\n\n```\nI (465) app: Already provisioned, starting Wi-Fi STA\n```\n\nit means either the device has been provisioned earlier with or without success (e.g. scenario covered in above section), or that the Wi-Fi credentials were already set by some other application flashed previously onto your device. On setting the log level to DEBUG this is clearly evident :\n\n```\nD (455) network_prov_mgr: Found Wi-Fi SSID     : myssid\nD (465) network_prov_mgr: Found Wi-Fi Password : m********d\nI (465) app: Already provisioned, starting Wi-Fi STA\n```\n\nTo fix this we simple need to erase the NVS partition from flash. First we need to find out its address and size. This can be seen from the monitor log on the top right after reboot.\n\n```\nI (47) boot: Partition Table:\nI (50) boot: ## Label            Usage          Type ST Offset   Length\nI (58) boot:  0 nvs              WiFi data        01 02 00009000 00006000\nI (65) boot:  1 phy_init         RF data          01 01 0000f000 00001000\nI (73) boot:  2 factory          factory app      00 00 00010000 00124f80\nI (80) boot: End of partition table\n```\n\nNow erase NVS partition by running the following commands :\n\n```\n$IDF_PATH/components/esptool_py/esptool/esptool.py erase_region 0x9000 0x6000\n```\n\n### Bluetooth Pairing Request during provisioning\n\nESP-IDF now has functionality to enforce link encryption requirement while performing GATT write on characteristics of provisioning service. This will however result in a pairing pop-up dialog, if link is not encrypted. This feature is disabled by default. In order to enable this feature, please set `CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION=y` in the sdkconfig or select the configuration using \"idf.py menuconfig\" .\n\n```\nComponent Config --> Wi-Fi Provisioning Manager --> Force Link Encryption during Characteristic Read/Write\n\n```\nRecompiling the application with above changes should suffice to enable this functionality.\n\n\n### Unsupported platform\n\nIf the platform requirement, for running `esp_prov` is not satisfied, then the script execution will fallback to console mode, in which case the full process (involving user inputs) will look like this :\n\n```\n==== Esp_Prov Version: v1.0 ====\nBLE client is running in console mode\n    This could be due to your platform not being supported or dependencies not being met\n    Please ensure all pre-requisites are met to run the full fledged client\nBLECLI >> Please connect to BLE device `PROV_01B1E8` manually using your tool of choice\nBLECLI >> Was the device connected successfully? [y/n] y\nBLECLI >> List available attributes of the connected device\nBLECLI >> Is the service UUID '0000ffff-0000-1000-8000-00805f9b34fb' listed among available attributes? [y/n] y\nBLECLI >> Is the characteristic UUID '0000ff53-0000-1000-8000-00805f9b34fb' listed among available attributes? [y/n] y\nBLECLI >> Is the characteristic UUID '0000ff51-0000-1000-8000-00805f9b34fb' listed among available attributes? [y/n] y\nBLECLI >> Is the characteristic UUID '0000ff52-0000-1000-8000-00805f9b34fb' listed among available attributes? [y/n] y\n\n==== Verifying protocol version ====\nBLECLI >> Write following data to characteristic with UUID '0000ff53-0000-1000-8000-00805f9b34fb' :\n    >> 56302e31\nBLECLI >> Enter data read from characteristic (in hex) :\n    << 53554343455353\n==== Verified protocol version successfully ====\n\n==== Starting Session ====\nBLECLI >> Write following data to characteristic with UUID '0000ff51-0000-1000-8000-00805f9b34fb' :\n    >> 10015a25a201220a20ae6d9d5d1029f8c366892252d2d5a0ffa7ce1ee5829312545dd5f2aba057294d\nBLECLI >> Enter data read from characteristic (in hex) :\n    << 10015a390801aa0134122048008bfc365fad4753dc75912e0c764d60749cb26dd609595b6fbc72e12614031a1089733af233c7448e7d7fb7963682c6d8\nBLECLI >> Write following data to characteristic with UUID '0000ff51-0000-1000-8000-00805f9b34fb' :\n    >> 10015a270802b2012212204051088dc294fe4621fac934a8ea22e948fcc3e8ac458aac088ce705c65dbfb9\nBLECLI >> Enter data read from characteristic (in hex) :\n    << 10015a270803ba01221a20c8d38059d5206a3d92642973ac6ba8ac2f6ecf2b7a3632964eb35a0f20133adb\n==== Session Established ====\n\n==== Sending Wifi credential to esp32 ====\nBLECLI >> Write following data to characteristic with UUID '0000ff52-0000-1000-8000-00805f9b34fb' :\n    >> 98471ac4019a46765c28d87df8c8ae71c1ae6cfe0bc9c615bc6d2c\nBLECLI >> Enter data read from characteristic (in hex) :\n    << 3271f39a\n==== Wifi Credentials sent successfully ====\n\n==== Applying config to esp32 ====\nBLECLI >> Write following data to characteristic with UUID '0000ff52-0000-1000-8000-00805f9b34fb' :\n    >> 5355\nBLECLI >> Enter data read from characteristic (in hex) :\n    << 1664db24\n==== Apply config sent successfully ====\n\n==== Wifi connection state  ====\nBLECLI >> Write following data to characteristic with UUID '0000ff52-0000-1000-8000-00805f9b34fb' :\n    >> 290d\nBLECLI >> Enter data read from characteristic (in hex) :\n    << 505f72a9f8521025c1964d7789c4d7edc56aedebd144e1b667bc7c0975757b80cc091aa9f3e95b06eaefbc30290fa1\n++++ WiFi state: connected ++++\n==== Provisioning was successful ====\n```\n\nThe write data is to be copied from the console output ```>>``` to the platform specific application and the data read from the application is to be pasted at the user input prompt ```<<``` of the console, in the format (hex) indicated in above sample log.\n"
  },
  {
    "path": "network_provisioning/examples/wifi_prov/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"app_main.c\"\n                    INCLUDE_DIRS \".\")\n"
  },
  {
    "path": "network_provisioning/examples/wifi_prov/main/Kconfig.projbuild",
    "content": "menu \"Example Configuration\"\n\n    choice EXAMPLE_PROV_TRANSPORT\n        bool \"Provisioning Transport\"\n        default EXAMPLE_PROV_TRANSPORT_SOFTAP if IDF_TARGET_ESP32S2\n        default EXAMPLE_PROV_TRANSPORT_BLE\n        help\n            Wi-Fi provisioning component offers both, SoftAP and BLE transports. Choose any one.\n\n        config EXAMPLE_PROV_TRANSPORT_BLE\n            bool \"BLE\"\n            select BT_ENABLED\n            depends on !IDF_TARGET_ESP32S2\n        config EXAMPLE_PROV_TRANSPORT_SOFTAP\n            bool \"Soft AP\"\n            select LWIP_IPV4\n    endchoice\n\n    choice EXAMPLE_PROV_SECURITY_VERSION\n        bool \"Protocomm security version\"\n        default EXAMPLE_PROV_SECURITY_VERSION_2\n        help\n            Wi-Fi provisioning component offers 3 security versions.\n            The example offers a choice between security version 1 and 2.\n\n        config EXAMPLE_PROV_SECURITY_VERSION_1\n            bool \"Security version 1\"\n            select ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1\n\n        config EXAMPLE_PROV_SECURITY_VERSION_2\n            bool \"Security version 2\"\n            select ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2\n    endchoice\n\n    choice EXAMPLE_PROV_MODE\n        bool \"Security version 2 mode\"\n        depends on EXAMPLE_PROV_SECURITY_VERSION_2\n        default EXAMPLE_PROV_SEC2_DEV_MODE\n\n        config EXAMPLE_PROV_SEC2_DEV_MODE\n            bool \"Security version 2 development mode\"\n            depends on EXAMPLE_PROV_SECURITY_VERSION_2\n            help\n                This enables the development mode for\n                security version 2.\n                Please note that this mode is NOT recommended for production purpose.\n\n        config EXAMPLE_PROV_SEC2_PROD_MODE\n            bool \"Security version 2 production mode\"\n            depends on EXAMPLE_PROV_SECURITY_VERSION_2\n            help\n                This enables the production mode for\n                security version 2.\n    endchoice\n\n    config EXAMPLE_PROV_TRANSPORT\n        int\n        default 1 if EXAMPLE_PROV_TRANSPORT_BLE\n        default 2 if EXAMPLE_PROV_TRANSPORT_SOFTAP\n\n    config EXAMPLE_PROV_ENABLE_APP_CALLBACK\n        bool \"Enable provisioning manager app callback\"\n        default n\n        help\n            This is for advanced use-cases like modifying Wi-Fi configuration parameters. This\n            executes a blocking app callback when any provisioning event is triggered.\n\n    config EXAMPLE_RESET_PROVISIONED\n        bool\n        default n\n        prompt \"Reset provisioned status of the device\"\n        help\n            This erases the NVS to reset provisioned status of the device on every reboot.\n            Provisioned status is determined by the Wi-Fi STA configuration, saved on the NVS.\n\n    config EXAMPLE_RESET_PROV_MGR_ON_FAILURE\n        bool\n        default y\n        prompt \"Reset provisioned credentials and state machine after session failure\"\n        help\n            Enable resetting provisioned credentials and state machine after session failure.\n            This will restart the provisioning service after retries are exhausted.\n\n    config EXAMPLE_PROV_MGR_CONNECTION_CNT\n        int\n        default 5\n        prompt \"Max connection attempts before resetting provisioning state machine\"\n        depends on EXAMPLE_RESET_PROV_MGR_ON_FAILURE\n        help\n            Set the total number of connection attempts to avoid reconnecting to an inexistent AP or if credentials\n            are misconfigured. Provisioned credentials are erased and internal state machine\n            is reset after this threshold is reached.\n\n    config EXAMPLE_PROV_SHOW_QR\n        bool \"Show provisioning QR code\"\n        default y\n        help\n            Show the QR code for provisioning.\n\n    config EXAMPLE_PROV_USING_BLUEDROID\n        bool\n        depends on (BT_BLUEDROID_ENABLED && (IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3))\n        select BT_BLE_42_FEATURES_SUPPORTED\n        default y\n        help\n            This enables BLE 4.2 features for Bluedroid.\n\n    config EXAMPLE_REPROVISIONING\n        bool \"Re-provisioning\"\n        help\n            Enable re-provisioning - allow the device to provision for new credentials\n            after previous successful provisioning.\n\nendmenu\n"
  },
  {
    "path": "network_provisioning/examples/wifi_prov/main/app_main.c",
    "content": "/* Wi-Fi Provisioning Manager Example\n\n   This example code is in the Public Domain (or CC0 licensed, at your option.)\n\n   Unless required by applicable law or agreed to in writing, this\n   software is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n   CONDITIONS OF ANY KIND, either express or implied.\n*/\n\n#include <stdio.h>\n#include <string.h>\n\n#include <freertos/FreeRTOS.h>\n#include <freertos/task.h>\n#include <freertos/event_groups.h>\n\n#include <esp_log.h>\n#include <esp_wifi.h>\n#include <esp_event.h>\n#include <nvs_flash.h>\n\n#include <network_provisioning/manager.h>\n\n#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE\n#include <network_provisioning/scheme_ble.h>\n#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_BLE */\n\n#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP\n#include <network_provisioning/scheme_softap.h>\n#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP */\n#include \"qrcode.h\"\n\nstatic const char *TAG = \"app\";\n\n#if CONFIG_EXAMPLE_PROV_SECURITY_VERSION_2\n#if CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE\n#define EXAMPLE_PROV_SEC2_USERNAME          \"wifiprov\"\n#define EXAMPLE_PROV_SEC2_PWD               \"abcd1234\"\n\n/* This salt,verifier has been generated for username = \"wifiprov\" and password = \"abcd1234\"\n * IMPORTANT NOTE: For production cases, this must be unique to every device\n * and should come from device manufacturing partition.*/\nstatic const char sec2_salt[] = {\n    0x03, 0x6e, 0xe0, 0xc7, 0xbc, 0xb9, 0xed, 0xa8, 0x4c, 0x9e, 0xac, 0x97, 0xd9, 0x3d, 0xec, 0xf4\n};\n\nstatic const char sec2_verifier[] = {\n    0x7c, 0x7c, 0x85, 0x47, 0x65, 0x08, 0x94, 0x6d, 0xd6, 0x36, 0xaf, 0x37, 0xd7, 0xe8, 0x91, 0x43,\n    0x78, 0xcf, 0xfd, 0x61, 0x6c, 0x59, 0xd2, 0xf8, 0x39, 0x08, 0x12, 0x72, 0x38, 0xde, 0x9e, 0x24,\n    0xa4, 0x70, 0x26, 0x1c, 0xdf, 0xa9, 0x03, 0xc2, 0xb2, 0x70, 0xe7, 0xb1, 0x32, 0x24, 0xda, 0x11,\n    0x1d, 0x97, 0x18, 0xdc, 0x60, 0x72, 0x08, 0xcc, 0x9a, 0xc9, 0x0c, 0x48, 0x27, 0xe2, 0xae, 0x89,\n    0xaa, 0x16, 0x25, 0xb8, 0x04, 0xd2, 0x1a, 0x9b, 0x3a, 0x8f, 0x37, 0xf6, 0xe4, 0x3a, 0x71, 0x2e,\n    0xe1, 0x27, 0x86, 0x6e, 0xad, 0xce, 0x28, 0xff, 0x54, 0x46, 0x60, 0x1f, 0xb9, 0x96, 0x87, 0xdc,\n    0x57, 0x40, 0xa7, 0xd4, 0x6c, 0xc9, 0x77, 0x54, 0xdc, 0x16, 0x82, 0xf0, 0xed, 0x35, 0x6a, 0xc4,\n    0x70, 0xad, 0x3d, 0x90, 0xb5, 0x81, 0x94, 0x70, 0xd7, 0xbc, 0x65, 0xb2, 0xd5, 0x18, 0xe0, 0x2e,\n    0xc3, 0xa5, 0xf9, 0x68, 0xdd, 0x64, 0x7b, 0xb8, 0xb7, 0x3c, 0x9c, 0xfc, 0x00, 0xd8, 0x71, 0x7e,\n    0xb7, 0x9a, 0x7c, 0xb1, 0xb7, 0xc2, 0xc3, 0x18, 0x34, 0x29, 0x32, 0x43, 0x3e, 0x00, 0x99, 0xe9,\n    0x82, 0x94, 0xe3, 0xd8, 0x2a, 0xb0, 0x96, 0x29, 0xb7, 0xdf, 0x0e, 0x5f, 0x08, 0x33, 0x40, 0x76,\n    0x52, 0x91, 0x32, 0x00, 0x9f, 0x97, 0x2c, 0x89, 0x6c, 0x39, 0x1e, 0xc8, 0x28, 0x05, 0x44, 0x17,\n    0x3f, 0x68, 0x02, 0x8a, 0x9f, 0x44, 0x61, 0xd1, 0xf5, 0xa1, 0x7e, 0x5a, 0x70, 0xd2, 0xc7, 0x23,\n    0x81, 0xcb, 0x38, 0x68, 0xe4, 0x2c, 0x20, 0xbc, 0x40, 0x57, 0x76, 0x17, 0xbd, 0x08, 0xb8, 0x96,\n    0xbc, 0x26, 0xeb, 0x32, 0x46, 0x69, 0x35, 0x05, 0x8c, 0x15, 0x70, 0xd9, 0x1b, 0xe9, 0xbe, 0xcc,\n    0xa9, 0x38, 0xa6, 0x67, 0xf0, 0xad, 0x50, 0x13, 0x19, 0x72, 0x64, 0xbf, 0x52, 0xc2, 0x34, 0xe2,\n    0x1b, 0x11, 0x79, 0x74, 0x72, 0xbd, 0x34, 0x5b, 0xb1, 0xe2, 0xfd, 0x66, 0x73, 0xfe, 0x71, 0x64,\n    0x74, 0xd0, 0x4e, 0xbc, 0x51, 0x24, 0x19, 0x40, 0x87, 0x0e, 0x92, 0x40, 0xe6, 0x21, 0xe7, 0x2d,\n    0x4e, 0x37, 0x76, 0x2f, 0x2e, 0xe2, 0x68, 0xc7, 0x89, 0xe8, 0x32, 0x13, 0x42, 0x06, 0x84, 0x84,\n    0x53, 0x4a, 0xb3, 0x0c, 0x1b, 0x4c, 0x8d, 0x1c, 0x51, 0x97, 0x19, 0xab, 0xae, 0x77, 0xff, 0xdb,\n    0xec, 0xf0, 0x10, 0x95, 0x34, 0x33, 0x6b, 0xcb, 0x3e, 0x84, 0x0f, 0xb9, 0xd8, 0x5f, 0xb8, 0xa0,\n    0xb8, 0x55, 0x53, 0x3e, 0x70, 0xf7, 0x18, 0xf5, 0xce, 0x7b, 0x4e, 0xbf, 0x27, 0xce, 0xce, 0xa8,\n    0xb3, 0xbe, 0x40, 0xc5, 0xc5, 0x32, 0x29, 0x3e, 0x71, 0x64, 0x9e, 0xde, 0x8c, 0xf6, 0x75, 0xa1,\n    0xe6, 0xf6, 0x53, 0xc8, 0x31, 0xa8, 0x78, 0xde, 0x50, 0x40, 0xf7, 0x62, 0xde, 0x36, 0xb2, 0xba\n};\n#endif\n\nstatic esp_err_t example_get_sec2_salt(const char **salt, uint16_t *salt_len)\n{\n#if CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE\n    ESP_LOGI(TAG, \"Development mode: using hard coded salt\");\n    *salt = sec2_salt;\n    *salt_len = sizeof(sec2_salt);\n    return ESP_OK;\n#elif CONFIG_EXAMPLE_PROV_SEC2_PROD_MODE\n    ESP_LOGE(TAG, \"Not implemented!\");\n    return ESP_FAIL;\n#endif\n}\n\nstatic esp_err_t example_get_sec2_verifier(const char **verifier, uint16_t *verifier_len)\n{\n#if CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE\n    ESP_LOGI(TAG, \"Development mode: using hard coded verifier\");\n    *verifier = sec2_verifier;\n    *verifier_len = sizeof(sec2_verifier);\n    return ESP_OK;\n#elif CONFIG_EXAMPLE_PROV_SEC2_PROD_MODE\n    /* This code needs to be updated with appropriate implementation to provide verifier */\n    ESP_LOGE(TAG, \"Not implemented!\");\n    return ESP_FAIL;\n#endif\n}\n#endif\n\n/* Signal Wi-Fi events on this event-group */\nconst int WIFI_CONNECTED_EVENT = BIT0;\nstatic EventGroupHandle_t wifi_event_group;\n\n#define PROV_QR_VERSION         \"v1\"\n#define PROV_TRANSPORT_SOFTAP   \"softap\"\n#define PROV_TRANSPORT_BLE      \"ble\"\n#define QRCODE_BASE_URL         \"https://espressif.github.io/esp-jumpstart/qrcode.html\"\n\n/* Event handler for catching system events */\nstatic void event_handler(void *arg, esp_event_base_t event_base,\n                          int32_t event_id, void *event_data)\n{\n    if (event_base == NETWORK_PROV_EVENT) {\n        switch (event_id) {\n        case NETWORK_PROV_START:\n            ESP_LOGI(TAG, \"Provisioning started\");\n            break;\n        case NETWORK_PROV_WIFI_CRED_RECV: {\n            wifi_sta_config_t *wifi_sta_cfg = (wifi_sta_config_t *)event_data;\n            ESP_LOGI(TAG, \"Received Wi-Fi credentials\"\n                     \"\\n\\tSSID     : %s\\n\\tPassword : %s\",\n                     (const char *) wifi_sta_cfg->ssid,\n                     (const char *) wifi_sta_cfg->password);\n            break;\n        }\n        case NETWORK_PROV_WIFI_CRED_FAIL: {\n            network_prov_wifi_sta_fail_reason_t *reason = (network_prov_wifi_sta_fail_reason_t *)event_data;\n            ESP_LOGE(TAG, \"Provisioning failed!\\n\\tReason : %s\"\n                     \"\\n\\tPlease reset to factory and retry provisioning\",\n                     (*reason == NETWORK_PROV_WIFI_STA_AUTH_ERROR) ?\n                     \"Wi-Fi station authentication failed\" : \"Wi-Fi access-point not found\");\n#ifdef CONFIG_EXAMPLE_RESET_PROV_MGR_ON_FAILURE\n            /* Reset the state machine on provisioning failure.\n             * This is enabled by the CONFIG_EXAMPLE_RESET_PROV_MGR_ON_FAILURE configuration.\n             * It allows the provisioning manager to retry the provisioning process\n             * based on the number of attempts specified in wifi_conn_attempts. After attempting\n             * the maximum number of retries, the provisioning manager will reset the state machine\n             * and the provisioning process will be terminated.\n             */\n            network_prov_mgr_reset_wifi_sm_state_on_failure();\n#endif\n            break;\n        }\n        case NETWORK_PROV_WIFI_CRED_SUCCESS:\n            ESP_LOGI(TAG, \"Provisioning successful\");\n            break;\n        case NETWORK_PROV_END:\n            /* De-initialize manager once provisioning is finished */\n            esp_err_t err = network_prov_mgr_deinit();\n            if (err != ESP_OK) {\n                ESP_LOGE(TAG, \"Failed to de-initialize provisioning manager: %s\", esp_err_to_name(err));\n            }\n            break;\n        default:\n            break;\n        }\n    } else if (event_base == WIFI_EVENT) {\n        switch (event_id) {\n        case WIFI_EVENT_STA_START:\n            esp_wifi_connect();\n            break;\n        case WIFI_EVENT_STA_DISCONNECTED:\n            ESP_LOGI(TAG, \"Disconnected. Connecting to the AP again...\");\n            esp_wifi_connect();\n            break;\n#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP\n        case WIFI_EVENT_AP_STACONNECTED:\n            ESP_LOGI(TAG, \"SoftAP transport: Connected!\");\n            break;\n        case WIFI_EVENT_AP_STADISCONNECTED:\n            ESP_LOGI(TAG, \"SoftAP transport: Disconnected!\");\n            break;\n#endif\n        default:\n            break;\n        }\n    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {\n        ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;\n        ESP_LOGI(TAG, \"Connected with IP Address:\" IPSTR, IP2STR(&event->ip_info.ip));\n        /* Signal main application to continue execution */\n        xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_EVENT);\n#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE\n    } else if (event_base == PROTOCOMM_TRANSPORT_BLE_EVENT) {\n        switch (event_id) {\n        case PROTOCOMM_TRANSPORT_BLE_CONNECTED:\n            ESP_LOGI(TAG, \"BLE transport: Connected!\");\n            break;\n        case PROTOCOMM_TRANSPORT_BLE_DISCONNECTED:\n            ESP_LOGI(TAG, \"BLE transport: Disconnected!\");\n            break;\n        default:\n            break;\n        }\n#endif\n    } else if (event_base == PROTOCOMM_SECURITY_SESSION_EVENT) {\n        switch (event_id) {\n        case PROTOCOMM_SECURITY_SESSION_SETUP_OK:\n            ESP_LOGI(TAG, \"Secured session established!\");\n            break;\n        case PROTOCOMM_SECURITY_SESSION_INVALID_SECURITY_PARAMS:\n            ESP_LOGE(TAG, \"Received invalid security parameters for establishing secure session!\");\n            break;\n        case PROTOCOMM_SECURITY_SESSION_CREDENTIALS_MISMATCH:\n            ESP_LOGE(TAG, \"Received incorrect username and/or PoP for establishing secure session!\");\n            break;\n        default:\n            break;\n        }\n    }\n}\n\nstatic void wifi_init_sta(void)\n{\n    /* Start Wi-Fi in station mode */\n    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));\n    ESP_ERROR_CHECK(esp_wifi_start());\n}\n\nstatic void get_device_service_name(char *service_name, size_t max)\n{\n    uint8_t eth_mac[6];\n    const char *ssid_prefix = \"PROV_\";\n    esp_wifi_get_mac(WIFI_IF_STA, eth_mac);\n    snprintf(service_name, max, \"%s%02X%02X%02X\",\n             ssid_prefix, eth_mac[3], eth_mac[4], eth_mac[5]);\n}\n\n/* Handler for the optional provisioning endpoint registered by the application.\n * The data format can be chosen by applications. Here, we are using plain ascii text.\n * Applications can choose to use other formats like protobuf, JSON, XML, etc.\n * Note that memory for the response buffer must be allocated using heap as this buffer\n * gets freed by the protocomm layer once it has been sent by the transport layer.\n */\nesp_err_t custom_prov_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,\n                                   uint8_t **outbuf, ssize_t *outlen, void *priv_data)\n{\n    if (inbuf) {\n        ESP_LOGI(TAG, \"Received data: %.*s\", inlen, (char *)inbuf);\n    }\n    char response[] = \"SUCCESS\";\n    *outbuf = (uint8_t *)strdup(response);\n    if (*outbuf == NULL) {\n        ESP_LOGE(TAG, \"System out of memory\");\n        return ESP_ERR_NO_MEM;\n    }\n    *outlen = strlen(response) + 1; /* +1 for NULL terminating byte */\n\n    return ESP_OK;\n}\n\nstatic void wifi_prov_print_qr(const char *name, const char *username, const char *pop, const char *transport)\n{\n    if (!name || !transport) {\n        ESP_LOGW(TAG, \"Cannot generate QR code payload. Data missing.\");\n        return;\n    }\n    char payload[150] = {0};\n    if (pop) {\n#if CONFIG_EXAMPLE_PROV_SECURITY_VERSION_1\n        snprintf(payload, sizeof(payload), \"{\\\"ver\\\":\\\"%s\\\",\\\"name\\\":\\\"%s\\\"\" \\\n                 \",\\\"pop\\\":\\\"%s\\\",\\\"transport\\\":\\\"%s\\\"}\",\n                 PROV_QR_VERSION, name, pop, transport);\n#elif CONFIG_EXAMPLE_PROV_SECURITY_VERSION_2\n        snprintf(payload, sizeof(payload), \"{\\\"ver\\\":\\\"%s\\\",\\\"name\\\":\\\"%s\\\"\" \\\n                 \",\\\"username\\\":\\\"%s\\\",\\\"pop\\\":\\\"%s\\\",\\\"transport\\\":\\\"%s\\\"}\",\n                 PROV_QR_VERSION, name, username, pop, transport);\n#endif\n    } else {\n        snprintf(payload, sizeof(payload), \"{\\\"ver\\\":\\\"%s\\\",\\\"name\\\":\\\"%s\\\"\" \\\n                 \",\\\"transport\\\":\\\"%s\\\",\\\"network\\\":\\\"wifi\\\"}\",\n                 PROV_QR_VERSION, name, transport);\n    }\n    //TODO: Add the network protocol type to the QR code payload\n#ifdef CONFIG_EXAMPLE_PROV_SHOW_QR\n    ESP_LOGI(TAG, \"Scan this QR code from the provisioning application for Provisioning.\");\n    esp_qrcode_config_t cfg = ESP_QRCODE_CONFIG_DEFAULT();\n    esp_qrcode_generate(&cfg, payload);\n#endif /* CONFIG_EXAMPLE_PROV_SHOW_QR */\n    ESP_LOGI(TAG, \"If QR code is not visible, copy paste the below URL in a browser.\\n%s?data=%s\", QRCODE_BASE_URL, payload);\n}\n\n#ifdef CONFIG_EXAMPLE_PROV_ENABLE_APP_CALLBACK\nvoid wifi_prov_app_callback(void *user_data, wifi_prov_cb_event_t event, void *event_data)\n{\n    /**\n     * This is blocking callback, any configurations that needs to be set when a particular\n     * provisioning event is triggered can be set here.\n    */\n    switch (event) {\n    case WIFI_PROV_SET_STA_CONFIG: {\n        /**\n         * Wi-Fi configurations can be set here before the Wi-Fi is enabled in\n         * STA mode.\n        */\n        wifi_config_t *wifi_config = (wifi_config_t *)event_data;\n        (void) wifi_config;\n        break;\n    }\n    default:\n        break;\n    }\n}\n\nconst wifi_prov_event_handler_t wifi_prov_event_handler = {\n    .event_cb = wifi_prov_app_callback,\n    .user_data = NULL,\n};\n#endif /* EXAMPLE_PROV_ENABLE_APP_CALLBACK */\n\nvoid app_main(void)\n{\n    /* Initialize NVS partition */\n    esp_err_t ret = nvs_flash_init();\n    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {\n        /* NVS partition was truncated\n         * and needs to be erased */\n        ESP_ERROR_CHECK(nvs_flash_erase());\n\n        /* Retry nvs_flash_init */\n        ESP_ERROR_CHECK(nvs_flash_init());\n    }\n\n    /* Initialize TCP/IP */\n    ESP_ERROR_CHECK(esp_netif_init());\n\n    /* Initialize the event loop */\n    ESP_ERROR_CHECK(esp_event_loop_create_default());\n    wifi_event_group = xEventGroupCreate();\n\n    /* Register our event handler for Wi-Fi, IP and Provisioning related events */\n    ESP_ERROR_CHECK(esp_event_handler_register(NETWORK_PROV_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));\n#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE\n    ESP_ERROR_CHECK(esp_event_handler_register(PROTOCOMM_TRANSPORT_BLE_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));\n#endif\n    ESP_ERROR_CHECK(esp_event_handler_register(PROTOCOMM_SECURITY_SESSION_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));\n    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));\n\n    /* Initialize Wi-Fi including netif with default config */\n    esp_netif_create_default_wifi_sta();\n#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP\n    esp_netif_create_default_wifi_ap();\n#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP */\n    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();\n    ESP_ERROR_CHECK(esp_wifi_init(&cfg));\n\n    /* Configuration for the provisioning manager */\n    network_prov_mgr_config_t config = {\n#ifdef CONFIG_EXAMPLE_RESET_PROV_MGR_ON_FAILURE\n        .network_prov_wifi_conn_cfg = {\n            .wifi_conn_attempts =  CONFIG_EXAMPLE_PROV_MGR_CONNECTION_CNT,\n        },\n#endif\n        /* What is the Provisioning Scheme that we want ?\n         * network_prov_scheme_softap or network_prov_scheme_ble */\n#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE\n        .scheme = network_prov_scheme_ble,\n#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_BLE */\n#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP\n        .scheme = network_prov_scheme_softap,\n#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP */\n#ifdef CONFIG_EXAMPLE_PROV_ENABLE_APP_CALLBACK\n        .app_event_handler = wifi_prov_event_handler,\n#endif /* EXAMPLE_PROV_ENABLE_APP_CALLBACK */\n\n        /* Any default scheme specific event handler that you would\n         * like to choose. Since our example application requires\n         * neither BT nor BLE, we can choose to release the associated\n         * memory once provisioning is complete, or not needed\n         * (in case when device is already provisioned). Choosing\n         * appropriate scheme specific event handler allows the manager\n         * to take care of this automatically. This can be set to\n         * NETWORK_PROV_EVENT_HANDLER_NONE when using network_prov_scheme_softap*/\n#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE\n        .scheme_event_handler = NETWORK_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM\n#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_BLE */\n#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP\n        .scheme_event_handler = NETWORK_PROV_EVENT_HANDLER_NONE\n#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP */\n    };\n\n    /* Initialize provisioning manager with the\n     * configuration parameters set above */\n    ESP_ERROR_CHECK(network_prov_mgr_init(config));\n\n    bool provisioned = false;\n#ifdef CONFIG_EXAMPLE_RESET_PROVISIONED\n    network_prov_mgr_reset_wifi_provisioning();\n#else\n    /* Let's find out if the device is provisioned */\n    ESP_ERROR_CHECK(network_prov_mgr_is_wifi_provisioned(&provisioned));\n\n#endif\n    /* If device is not yet provisioned start provisioning service */\n    if (!provisioned) {\n        ESP_LOGI(TAG, \"Starting provisioning\");\n\n        /* What is the Device Service Name that we want\n         * This translates to :\n         *     - Wi-Fi SSID when scheme is network_prov_scheme_softap\n         *     - device name when scheme is network_prov_scheme_ble\n         */\n        char service_name[12];\n        get_device_service_name(service_name, sizeof(service_name));\n\n#ifdef CONFIG_EXAMPLE_PROV_SECURITY_VERSION_1\n        /* What is the security level that we want (0, 1, 2):\n         *      - NETWORK_PROV_SECURITY_0 is simply plain text communication.\n         *      - NETWORK_PROV_SECURITY_1 is secure communication which consists of secure handshake\n         *          using X25519 key exchange and proof of possession (pop) and AES-CTR\n         *          for encryption/decryption of messages.\n         *      - NETWORK_PROV_SECURITY_2 SRP6a based authentication and key exchange\n         *        + AES-GCM encryption/decryption of messages\n         */\n        network_prov_security_t security = NETWORK_PROV_SECURITY_1;\n\n        /* Do we want a proof-of-possession (ignored if Security 0 is selected):\n         *      - this should be a string with length > 0\n         *      - NULL if not used\n         */\n        const char *pop = \"abcd1234\";\n\n        /* This is the structure for passing security parameters\n         * for the protocomm security 1.\n         */\n        network_prov_security1_params_t *sec_params = pop;\n\n        const char *username  = NULL;\n\n#elif CONFIG_EXAMPLE_PROV_SECURITY_VERSION_2\n        network_prov_security_t security = NETWORK_PROV_SECURITY_2;\n        /* The username must be the same one, which has been used in the generation of salt and verifier */\n\n#if CONFIG_EXAMPLE_PROV_SEC2_DEV_MODE\n        /* This pop field represents the password that will be used to generate salt and verifier.\n         * The field is present here in order to generate the QR code containing password.\n         * In production this password field shall not be stored on the device */\n        const char *username  = EXAMPLE_PROV_SEC2_USERNAME;\n        const char *pop = EXAMPLE_PROV_SEC2_PWD;\n#elif CONFIG_EXAMPLE_PROV_SEC2_PROD_MODE\n        /* The username and password shall not be embedded in the firmware,\n         * they should be provided to the user by other means.\n         * e.g. QR code sticker */\n        const char *username  = NULL;\n        const char *pop = NULL;\n#endif\n        /* This is the structure for passing security parameters\n         * for the protocomm security 2.\n         * If dynamically allocated, sec2_params pointer and its content\n         * must be valid till NETWORK_PROV_END event is triggered.\n         */\n        network_prov_security2_params_t sec2_params = {};\n\n        ESP_ERROR_CHECK(example_get_sec2_salt(&sec2_params.salt, &sec2_params.salt_len));\n        ESP_ERROR_CHECK(example_get_sec2_verifier(&sec2_params.verifier, &sec2_params.verifier_len));\n\n        network_prov_security2_params_t *sec_params = &sec2_params;\n#endif\n        /* What is the service key (could be NULL)\n         * This translates to :\n         *     - Wi-Fi password when scheme is network_prov_scheme_softap\n         *          (Minimum expected length: 8, maximum 64 for WPA2-PSK)\n         *     - simply ignored when scheme is network_prov_scheme_ble\n         */\n        const char *service_key = NULL;\n\n#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE\n        /* This step is only useful when scheme is network_prov_scheme_ble. This will\n         * set a custom 128 bit UUID which will be included in the BLE advertisement\n         * and will correspond to the primary GATT service that provides provisioning\n         * endpoints as GATT characteristics. Each GATT characteristic will be\n         * formed using the primary service UUID as base, with different auto assigned\n         * 12th and 13th bytes (assume counting starts from 0th byte). The client side\n         * applications must identify the endpoints by reading the User Characteristic\n         * Description descriptor (0x2901) for each characteristic, which contains the\n         * endpoint name of the characteristic */\n        uint8_t custom_service_uuid[] = {\n            /* LSB <---------------------------------------\n             * ---------------------------------------> MSB */\n            0xb4, 0xdf, 0x5a, 0x1c, 0x3f, 0x6b, 0xf4, 0xbf,\n            0xea, 0x4a, 0x82, 0x03, 0x04, 0x90, 0x1a, 0x02,\n        };\n\n        /* If your build fails with linker errors at this point, then you may have\n         * forgotten to enable the BT stack or BTDM BLE settings in the SDK (e.g. see\n         * the sdkconfig.defaults in the example project) */\n        network_prov_scheme_ble_set_service_uuid(custom_service_uuid);\n#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_BLE */\n\n        /* An optional endpoint that applications can create if they expect to\n         * get some additional custom data during provisioning workflow.\n         * The endpoint name can be anything of your choice.\n         * This call must be made before starting the provisioning.\n         */\n        network_prov_mgr_endpoint_create(\"custom-data\");\n\n        /* Do not stop and de-init provisioning even after success,\n         * so that we can restart it later. */\n#ifdef CONFIG_EXAMPLE_REPROVISIONING\n        network_prov_mgr_disable_auto_stop(1000);\n#endif\n        /* Start provisioning service */\n        ESP_ERROR_CHECK(network_prov_mgr_start_provisioning(security, (const void *) sec_params, service_name, service_key));\n\n        /* The handler for the optional endpoint created above.\n         * This call must be made after starting the provisioning, and only if the endpoint\n         * has already been created above.\n         */\n        network_prov_mgr_endpoint_register(\"custom-data\", custom_prov_data_handler, NULL);\n\n        /* Uncomment the following to wait for the provisioning to finish and then release\n         * the resources of the manager. Since in this case de-initialization is triggered\n         * by the default event loop handler, we don't need to call the following */\n        // network_prov_mgr_wait();\n        // network_prov_mgr_deinit();\n        /* Print QR code for provisioning */\n#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE\n        wifi_prov_print_qr(service_name, username, pop, PROV_TRANSPORT_BLE);\n#else /* CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP */\n        wifi_prov_print_qr(service_name, username, pop, PROV_TRANSPORT_SOFTAP);\n#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_BLE */\n    } else {\n        ESP_LOGI(TAG, \"Already provisioned, starting Wi-Fi STA\");\n\n        /* We don't need the manager as device is already provisioned,\n         * so let's release it's resources */\n        ESP_ERROR_CHECK(network_prov_mgr_deinit());\n\n        ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));\n        /* Start Wi-Fi station */\n        wifi_init_sta();\n    }\n\n    /* Wait for Wi-Fi connection */\n    xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_EVENT, true, true, portMAX_DELAY);\n\n    /* Start main application now */\n#if CONFIG_EXAMPLE_REPROVISIONING\n    while (1) {\n        for (int i = 0; i < 10; i++) {\n            ESP_LOGI(TAG, \"Hello World!\");\n            vTaskDelay(1000 / portTICK_PERIOD_MS);\n        }\n\n        /* Resetting provisioning state machine to enable re-provisioning */\n        network_prov_mgr_reset_wifi_sm_state_for_reprovision();\n\n        /* Wait for Wi-Fi connection */\n        xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_EVENT, true, true, portMAX_DELAY);\n    }\n#else\n    while (1) {\n        ESP_LOGI(TAG, \"Hello World!\");\n        vTaskDelay(1000 / portTICK_PERIOD_MS);\n    }\n#endif\n\n}\n"
  },
  {
    "path": "network_provisioning/examples/wifi_prov/main/idf_component.yml",
    "content": "version: \"1.0.0\"\ndependencies:\n  espressif/qrcode:\n      version: \"^0.1.0\"\n  espressif/network_provisioning:\n      version: \"*\"\n      override_path: '../../../'\n\n"
  },
  {
    "path": "network_provisioning/examples/wifi_prov/partitions.csv",
    "content": "# Name,   Type, SubType, Offset,  Size, Flags\n# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap\nnvs,      data, nvs,     ,      0x6000,\nphy_init, data, phy,     ,      0x1000,\nfactory,  app,  factory, ,      0x180000,\n"
  },
  {
    "path": "network_provisioning/examples/wifi_prov/sdkconfig.defaults",
    "content": "# Override some defaults so BT stack is enabled\nCONFIG_BT_ENABLED=y\nCONFIG_BT_NIMBLE_ENABLED=y\n\n## For Bluedroid as binary is larger than default size\nCONFIG_PARTITION_TABLE_CUSTOM=y\nCONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions.csv\"\nCONFIG_PARTITION_TABLE_FILENAME=\"partitions.csv\"\n"
  },
  {
    "path": "network_provisioning/examples/wifi_prov/sdkconfig.defaults.esp32",
    "content": "# ESP32 specific default configurations\n\nCONFIG_BTDM_CTRL_MODE_BLE_ONLY=y\nCONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n\nCONFIG_BTDM_CTRL_MODE_BTDM=n\n"
  },
  {
    "path": "network_provisioning/idf_component.yml",
    "content": "version: \"1.2.4\"\ndescription: Network provisioning component for Wi-Fi or Thread devices\nurl: https://github.com/espressif/idf-extra-components/tree/master/network_provisioning\ndependencies:\n    idf: \">=5.1\"\n    espressif/cjson:\n      version: \"^1.7.19\"\n      override_path: \"../cjson\"\n      rules:\n        - if: \"idf_version >= 6.0\"\n"
  },
  {
    "path": "network_provisioning/include/network_provisioning/manager.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include <protocomm.h>\n\n#include \"esp_event.h\"\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n#include \"esp_wifi_types.h\"\n#endif\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n#include \"openthread/dataset.h\"\n#endif\n#include \"network_provisioning/network_config.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nESP_EVENT_DECLARE_BASE(NETWORK_PROV_EVENT);\n\n/**\n * @brief   Events generated by manager\n *\n * These events are generated in order of declaration and, for the\n * stretch of time between initialization and de-initialization of\n * the manager, each event is signaled only once\n */\ntypedef enum {\n    /**\n     * Emitted when the manager is initialized\n     */\n    NETWORK_PROV_INIT,\n\n    /**\n     * Indicates that provisioning has started\n     */\n    NETWORK_PROV_START,\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    /**\n     * Emitted before accepting the wifi credentials to\n     * set the wifi configurations according to requirement.\n     * NOTE - In this case event_data shall be populated with a pointer to `wifi_config_t`.\n     */\n    NETWORK_PROV_SET_WIFI_STA_CONFIG,\n\n    /**\n     * Emitted when Wi-Fi AP credentials are received via `protocomm`\n     * endpoint `network_config`. The event data in this case is a pointer\n     * to the corresponding `wifi_sta_config_t` structure\n     */\n    NETWORK_PROV_WIFI_CRED_RECV,\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    /**\n     * Emitted when Thread Dataset is received via `protocomm` endpoint\n     * `network_config`, The event data in this case is a pointer to the\n     * corresponding `otOperationalDatasetTlvs` structure\n     */\n    NETWORK_PROV_THREAD_DATASET_RECV,\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    /**\n     * Emitted when device fails to connect to the AP of which the\n     * credentials were received earlier on event `NETWORK_PROV_WIFI_CRED_RECV`.\n     * The event data in this case is a pointer to the disconnection\n     * reason code with type `network_prov_wifi_sta_fail_reason_t`\n     */\n    NETWORK_PROV_WIFI_CRED_FAIL,\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    /**\n     * Emitted when device fails to connect to the Thread network of which\n     * dataset was received earlier on event `NETWORK_PROv_THREAD_DATASET_RECV`.\n     * The event data in this case is a pointer to the disconnection\n     * reason code with type `network_prov_thread_fail_reason_t`\n     */\n    NETWORK_PROV_THREAD_DATASET_FAIL,\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    /**\n     * Emitted when device successfully connects to the AP of which the\n     * credentials were received earlier on event `NETWORK_PROV_WIFI_CRED_RECV`\n     */\n    NETWORK_PROV_WIFI_CRED_SUCCESS,\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    /**\n     * Emitted when device successfully connects to the Thread etwork of\n     * which the dataset was received earlier on event\n     * `NETWORK_PROV_THREAD_DATASET_RECV`\n     */\n    NETWORK_PROV_THREAD_DATASET_SUCCESS,\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n\n    /**\n     * Signals that provisioning service has stopped\n     */\n    NETWORK_PROV_END,\n\n    /**\n     * Signals that manager has been de-initialized\n     */\n    NETWORK_PROV_DEINIT,\n} network_prov_cb_event_t;\n\ntypedef void (*network_prov_cb_func_t)(void *user_data, network_prov_cb_event_t event, void *event_data);\n\n/**\n * @brief   Event handler that is used by the manager while\n *          provisioning service is active\n */\ntypedef struct {\n    /**\n     * Callback function to be executed on provisioning events\n     */\n    network_prov_cb_func_t event_cb;\n\n    /**\n     * User context data to pass as parameter to callback function\n     */\n    void *user_data;\n} network_prov_event_handler_t;\n\n/**\n * @brief   Structure holding the configuration related to Wi-Fi provisioning\n */\ntypedef struct {\n    /**\n     * Maximum number of allowed connection attempts for Wi-Fi. If value 0\n     * same as legacy behavior of infinite connection attempts.\n     */\n    uint32_t wifi_conn_attempts;\n} network_prov_wifi_conn_cfg_t;\n\n/**\n * @brief Event handler can be set to none if not used\n */\n#define NETWORK_PROV_EVENT_HANDLER_NONE { \\\n    .event_cb  = NULL,                    \\\n    .user_data = NULL                     \\\n}\n\n/**\n * @brief   Structure for specifying the provisioning scheme to be\n *          followed by the manager\n *\n * @note    Ready to use schemes are available:\n *              - network_prov_scheme_ble     : for provisioning over BLE transport + GATT server\n *              - network_prov_scheme_softap  : for provisioning over SoftAP transport + HTTP server\n *              - network_prov_scheme_console : for provisioning over Serial UART transport + Console (for debugging)\n */\ntypedef struct network_prov_scheme {\n    /**\n     * Function which is to be called by the manager when it is to\n     * start the provisioning service associated with a protocomm instance\n     * and a scheme specific configuration\n     */\n    esp_err_t (*prov_start) (protocomm_t *pc, void *config);\n\n    /**\n     * Function which is to be called by the manager to stop the\n     * provisioning service previously associated with a protocomm instance\n     */\n    esp_err_t (*prov_stop) (protocomm_t *pc);\n\n    /**\n     * Function which is to be called by the manager to generate\n     * a new configuration for the provisioning service, that is\n     * to be passed to prov_start()\n     */\n    void *(*new_config) (void);\n\n    /**\n     * Function which is to be called by the manager to delete a\n     * configuration generated using new_config()\n     */\n    void (*delete_config) (void *config);\n\n    /**\n     * Function which is to be called by the manager to set the\n     * service name and key values in the configuration structure\n     */\n    esp_err_t (*set_config_service) (void *config, const char *service_name, const char *service_key);\n\n    /**\n     * Function which is to be called by the manager to set a protocomm endpoint\n     * with an identifying name and UUID in the configuration structure\n     */\n    esp_err_t (*set_config_endpoint) (void *config, const char *endpoint_name, uint16_t uuid);\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    /**\n     * Sets mode of operation of Wi-Fi during provisioning\n     * This is set to :\n     * - WIFI_MODE_APSTA for SoftAP transport\n     * - WIFI_MODE_STA for BLE transport\n     */\n    wifi_mode_t wifi_mode;\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n} network_prov_scheme_t;\n\n/**\n * @brief   Structure for specifying the manager configuration\n */\ntypedef struct {\n    /**\n     * Provisioning scheme to use. Following schemes are already available:\n     *     - network_prov_scheme_ble     : for provisioning over BLE transport + GATT server\n     *     - network_prov_scheme_softap  : for provisioning over SoftAP transport + HTTP server + mDNS (optional)\n     *     - network_prov_scheme_console : for provisioning over Serial UART transport + Console (for debugging)\n     */\n    network_prov_scheme_t scheme;\n\n    /**\n     * Event handler required by the scheme for incorporating scheme specific\n     * behavior while provisioning manager is running. Various options may be\n     * provided by the scheme for setting this field. Use NETWORK_PROV_EVENT_HANDLER_NONE\n     * when not used. When using scheme network_prov_scheme_ble, the following\n     * options are available:\n     *     - NETWORK_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM\n     *     - NETWORK_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BLE\n     *     - NETWORK_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BT\n     */\n    network_prov_event_handler_t scheme_event_handler;\n\n    /**\n     * Event handler that can be set for the purpose of incorporating application\n     * specific behavior. Use NETWORK_PROV_EVENT_HANDLER_NONE when not used.\n     */\n    network_prov_event_handler_t app_event_handler;\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    /**\n     * This config holds the Wi-Fi provisioning related configurations.\n     */\n    network_prov_wifi_conn_cfg_t network_prov_wifi_conn_cfg;\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n} network_prov_mgr_config_t;\n\n/**\n * @brief   Security modes supported by the Provisioning Manager.\n *\n * These are same as the security modes provided by protocomm\n */\ntypedef enum network_prov_security {\n#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0\n    /**\n     * No security (plain-text communication)\n     */\n    NETWORK_PROV_SECURITY_0 = 0,\n#endif\n#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1\n    /**\n     * This secure communication mode consists of\n     *   X25519 key exchange\n     * + proof of possession (pop) based authentication\n     * + AES-CTR encryption\n     */\n    NETWORK_PROV_SECURITY_1 = 1,\n#endif\n#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2\n    /**\n     * This secure communication mode consists of\n     *  SRP6a based authentication and key exchange\n     *  + AES-GCM encryption/decryption\n     */\n    NETWORK_PROV_SECURITY_2 = 2\n#endif\n#if !CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0 && !CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1 && !CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2\n#error \"All of the protocomm security versions are disabled. Make sure to enable at least one security version.\"\n#endif\n} network_prov_security_t;\n\n/**\n * @brief  Security 1 params structure\n *         This needs to be passed when using NETWORK_PROV_SECURITY_1\n */\ntypedef const char network_prov_security1_params_t;\n\n/**\n * @brief  Security 2 params structure\n *         This needs to be passed when using NETWORK_PROV_SECURITY_2\n */\ntypedef protocomm_security2_params_t network_prov_security2_params_t;\n\n/**\n * @brief   Initialize provisioning manager instance\n *\n * Configures the manager and allocates internal resources\n *\n * Configuration specifies the provisioning scheme (transport)\n * and event handlers\n *\n * Event NETWORK_PROV_INIT is emitted right after initialization\n * is complete\n *\n * @param[in] config Configuration structure\n *\n * @return\n *  - ESP_OK      : Success\n *  - ESP_FAIL    : Fail\n */\nesp_err_t network_prov_mgr_init(network_prov_mgr_config_t config);\n\n/**\n * @brief   Stop provisioning (if running) and release\n *          resource used by the manager\n *\n * Event NETWORK_PROV_DEINIT is emitted right after de-initialization\n * is finished\n *\n * If provisioning service is  still active when this API is called,\n * it first stops the service, hence emitting NETWORK_PROV_END, and\n * then performs the de-initialization\n *\n * @return\n *  - ESP_OK         : Success\n *  - ESP_FAIL       : Failed to post event NETWORK_PROV_DEINIT or NETWORK_PROV_END\n *  - ESP_ERR_NO_MEM : Out of memory (as may be returned by esp_event_post)\n */\nesp_err_t network_prov_mgr_deinit(void);\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n/**\n * @brief   Checks if device is provisioned\n *\n * This checks if Wi-Fi credentials are present on the NVS\n *\n * The Wi-Fi credentials are assumed to be kept in the same\n * NVS namespace as used by esp_wifi component\n *\n * If one were to call esp_wifi_set_config() directly instead\n * of going through the provisioning process, this function will\n * still yield true (i.e. device will be found to be provisioned)\n *\n * @note    Calling network_prov_mgr_start_provisioning() automatically\n *          resets the provision state, irrespective of what the\n *          state was prior to making the call.\n *\n * @param[out] provisioned  True if provisioned, else false\n *\n * @return\n *  - ESP_OK      : Retrieved provision state successfully\n *  - ESP_FAIL    : Wi-Fi not initialized\n *  - ESP_ERR_INVALID_ARG   : Null argument supplied\n */\nesp_err_t network_prov_mgr_is_wifi_provisioned(bool *provisioned);\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n/**\n * @brief   Checks if device is provisioned\n *\n * This checks if there is active dataset for Thread device\n *\n * @note    Calling network_prov_mgr_start_provisioning() automatically\n *          resets the provision state, irrespective of what the\n *          state was prior to making the call.\n *\n * @param[out] provisioned  True if provisioned, else false\n *\n * @return\n *  - ESP_OK      : Retrieved provision state successfully\n *  - ESP_FAIL    : Not initialized\n *  - ESP_ERR_INVALID_ARG   : Null argument supplied\n */\nesp_err_t network_prov_mgr_is_thread_provisioned(bool *provisioned);\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n\n/**\n * @brief   Checks whether the provisioning state machine is idle\n *\n * @return  True if state machine is idle, else false\n */\nbool network_prov_mgr_is_sm_idle(void);\n\n/**\n * @brief   Start provisioning service\n *\n * This starts the provisioning service according to the scheme\n * configured at the time of initialization. For scheme :\n * - network_prov_scheme_ble : This starts protocomm_ble, which internally initializes\n *                          BLE transport and starts GATT server for handling\n *                          provisioning requests\n * - network_prov_scheme_softap : This activates SoftAP mode of Wi-Fi and starts\n *                          protocomm_httpd, which internally starts an HTTP\n *                          server for handling provisioning requests (If mDNS is\n *                          active it also starts advertising service with type\n *                          _esp_wifi_prov._tcp)\n *\n * Event NETWORK_PROV_START is emitted right after provisioning starts without failure\n *\n * @note   This API will start provisioning service even if device is found to be\n *         already provisioned, i.e. network_prov_mgr_is_wifi_provisioned() yields true\n *\n * @param[in] security      Specify which protocomm security scheme to use :\n *                              - NETWORK_PROV_SECURITY_0 : For no security\n *                              - NETWORK_PROV_SECURITY_1 : x25519 secure handshake for session\n *                                establishment followed by AES-CTR encryption of provisioning messages\n *                              - NETWORK_PROV_SECURITY_2:  SRP6a based authentication and key exchange\n *                                followed by AES-GCM encryption/decryption of provisioning messages\n * @param[in] network_prov_sec_params\n *                          Pointer to security params (NULL if not needed).\n *                          This is not needed for protocomm security 0\n *                          This pointer should hold the struct of type\n *                          network_prov_security1_params_t for protocomm security 1\n *                          and network_prov_security2_params_t for protocomm security 2 respectively.\n *                          This pointer and its contents should be valid till the provisioning service is\n *                          running and has not been stopped or de-inited.\n * @param[in] service_name  Unique name of the service. This translates to:\n *                              - Wi-Fi SSID when provisioning mode is softAP\n *                              - Device name when provisioning mode is BLE\n * @param[in] service_key   Key required by client to access the service (NULL if not needed).\n *                          This translates to:\n *                              - Wi-Fi password when provisioning mode is softAP\n *                              - ignored when provisioning mode is BLE\n *\n * @return\n *  - ESP_OK      : Provisioning started successfully\n *  - ESP_FAIL    : Failed to start provisioning service\n *  - ESP_ERR_INVALID_STATE : Provisioning manager not initialized or already started\n */\nesp_err_t network_prov_mgr_start_provisioning(network_prov_security_t security, const void *network_prov_sec_params, const char *service_name, const char *service_key);\n\n/**\n * @brief   Stop provisioning service\n *\n * If provisioning service is active, this API will initiate a process to stop\n * the service and return. Once the service actually stops, the event NETWORK_PROV_END\n * will be emitted.\n *\n * If network_prov_mgr_deinit() is called without calling this API first, it will\n * automatically stop the provisioning service and emit the NETWORK_PROV_END, followed\n * by NETWORK_PROV_DEINIT, before returning.\n *\n * This API will generally be used along with network_prov_mgr_disable_auto_stop()\n * in the scenario when the main application has registered its own endpoints,\n * and wishes that the provisioning service is stopped only when some protocomm\n * command from the client side application is received.\n *\n * Calling this API inside an endpoint handler, with sufficient cleanup_delay,\n * will allow the response / acknowledgment to be sent successfully before the\n * underlying protocomm service is stopped.\n *\n * Cleaup_delay is set when calling network_prov_mgr_disable_auto_stop().\n * If not specified, it defaults to 1000ms.\n *\n * For straightforward cases, using this API is usually not necessary as\n * provisioning is stopped automatically once NETWORK_PROV_CRED_SUCCESS is emitted.\n * Stopping is delayed (maximum 30 seconds) thus allowing the client side\n * application to query for network state, i.e. after receiving the first query\n * and sending `network state connected` response the service is stopped immediately.\n */\nvoid network_prov_mgr_stop_provisioning(void);\n\n/**\n * @brief   Wait for provisioning service to finish\n *\n * Calling this API will block until provisioning service is stopped\n * i.e. till event NETWORK_PROV_END is emitted.\n *\n * This will not block if provisioning is not started or not initialized.\n */\nvoid network_prov_mgr_wait(void);\n\n/**\n * @brief   Disable auto stopping of provisioning service upon completion\n *\n * By default, once provisioning is complete, the provisioning service is automatically\n * stopped, and all endpoints (along with those registered by main application) are\n * deactivated.\n *\n * This API is useful in the case when main application wishes to close provisioning service\n * only after it receives some protocomm command from the client side app. For example, after\n * connecting to network, the device may want to connect to the cloud, and only once that is\n * successfully, the device is said to be fully configured. But, then it is upto the main\n * application to explicitly call network_prov_mgr_stop_provisioning() later when the device is\n * fully configured and the provisioning service is no longer required.\n *\n * @note    This must be called before executing network_prov_mgr_start_provisioning()\n *\n * @param[in] cleanup_delay Sets the delay after which the actual cleanup of transport related\n *                          resources is done after a call to network_prov_mgr_stop_provisioning()\n *                          returns. Minimum allowed value is 100ms. If not specified, this will\n *                          default to 1000ms.\n *\n * @return\n *  - ESP_OK : Success\n *  - ESP_ERR_INVALID_STATE : Manager not initialized or\n *                            provisioning service already started\n */\nesp_err_t network_prov_mgr_disable_auto_stop(uint32_t cleanup_delay);\n\n/**\n * @brief   Set application version and capabilities in the JSON data returned by\n *          proto-ver endpoint\n *\n * This function can be called multiple times, to specify information about the various\n * application specific services running on the device, identified by unique labels.\n *\n * The provisioning service itself registers an entry in the JSON data, by the label \"prov\",\n * containing only provisioning service version and capabilities. Application services should\n * use a label other than \"prov\" so as not to overwrite this.\n *\n * @note    This must be called before executing network_prov_mgr_start_provisioning()\n *\n * @param[in] label   String indicating the application name.\n *\n * @param[in] version String indicating the application version.\n *                    There is no constraint on format.\n *\n * @param[in] capabilities  Array of strings with capabilities.\n *                          These could be used by the client side app to know\n *                          the application registered endpoint capabilities\n *\n * @param[in] total_capabilities  Size of capabilities array\n *\n * @return\n *  - ESP_OK : Success\n *  - ESP_ERR_INVALID_STATE : Manager not initialized or\n *                            provisioning service already started\n *  - ESP_ERR_NO_MEM : Failed to allocate memory for version string\n *  - ESP_ERR_INVALID_ARG : Null argument\n */\nesp_err_t network_prov_mgr_set_app_info(const char *label, const char *version,\n                                        const char **capabilities, size_t total_capabilities);\n\n/**\n * @brief   Create an additional endpoint and allocate internal resources for it\n *\n * This API is to be called by the application if it wants to create an additional\n * endpoint. All additional endpoints will be assigned UUIDs starting from 0xFF54\n * and so on in the order of execution.\n *\n * protocomm handler for the created endpoint is to be registered later using\n * network_prov_mgr_endpoint_register() after provisioning has started.\n *\n * @note    This API can only be called BEFORE provisioning is started\n *\n * @note    Additional endpoints can be used for configuring client provided\n *          parameters other than Wi-Fi credentials or Thread dataset, that are necessary\n *          for the main application and hence must be set prior to starting the application\n *\n * @note    After session establishment, the additional endpoints must be targeted\n *          first by the client side application before sending Wi-Fi/Thread configuration,\n *          because once Wi-Fi/Thread configuration finishes the provisioning service is\n *          stopped and hence all endpoints are unregistered\n *\n * @param[in] ep_name  unique name of the endpoint\n *\n * @return\n *  - ESP_OK      : Success\n *  - ESP_FAIL    : Failure\n */\nesp_err_t network_prov_mgr_endpoint_create(const char *ep_name);\n\n/**\n * @brief   Register a handler for the previously created endpoint\n *\n * This API can be called by the application to register a protocomm handler\n * to any endpoint that was created using network_prov_mgr_endpoint_create().\n *\n * @note    This API can only be called AFTER provisioning has started\n *\n * @note    Additional endpoints can be used for configuring client provided\n *          parameters other than Wi-Fi credentials or Thread dataset, that are necessary\n *          for the main application and hence must be set prior to starting the application\n *\n * @note    After session establishment, the additional endpoints must be targeted\n *          first by the client side application before sending Wi-Fi/Thread configuration,\n *          because once Wi-Fi/Thread configuration finishes the provisioning service is\n *          stopped and hence all endpoints are unregistered\n *\n * @param[in] ep_name   Name of the endpoint\n * @param[in] handler   Endpoint handler function\n * @param[in] user_ctx  User data\n *\n * @return\n *  - ESP_OK      : Success\n *  - ESP_FAIL    : Failure\n */\nesp_err_t network_prov_mgr_endpoint_register(const char *ep_name,\n        protocomm_req_handler_t handler,\n        void *user_ctx);\n\n/**\n * @brief   Unregister the handler for an endpoint\n *\n * This API can be called if the application wants to selectively\n * unregister the handler of an endpoint while the provisioning\n * is still in progress.\n *\n * All the endpoint handlers are unregistered automatically when\n * the provisioning stops.\n *\n * @param[in] ep_name  Name of the endpoint\n */\nvoid network_prov_mgr_endpoint_unregister(const char *ep_name);\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n/**\n * @brief   Get state of Wi-Fi Station during provisioning\n *\n * @param[out] state    Pointer to network_prov_wifi_sta_state_t\n *                      variable to be filled\n *\n * @return\n *  - ESP_OK    : Successfully retrieved Wi-Fi state\n *  - ESP_FAIL  : Provisioning app not running\n */\nesp_err_t network_prov_mgr_get_wifi_state(network_prov_wifi_sta_state_t *state);\n\n/**\n * @brief   Get reason code in case of Wi-Fi station\n *          disconnection during provisioning\n *\n* @param[out] reason    Pointer to network_prov_wifi_sta_fail_reason_t\n*                       variable to be filled\n *\n * @return\n *  - ESP_OK    : Successfully retrieved Wi-Fi disconnect reason\n *  - ESP_FAIL  : Provisioning app not running\n */\nesp_err_t network_prov_mgr_get_wifi_disconnect_reason(network_prov_wifi_sta_fail_reason_t *reason);\n\n/**\n * @brief   Runs Wi-Fi as Station with the supplied configuration\n *\n * Configures the Wi-Fi station mode to connect to the AP with\n * SSID and password specified in config structure and sets\n * Wi-Fi to run as station.\n *\n * This is automatically called by provisioning service upon\n * receiving new credentials.\n *\n * If credentials are to be supplied to the manager via a\n * different mode other than through protocomm, then this\n * API needs to be called.\n *\n * Event NETWORK_PROV_CRED_RECV is emitted after credentials have\n * been applied and Wi-Fi station started\n *\n * @param[in] wifi_cfg  Pointer to Wi-Fi configuration structure\n *\n * @return\n *  - ESP_OK      : Wi-Fi configured and started successfully\n *  - ESP_FAIL    : Failed to set configuration\n */\nesp_err_t network_prov_mgr_configure_wifi_sta(wifi_config_t *wifi_cfg);\n\n/**\n * @brief   Reset Wi-Fi provisioning config\n *\n * Calling this API will restore WiFi stack persistent settings to default values.\n *\n * @return\n *  - ESP_OK      : Reset provisioning config successfully\n *  - ESP_FAIL    : Failed to reset provisioning config\n */\nesp_err_t network_prov_mgr_reset_wifi_provisioning(void);\n\n/**\n * @brief   Reset internal state machine and clear provisioned credentials.\n *\n * This API should be used to restart provisioning ONLY in the case\n * of provisioning failures without rebooting the device.\n *\n * @return\n *  - ESP_OK      : Reset provisioning state machine successfully\n *  - ESP_FAIL    : Failed to reset provisioning state machine\n *  - ESP_ERR_INVALID_STATE : Manager not initialized\n */\nesp_err_t network_prov_mgr_reset_wifi_sm_state_on_failure(void);\n\n/**\n * @brief   Reset internal state machine and clear provisioned credentials.\n *\n * This API can be used to restart provisioning ONLY in case the device is\n * to be provisioned again for new credentials after a previous successful\n * provisioning without rebooting the device.\n *\n * @note   This API can be used only if provisioning auto-stop has been\n *         disabled using network_prov_mgr_disable_auto_stop()\n *\n * @return\n *  - ESP_OK      : Reset provisioning state machine successfully\n *  - ESP_FAIL    : Failed to reset provisioning state machine\n *  - ESP_ERR_INVALID_STATE : Manager not initialized\n */\nesp_err_t network_prov_mgr_reset_wifi_sm_state_for_reprovision(void);\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n/**\n * @brief   Reset Thread provisioning config\n *\n * Calling this API will restore Thread stack persistent settings to default values.\n *\n * @return\n *  - ESP_OK      : Reset provisioning config successfully\n *  - ESP_FAIL    : Failed to reset provisioning config\n */\nesp_err_t network_prov_mgr_reset_thread_provisioning(void);\n\n/**\n * @brief   Get state of Thread during provisioning\n *\n * @param[out] state    Pointer to network_prov_thread_state_t\n *                      variable to be filled\n *\n * @return\n *  - ESP_OK    : Successfully retrieved Thread state\n *  - ESP_FAIL  : Provisioning app not running\n */\nesp_err_t network_prov_mgr_get_thread_state(network_prov_thread_state_t *state);\n\n/**\n * @brief   Get reason code in case of thread detached during provisioning\n *\n* @param[out] reason    Pointer to network_prov_thread_fail_reason_t\n*                       variable to be filled\n *\n * @return\n *  - ESP_OK    : Successfully retrieved thread detached reason\n *  - ESP_FAIL  : Provisioning app not running\n */\nesp_err_t network_prov_mgr_get_thread_detached_reason(network_prov_thread_fail_reason_t *reason);\n\n/**\n * @brief   Runs Thread with the supplied configuration\n *\n * Configures the Thread Dataset so that the device can be attached\n * to a specific Thread network\n *\n * This is automatically called by provisioning service upon\n * receiving new Thread dataset.\n *\n * If the dataset is to be supplied to the manager via a\n * different mode other than through protocomm, then this\n * API needs to be called.\n *\n * Event THREAD_PROV_CRED_RECV is emitted after credentials have\n * been applied and Thread started\n *\n * @param[in] thread_dataset  Pointer to Dataset Tlvs structure\n *\n * @return\n *  - ESP_OK      : Thread dataset configured and started successfully\n *  - ESP_FAIL    : Failed to set configuration\n */\nesp_err_t network_prov_mgr_configure_thread_dataset(otOperationalDatasetTlvs *thread_dataset);\n\n/**\n * @brief   Reset internal state machine and clear provisioned credentials.\n *\n * This API should be used to restart provisioning ONLY in the case\n * of provisioning failures without rebooting the device.\n *\n * @return\n *  - ESP_OK      : Reset provisioning state machine successfully\n *  - ESP_FAIL    : Failed to reset provisioning state machine\n *  - ESP_ERR_INVALID_STATE : Manager not initialized\n */\nesp_err_t network_prov_mgr_reset_thread_sm_state_on_failure(void);\n\n/**\n * @brief   Reset internal state machine and clear provisioned credentials.\n *\n * This API can be used to restart provisioning ONLY in case the device is\n * to be provisioned again for new credentials after a previous successful\n * provisioning without rebooting the device.\n *\n * @note   This API can be used only if provisioning auto-stop has been\n *         disabled using network_prov_mgr_disable_auto_stop()\n *\n * @return\n *  - ESP_OK      : Reset provisioning state machine successfully\n *  - ESP_FAIL    : Failed to reset provisioning state machine\n *  - ESP_ERR_INVALID_STATE : Manager not initialized\n */\nesp_err_t network_prov_mgr_reset_thread_sm_state_for_reprovision(void);\n\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "network_provisioning/include/network_provisioning/network_config.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#ifndef _NETWORK_PROV_CONFIG_H_\n#define _NETWORK_PROV_CONFIG_H_\n\n#include \"esp_netif_ip_addr.h\"\n#include \"esp_err.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n/**\n * @brief   WiFi STA status for conveying back to the provisioning master\n */\ntypedef enum {\n    NETWORK_PROV_WIFI_STA_CONNECTING,\n    NETWORK_PROV_WIFI_STA_CONNECTED,\n    NETWORK_PROV_WIFI_STA_DISCONNECTED,\n    NETWORK_PROV_WIFI_STA_CONN_ATTEMPT_FAILED\n} network_prov_wifi_sta_state_t;\n\n/**\n * @brief   WiFi STA connection fail reason\n */\ntypedef enum {\n    NETWORK_PROV_WIFI_STA_AUTH_ERROR,\n    NETWORK_PROV_WIFI_STA_AP_NOT_FOUND\n} network_prov_wifi_sta_fail_reason_t;\n\n/**\n * @brief   WiFi STA connected status information\n */\ntypedef struct {\n    /**\n     * IP Address received by station\n     */\n    char    ip_addr[IP4ADDR_STRLEN_MAX];\n\n    char    bssid[6];   /*!< BSSID of the AP to which connection was estalished */\n    char    ssid[33];   /*!< SSID of the to which connection was estalished */\n    uint8_t channel;    /*!< Channel of the AP */\n    uint8_t auth_mode;  /*!< Authorization mode of the AP */\n} network_prov_wifi_sta_conn_info_t;\n\n/**\n * @brief   WiFi STA connecting status information\n */\ntypedef struct {\n    uint32_t attempts_remaining; /*!< Number of Wi-Fi connection attempts remaining */\n} network_prov_wifi_sta_connecting_info_t;\n\n/**\n * @brief   WiFi status data to be sent in response to `get_status` request from master\n */\ntypedef struct {\n    network_prov_wifi_sta_state_t wifi_state;    /*!< WiFi state of the station */\n    union {\n        /**\n         * Reason for disconnection (valid only when `wifi_state` is `WIFI_STATION_DISCONNECTED`)\n         */\n        network_prov_wifi_sta_fail_reason_t fail_reason;\n\n        /**\n         * Connection information (valid only when `wifi_state` is `WIFI_STATION_CONNECTED`)\n         */\n        network_prov_wifi_sta_conn_info_t   conn_info;\n\n        /**\n         * Connecting information (valid only when `wifi_state` is `WIFI_STATION_CONNECTING`)\n         */\n        network_prov_wifi_sta_connecting_info_t connecting_info;\n    };\n} network_prov_config_get_wifi_data_t;\n\n/**\n * @brief   WiFi config data received by slave during `set_config` request from master\n */\ntypedef struct {\n    char    ssid[33];       /*!< SSID of the AP to which the slave is to be connected */\n    char    password[64];   /*!< Password of the AP */\n    char    bssid[6];       /*!< BSSID of the AP */\n    uint8_t channel;        /*!< Channel of the AP */\n} network_prov_config_set_wifi_data_t;\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n/**\n * @brief   Thread status for conveying back to the provisioning master\n */\ntypedef enum {\n    NETWORK_PROV_THREAD_ATTACHING,\n    NETWORK_PROV_THREAD_ATTACHED,\n    NETWORK_PROV_THREAD_DETACHED,\n} network_prov_thread_state_t;\n\n/**\n * @brief   Thread attaching fail reason\n */\ntypedef enum {\n    NETWORK_PROV_THREAD_DATASET_INVALID,\n    NETWORK_PROV_THREAD_NETWORK_NOT_FOUND,\n} network_prov_thread_fail_reason_t;\n\n/**\n * @brief   Thread attached status information\n */\ntypedef struct {\n    uint32_t pan_id; /*!< PAN ID */\n    uint16_t channel; /*!< Channel */\n    char name[17]; /*!< Network Name */\n    uint8_t ext_pan_id[8]; /*!< Extended PAN ID */\n} network_prov_thread_conn_info_t;\n\n/**\n * @brief   Thread status data to be sent in response to `get_status` request from master\n */\ntypedef struct {\n    network_prov_thread_state_t thread_state;\n    union {\n        /**\n         * Reason for disconnection (valid only when `thread_state` is `THREAD_DETACHED`)\n         */\n        network_prov_thread_fail_reason_t fail_reason;\n\n        /**\n         * Connection information (valid only when `thread_state` is `THREAD_ATTACHED`)\n         */\n        network_prov_thread_conn_info_t conn_info;\n    };\n} network_prov_config_get_thread_data_t;\n\n/**\n * @brief   Thread config data received by slave during `set_config` request from master\n */\ntypedef struct {\n    uint8_t dataset[254];\n    uint8_t length;\n} network_prov_config_set_thread_data_t;\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n\n/**\n * @brief   Type of context data passed to each get/set/apply handler\n *           function set in `network_prov_config_handlers` structure.\n *\n * This is passed as an opaque pointer, thereby allowing it be defined\n * later in application code as per requirements.\n */\ntypedef struct network_prov_ctx network_prov_ctx_t;\n\n/**\n * @brief   Internal handlers for receiving and responding to protocomm\n *          requests from master\n *\n * This is to be passed as priv_data for protocomm request handler\n * (refer to `network_prov_config_data_handler()`) when calling `protocomm_add_endpoint()`.\n */\ntypedef struct network_prov_config_handlers {\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    /**\n     * Handler function called when connection status\n     * of the slave (in WiFi station mode) is requested\n     */\n    esp_err_t (*wifi_get_status_handler)(network_prov_config_get_wifi_data_t *resp_data,\n                                         network_prov_ctx_t **ctx);\n\n    /**\n     * Handler function called when WiFi connection configuration\n     * (eg. AP SSID, password, etc.) of the slave (in WiFi station mode)\n     * is to be set to user provided values\n     */\n    esp_err_t (*wifi_set_config_handler)(const network_prov_config_set_wifi_data_t *req_data,\n                                         network_prov_ctx_t **ctx);\n\n    /**\n     * Handler function for applying the configuration that was set in\n     * `set_config_handler`. After applying the station may get connected to\n     * the AP or may fail to connect. The slave must be ready to convey the\n     * updated connection status information when `get_status_handler` is\n     * invoked again by the master.\n     */\n    esp_err_t (*wifi_apply_config_handler)(network_prov_ctx_t **ctx);\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    esp_err_t (*thread_get_status_handler)(network_prov_config_get_thread_data_t *resp_data,\n                                           network_prov_ctx_t **ctx);\n\n    esp_err_t (*thread_set_config_handler)(const network_prov_config_set_thread_data_t *req_data,\n                                           network_prov_ctx_t **ctx);\n\n    esp_err_t (*thread_apply_config_handler)(network_prov_ctx_t **ctx);\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n\n    /**\n     * Context pointer to be passed to above handler functions upon invocation\n     */\n    network_prov_ctx_t *ctx;\n} network_prov_config_handlers_t;\n\n/**\n * @brief   Handler for receiving and responding to requests from master\n *\n * This is to be registered as the `network_config` endpoint handler\n * (protocomm `protocomm_req_handler_t`) using `protocomm_add_endpoint()`\n */\nesp_err_t network_prov_config_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,\n        uint8_t **outbuf, ssize_t *outlen, void *priv_data);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "network_provisioning/include/network_provisioning/network_scan.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#ifndef _PROV_NETWORK_SCAN_H_\n#define _PROV_NETWORK_SCAN_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#include <sdkconfig.h>\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n#include <esp_wifi.h>\n\n#define WIFI_SSID_LEN  sizeof(((wifi_ap_record_t *)0)->ssid)\n#define WIFI_BSSID_LEN sizeof(((wifi_ap_record_t *)0)->bssid)\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n#include <openthread/dataset.h>\n#include <openthread/platform/radio.h>\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n\n/**\n * @brief   Type of context data passed to each get/set/apply handler\n *           function set in `network_prov_scan_handlers` structure.\n *\n * This is passed as an opaque pointer, thereby allowing it be defined\n * later in application code as per requirements.\n */\ntypedef struct network_prov_scan_ctx network_prov_scan_ctx_t;\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n/**\n * @brief   Structure of entries in the scan results list\n */\ntypedef struct {\n    /**\n     * SSID of Wi-Fi AP\n     */\n    char ssid[WIFI_SSID_LEN];\n\n    /**\n     * BSSID of Wi-Fi AP\n     */\n    char bssid[WIFI_BSSID_LEN];\n\n    /**\n     * Wi-Fi channel number\n     */\n    uint8_t channel;\n\n    /**\n     * Signal strength\n     */\n    int rssi;\n\n    /**\n     * Wi-Fi security mode\n     */\n    uint8_t auth;\n} network_prov_scan_wifi_result_t;\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\ntypedef struct {\n    uint16_t pan_id;\n    uint8_t ext_pan_id[OT_EXT_ADDRESS_SIZE];\n    char network_name[OT_NETWORK_NAME_MAX_SIZE + 1];\n    uint16_t channel;\n    uint8_t ext_addr[OT_EXT_ADDRESS_SIZE];\n    int8_t rssi;\n    uint8_t lqi;\n} network_prov_scan_thread_result_t;\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n\n/**\n * @brief   Internal handlers for receiving and responding to protocomm\n *          requests from client\n *\n * This is to be passed as priv_data for protocomm request handler\n * (refer to `network_prov_scan_handler()`) when calling `protocomm_add_endpoint()`.\n */\ntypedef struct network_prov_scan_handlers {\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    /**\n     * Handler function called when scan start command is received\n     * with various scan parameters :\n     *\n     * blocking (input) - If true, the function should return only\n     * when the scanning is finished\n     *\n     * passive (input) - If true, scan is to be started in passive\n     * mode (this may be slower) instead of active mode\n     *\n     * group_channels (input) - This specifies whether to scan\n     * all channels in one go (when zero) or perform scanning of\n     * channels in groups, with 120ms delay between scanning of\n     * consecutive groups, and the value of this parameter sets the\n     * number of channels in each group. This is useful when transport\n     * mode is SoftAP, where scanning all channels in one go may not\n     * give the Wi-Fi driver enough time to send out beacons, and\n     * hence may cause disconnection with any connected stations.\n     * When scanning in groups, the manager will wait for at least\n     * 120ms after completing scan on a group of channels, and thus\n     * allow the driver to send out the beacons. For example, given\n     * that the total number of Wi-Fi channels is 14, then setting\n     * group_channels to 4, will create 5 groups, with each group\n     * having 3 channels, except the last one which will have\n     * 14 % 3 = 2 channels. So, when scan is started, the first 3\n     * channels will be scanned, followed by a 120ms delay, and then\n     * the next 3 channels, and so on, until all the 14 channels have\n     * been scanned. One may need to adjust this parameter as having\n     * only few channels in a group may slow down the overall scan\n     * time, while having too many may again cause disconnection.\n     * Usually a value of 4 should work for most cases. Note that\n     * for any other mode of transport, e.g. BLE, this can be safely\n     * set to 0, and hence achieve the fastest overall scanning time.\n     *\n     * period_ms (input) - Scan parameter specifying how long to\n     * wait on each channel (in milli-seconds)\n     */\n    esp_err_t (*wifi_scan_start)(bool blocking, bool passive,\n                                 uint8_t group_channels, uint32_t period_ms,\n                                 network_prov_scan_ctx_t **ctx);\n\n    /**\n     * Handler function called when scan status is requested. Status\n     * is given the parameters :\n     *\n     * scan_finished (output) - When scan has finished this returns true\n     *\n     * result_count (output) - This gives the total number of results\n     * obtained till now. If scan is yet happening this number will\n     * keep on updating\n     */\n    esp_err_t (*wifi_scan_status)(bool *scan_finished,\n                                  uint16_t *result_count,\n                                  network_prov_scan_ctx_t **ctx);\n\n    /**\n     * Handler function called when scan result is requested. Parameters :\n     *\n     * scan_result - For fetching scan results. This can be called even\n     * if scan is still on going\n     *\n     * start_index (input) - Starting index from where to fetch the\n     * entries from the results list\n     *\n     * count (input) - Number of entries to fetch from the starting index\n     *\n     * entries (output) - List of entries returned. Each entry consists\n     * of ssid, channel and rssi information\n     */\n    esp_err_t (*wifi_scan_result)(uint16_t result_index,\n                                  network_prov_scan_wifi_result_t *result,\n                                  network_prov_scan_ctx_t **ctx);\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    esp_err_t (*thread_scan_start)(bool blocking, uint32_t channel_mask, network_prov_scan_ctx_t **ctx);\n\n    esp_err_t (*thread_scan_status)(bool *scan_finished,\n                                    uint16_t *result_count,\n                                    network_prov_scan_ctx_t **ctx);\n\n    esp_err_t (*thread_scan_result)(uint16_t result_index,\n                                    network_prov_scan_thread_result_t *result,\n                                    network_prov_scan_ctx_t **ctx);\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n\n    /**\n     * Context pointer to be passed to above handler functions upon invocation\n     */\n    network_prov_scan_ctx_t *ctx;\n} network_prov_scan_handlers_t;\n\n/**\n * @brief   Handler for sending on demand Wi-Fi scan results\n *\n * This is to be registered as the `prov-scan` endpoint handler\n * (protocomm `protocomm_req_handler_t`) using `protocomm_add_endpoint()`\n */\nesp_err_t network_prov_scan_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,\n                                    uint8_t **outbuf, ssize_t *outlen, void *priv_data);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "network_provisioning/include/network_provisioning/scheme_ble.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include <protocomm.h>\n#include <protocomm_ble.h>\n\n#include \"network_provisioning/manager.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief   Scheme that can be used by manager for provisioning\n *          over BLE transport with GATT server\n */\nextern const network_prov_scheme_t network_prov_scheme_ble;\n\n/* This scheme specific event handler is to be used when application\n * doesn't require BT and BLE after provisioning has finished */\n#define NETWORK_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM {    \\\n    .event_cb  = network_prov_scheme_ble_event_cb_free_btdm, \\\n    .user_data = NULL                                     \\\n}\n\n/* This scheme specific event handler is to be used when application\n * doesn't require BLE to be active after provisioning has finished */\n#define NETWORK_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BLE {    \\\n    .event_cb  = network_prov_scheme_ble_event_cb_free_ble, \\\n    .user_data = NULL                                    \\\n}\n\n/* This scheme specific event handler is to be used when application\n * doesn't require BT to be active after provisioning has finished */\n#define NETWORK_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BT {    \\\n    .event_cb  = network_prov_scheme_ble_event_cb_free_bt, \\\n    .user_data = NULL                                   \\\n}\n\nvoid network_prov_scheme_ble_event_cb_free_btdm(void *user_data, network_prov_cb_event_t event, void *event_data);\nvoid network_prov_scheme_ble_event_cb_free_ble (void *user_data, network_prov_cb_event_t event, void *event_data);\nvoid network_prov_scheme_ble_event_cb_free_bt  (void *user_data, network_prov_cb_event_t event, void *event_data);\n\n/**\n * @brief   Set the 128 bit GATT service UUID used for provisioning\n *\n * This API is used to override the default 128 bit provisioning\n * service UUID, which is 0000ffff-0000-1000-8000-00805f9b34fb.\n *\n * This must be called before starting provisioning, i.e. before\n * making a call to network_prov_mgr_start_provisioning(), otherwise\n * the default UUID will be used.\n *\n * @note    The data being pointed to by the argument must be valid\n *          at least till provisioning is started. Upon start, the\n *          manager will store an internal copy of this UUID, and\n *          this data can be freed or invalidated afterwards.\n *\n * @param[in] uuid128  A custom 128 bit UUID\n *\n * @return\n *  - ESP_OK              : Success\n *  - ESP_ERR_INVALID_ARG : Null argument\n */\nesp_err_t network_prov_scheme_ble_set_service_uuid(uint8_t *uuid128);\n\n#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)\n/**\n * @brief   Keep the BLE on after provisioning\n *\n * This API is used to specify whether the BLE should remain on\n * after the provisioning process has stopped.\n *\n * This must be called before starting provisioning, i.e. before\n * making a call to network_prov_mgr_start_provisioning(), otherwise\n * the default behavior will be used.\n *\n * @note    The value being pointed to by the argument must be valid\n *          at least until provisioning is started. Upon start, the\n *          manager will store an internal copy of this value, and\n *          this data can be freed or invalidated afterwards.\n *\n * @param[in] is_on_after_ble_stop  A boolean indicating if BLE should remain on after provisioning\n *\n * @return\n *  - ESP_OK              : Success\n *  - ESP_ERR_INVALID_ARG : Null argument\n */\nesp_err_t network_prov_mgr_keep_ble_on(uint8_t is_on_after_ble_stop);\n\n/**\n * @brief   Set Bluetooth Random address\n *\n * This must be called before starting provisioning, i.e. before\n * making a call to network_prov_mgr_start_provisioning().\n *\n * This API can be used in cases where a new identity address is to be used during\n * provisioning. This will result in this device being treated as a new device by remote\n * devices.\n *\n * @note    This API will change the existing BD address for the device. The address once\n *          set will remain unchanged until BLE stack tear down happens when\n *          network_prov_mgr_deinit is invoked.\n *\n *          This API is only to be called to set random address. Re-invoking this API\n *          after provisioning is started will have no effect.\n *\n * @param[in] rand_addr     The static random address to be set of length 6 bytes.\n *\n * @return\n *  - ESP_OK              : Success\n *  - ESP_ERR_INVALID_ARG : Null argument\n */\nesp_err_t network_prov_scheme_ble_set_random_addr(const uint8_t *rand_addr);\n#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)\n\n/**\n * @brief   Set manufacturer specific data in scan response\n *\n * This must be called before starting provisioning, i.e. before\n * making a call to network_prov_mgr_start_provisioning().\n *\n * @note    It is important to understand that length of custom manufacturer\n *          data should be within limits. The manufacturer data goes into scan\n *          response along with BLE device name. By default, BLE device name\n *          length is of 11 Bytes, however it can vary as per application use\n *          case. So, one has to honour the scan response data size limits i.e.\n *          (mfg_data_len + 2) < 31 - (device_name_length + 2 ). If the\n *          mfg_data length exceeds this limit, the length will be truncated.\n *\n * @param[in] mfg_data      Custom manufacturer data\n * @param[in] mfg_data_len  Manufacturer data length\n *\n * @return\n *  - ESP_OK              : Success\n *  - ESP_ERR_INVALID_ARG : Null argument\n */\nesp_err_t network_prov_scheme_ble_set_mfg_data(uint8_t *mfg_data, ssize_t mfg_data_len);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "network_provisioning/include/network_provisioning/scheme_console.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include <protocomm.h>\n#include <protocomm_console.h>\n\n#include \"network_provisioning/manager.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief   Scheme that can be used by manager for provisioning\n *          over console (Serial UART)\n */\nextern const network_prov_scheme_t network_prov_scheme_console;\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "network_provisioning/include/network_provisioning/scheme_softap.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include <protocomm.h>\n#include <protocomm_httpd.h>\n\n#include \"network_provisioning/manager.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief   Scheme that can be used by manager for provisioning\n *          over SoftAP transport with HTTP server\n */\nextern const network_prov_scheme_t network_prov_scheme_softap;\n\n/**\n *\n * @brief Provide HTTPD Server handle externally.\n *\n * Useful in cases wherein applications need the webserver for some\n * different operations, and do not want the wifi provisioning component\n * to start/stop a new instance.\n *\n * @note This API should be called before network_prov_mgr_start_provisioning()\n *\n * @param[in] handle Handle to HTTPD server instance\n */\nvoid network_prov_scheme_softap_set_httpd_handle(void *handle);\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "network_provisioning/proto/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.22)\n\nset(PROTO_COMPILER \"protoc\")\nset(PROTO_C_COMPILER \"protoc-c\")\nset(C_OUT_PATH \"${CMAKE_CURRENT_LIST_DIR}/../proto-c\")\nset(PY_OUT_PATH \"${CMAKE_CURRENT_LIST_DIR}/../python\")\nset(PROTOCOMM_INCL_PATH \"${IDF_PATH}/component/protocomm/proto\")\n\nset(PROTO_SRCS \"network_constants.proto\"\n               \"network_config.proto\"\n               \"network_scan.proto\")\n\nadd_custom_target(c_proto\n    COMMAND ${PROTO_C_COMPILER} --c_out=${C_OUT_PATH} -I . -I ${PROTOCOMM_INCL_PATH} ${PROTO_SRCS}\n    VERBATIM\n    WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}\n    )\n\nadd_custom_target(python_proto\n    COMMAND ${PROTO_COMPILER} --python_out=${PY_OUT_PATH} -I . -I ${PROTOCOMM_INCL_PATH} ${PROTO_SRCS}\n    VERBATIM\n    WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}\n    )\n\nadd_custom_target(proto ALL\n    DEPENDS c_proto python_proto\n    VERBATIM\n    WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}\n    )\n"
  },
  {
    "path": "network_provisioning/proto/README.md",
    "content": "# Protobuf files for defining Network provisioning packet structures\n\n`network_provisioning` uses Google Protobuf for language, transport and architecture agnostic protocol communication. These proto files define the protocomm packet structure, separated across multiple files:\n* network_contants.proto - Defines the various enums for indicating state of network (connected / disconnect / connecting), disconnect reasons, auth modes, etc.\n* network_config.proto - Defines network configuration structures and commands for setting Wi-Fi credentials (SSID, passphrase, BSSID) or Thread dataset, applying credentials and getting connection state.\n* network_scan.proto - Defines network scan commands and result structures\n* network_ctrl.proto - Defines network control commands(reset and re-provision) and result structures\n\nNote : These proto files are not automatically compiled during the build process.\n\n# Compilation\n\nCompilation requires protoc (Protobuf Compiler) and protoc-c (Protobuf C Compiler) installed. Since the generated files are to remain the same, as long as the proto files are not modified, therefore the generated files are already available under `components/network_provisioning/proto-c` and `components/network_provisioning/python` directories, and thus running cmake / make (and installing the Protobuf compilers) is optional.\n\nIf using `cmake` follow the below steps. If using `make`, jump to Step 2 directly.\n\n## Step 1 (Only for cmake)\n\nWhen using cmake, first create a build directory and call cmake from inside:\n\n```\nmkdir build\ncd build\ncmake ..\n```\n\n## Step 2\n\nSimply run `make` to generate the respective C and Python files. The newly created files will overwrite those under `components/network_provisioning/proto-c` and `components/network_provisioning/python`\n"
  },
  {
    "path": "network_provisioning/proto/makefile",
    "content": "all: c_proto python_proto\n\nc_proto: *.proto\n\t@protoc-c --c_out=../proto-c/ -I . -I ${IDF_PATH}/components/protocomm/proto/ *.proto\n\npython_proto: *.proto\n\t@protoc --python_out=../python/ -I . -I ${IDF_PATH}/components/protocomm/proto/ *.proto\n"
  },
  {
    "path": "network_provisioning/proto/network_config.proto",
    "content": "syntax = \"proto3\";\n\nimport \"constants.proto\";\nimport \"network_constants.proto\";\n\nmessage CmdGetWifiStatus {\n}\n\nmessage RespGetWifiStatus {\n    Status status = 1;\n    WifiStationState wifi_sta_state = 2;\n    oneof state {\n        WifiConnectFailedReason wifi_fail_reason = 10;\n        WifiConnectedState wifi_connected = 11;\n        WifiAttemptFailed attempt_failed = 12;\n    }\n}\n\nmessage CmdGetThreadStatus {\n}\n\nmessage RespGetThreadStatus {\n    Status status = 1;\n    ThreadNetworkState thread_state = 2;\n    oneof state {\n        ThreadAttachFailedReason thread_fail_reason = 10;\n        ThreadAttachState thread_attached = 11;\n    }\n}\n\nmessage CmdSetWifiConfig {\n    bytes ssid = 1;\n    bytes passphrase = 2;\n    bytes bssid = 3;\n    int32 channel = 4;\n}\n\nmessage CmdSetThreadConfig {\n    bytes dataset = 1;\n}\n\nmessage RespSetWifiConfig {\n    Status status = 1;\n}\n\nmessage RespSetThreadConfig {\n    Status status = 1;\n}\n\nmessage CmdApplyWifiConfig {\n}\n\nmessage CmdApplyThreadConfig {\n}\n\nmessage RespApplyWifiConfig {\n    Status status = 1;\n}\n\nmessage RespApplyThreadConfig {\n    Status status = 1;\n}\n\nenum NetworkConfigMsgType {\n    TypeCmdGetWifiStatus = 0;\n    TypeRespGetWifiStatus = 1;\n    TypeCmdSetWifiConfig = 2;\n    TypeRespSetWifiConfig = 3;\n    TypeCmdApplyWifiConfig = 4;\n    TypeRespApplyWifiConfig = 5;\n    TypeCmdGetThreadStatus = 6;\n    TypeRespGetThreadStatus = 7;\n    TypeCmdSetThreadConfig = 8;\n    TypeRespSetThreadConfig = 9;\n    TypeCmdApplyThreadConfig = 10;\n    TypeRespApplyThreadConfig = 11;\n\n}\n\nmessage NetworkConfigPayload {\n    NetworkConfigMsgType msg = 1;\n    oneof payload {\n        CmdGetWifiStatus cmd_get_wifi_status = 10;\n        RespGetWifiStatus resp_get_wifi_status = 11;\n        CmdSetWifiConfig cmd_set_wifi_config = 12;\n        RespSetWifiConfig resp_set_wifi_config = 13;\n        CmdApplyWifiConfig cmd_apply_wifi_config = 14;\n        RespApplyWifiConfig resp_apply_wifi_config = 15;\n        CmdGetThreadStatus cmd_get_thread_status = 16;\n        RespGetThreadStatus resp_get_thread_status = 17;\n        CmdSetThreadConfig cmd_set_thread_config = 18;\n        RespSetThreadConfig resp_set_thread_config = 19;\n        CmdApplyThreadConfig cmd_apply_thread_config = 20;\n        RespApplyThreadConfig resp_apply_thread_config = 21;\n    }\n}\n"
  },
  {
    "path": "network_provisioning/proto/network_constants.proto",
    "content": "syntax = \"proto3\";\n\nenum WifiStationState {\n    Connected = 0;\n    Connecting = 1;\n    Disconnected = 2;\n    ConnectionFailed = 3;\n}\n\nenum WifiConnectFailedReason {\n    AuthError = 0;\n    WifiNetworkNotFound = 1;\n}\n\nenum WifiAuthMode {\n    Open = 0;\n    WEP  = 1;\n    WPA_PSK = 2;\n    WPA2_PSK = 3;\n    WPA_WPA2_PSK = 4;\n    WPA2_ENTERPRISE = 5;\n    WPA3_PSK = 6;\n    WPA2_WPA3_PSK = 7;\n}\n\nmessage WifiConnectedState {\n    string ip4_addr = 1;\n    WifiAuthMode auth_mode = 2;\n    bytes ssid = 3;\n    bytes bssid = 4;\n    int32 channel = 5;\n}\n\nmessage WifiAttemptFailed {\n    uint32 attempts_remaining = 1;\n}\n\nenum ThreadNetworkState {\n    Attached = 0;\n    Attaching = 1;\n    Dettached = 2;\n    AttachingFailed = 3;\n}\n\nenum ThreadAttachFailedReason {\n    DatasetInvalid = 0;\n    ThreadNetworkNotFound = 1;\n}\n\nmessage ThreadAttachState {\n    uint32 pan_id = 1;\n    bytes ext_pan_id = 2;\n    uint32 channel = 3;\n    string name = 4;\n}\n"
  },
  {
    "path": "network_provisioning/proto/network_ctrl.proto",
    "content": "syntax = \"proto3\";\n\nimport \"constants.proto\";\n\nmessage CmdCtrlWifiReset {\n}\n\nmessage RespCtrlWifiReset {\n}\n\nmessage CmdCtrlWifiReprov {\n}\n\nmessage RespCtrlWifiReprov{\n}\n\nmessage CmdCtrlThreadReset {\n}\n\nmessage RespCtrlThreadReset {\n}\n\nmessage CmdCtrlThreadReprov {\n}\n\nmessage RespCtrlThreadReprov{\n}\n\nenum NetworkCtrlMsgType {\n    TypeCtrlReserved = 0;\n    TypeCmdCtrlWifiReset = 1;\n    TypeRespCtrlWifiReset = 2;\n    TypeCmdCtrlWifiReprov = 3;\n    TypeRespCtrlWifiReprov = 4;\n    TypeCmdCtrlThreadReset = 5;\n    TypeRespCtrlThreadReset = 6;\n    TypeCmdCtrlThreadReprov = 7;\n    TypeRespCtrlThreadReprov = 8;\n\n}\n\nmessage NetworkCtrlPayload {\n    NetworkCtrlMsgType msg = 1;\n    Status status = 2;\n    oneof payload {\n        CmdCtrlWifiReset cmd_ctrl_wifi_reset = 11;\n        RespCtrlWifiReset resp_ctrl_wifi_reset = 12;\n        CmdCtrlWifiReprov cmd_ctrl_wifi_reprov = 13;\n        RespCtrlWifiReprov resp_ctrl_wifi_reprov = 14;\n        CmdCtrlThreadReset cmd_ctrl_thread_reset = 15;\n        RespCtrlThreadReset resp_ctrl_thread_reset = 16;\n        CmdCtrlThreadReprov cmd_ctrl_thread_reprov = 17;\n        RespCtrlThreadReprov resp_ctrl_thread_reprov = 18;\n    }\n}\n"
  },
  {
    "path": "network_provisioning/proto/network_scan.proto",
    "content": "syntax = \"proto3\";\n\nimport \"constants.proto\";\nimport \"network_constants.proto\";\n\nmessage CmdScanWifiStart {\n    bool blocking = 1;\n    bool passive = 2;\n    uint32 group_channels = 3;\n    uint32 period_ms = 4;\n}\n\nmessage CmdScanThreadStart {\n    bool blocking = 1;\n    uint32 channel_mask = 2;\n}\n\nmessage RespScanWifiStart {\n}\n\nmessage RespScanThreadStart {\n}\n\nmessage CmdScanWifiStatus {\n}\n\nmessage CmdScanThreadStatus {\n}\n\nmessage RespScanWifiStatus {\n    bool scan_finished = 1;\n    uint32 result_count = 2;\n}\n\nmessage RespScanThreadStatus {\n    bool scan_finished = 1;\n    uint32 result_count = 2;\n}\n\nmessage CmdScanWifiResult {\n    uint32 start_index = 1;\n    uint32 count = 2;\n}\n\nmessage CmdScanThreadResult {\n    uint32 start_index = 1;\n    uint32 count = 2;\n}\n\nmessage WiFiScanResult {\n    bytes ssid = 1;\n    uint32 channel = 2;\n    int32 rssi = 3;\n    bytes bssid = 4;\n    WifiAuthMode auth = 5;\n}\n\nmessage ThreadScanResult {\n    uint32 pan_id = 1;\n    uint32 channel = 2;\n    int32 rssi = 3;\n    uint32 lqi = 4;\n    bytes ext_addr = 5;\n    string network_name = 6;\n    bytes ext_pan_id = 7;\n}\n\nmessage RespScanWifiResult {\n    repeated WiFiScanResult entries = 1;\n}\n\nmessage RespScanThreadResult {\n    repeated ThreadScanResult entries = 1;\n}\n\n\nenum NetworkScanMsgType {\n    TypeCmdScanWifiStart = 0;\n    TypeRespScanWifiStart = 1;\n    TypeCmdScanWifiStatus = 2;\n    TypeRespScanWifiStatus = 3;\n    TypeCmdScanWifiResult = 4;\n    TypeRespScanWifiResult = 5;\n    TypeCmdScanThreadStart = 6;\n    TypeRespScanThreadStart = 7;\n    TypeCmdScanThreadStatus = 8;\n    TypeRespScanThreadStatus = 9;\n    TypeCmdScanThreadResult = 10;\n    TypeRespScanThreadResult = 11;\n}\n\nmessage NetworkScanPayload {\n    NetworkScanMsgType msg = 1;\n    Status status = 2;\n    oneof payload {\n        CmdScanWifiStart cmd_scan_wifi_start = 10;\n        RespScanWifiStart resp_scan_wifi_start = 11;\n        CmdScanWifiStatus cmd_scan_wifi_status = 12;\n        RespScanWifiStatus resp_scan_wifi_status = 13;\n        CmdScanWifiResult cmd_scan_wifi_result = 14;\n        RespScanWifiResult resp_scan_wifi_result = 15;\n        CmdScanThreadStart cmd_scan_thread_start = 16;\n        RespScanThreadStart resp_scan_thread_start = 17;\n        CmdScanThreadStatus cmd_scan_thread_status = 18;\n        RespScanThreadStatus resp_scan_thread_status = 19;\n        CmdScanThreadResult cmd_scan_thread_result = 20;\n        RespScanThreadResult resp_scan_thread_result = 21;\n    }\n}\n"
  },
  {
    "path": "network_provisioning/proto-c/network_config.pb-c.c",
    "content": "/* Generated by the protocol buffer compiler.  DO NOT EDIT! */\n/* Generated from: network_config.proto */\n\n/* Do not generate deprecated warnings for self */\n#ifndef PROTOBUF_C__NO_DEPRECATED\n#define PROTOBUF_C__NO_DEPRECATED\n#endif\n\n#include \"network_config.pb-c.h\"\nvoid   cmd_get_wifi_status__init\n                     (CmdGetWifiStatus         *message)\n{\n  static const CmdGetWifiStatus init_value = CMD_GET_WIFI_STATUS__INIT;\n  *message = init_value;\n}\nsize_t cmd_get_wifi_status__get_packed_size\n                     (const CmdGetWifiStatus *message)\n{\n  assert(message->base.descriptor == &cmd_get_wifi_status__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t cmd_get_wifi_status__pack\n                     (const CmdGetWifiStatus *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &cmd_get_wifi_status__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t cmd_get_wifi_status__pack_to_buffer\n                     (const CmdGetWifiStatus *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &cmd_get_wifi_status__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nCmdGetWifiStatus *\n       cmd_get_wifi_status__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (CmdGetWifiStatus *)\n     protobuf_c_message_unpack (&cmd_get_wifi_status__descriptor,\n                                allocator, len, data);\n}\nvoid   cmd_get_wifi_status__free_unpacked\n                     (CmdGetWifiStatus *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &cmd_get_wifi_status__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   resp_get_wifi_status__init\n                     (RespGetWifiStatus         *message)\n{\n  static const RespGetWifiStatus init_value = RESP_GET_WIFI_STATUS__INIT;\n  *message = init_value;\n}\nsize_t resp_get_wifi_status__get_packed_size\n                     (const RespGetWifiStatus *message)\n{\n  assert(message->base.descriptor == &resp_get_wifi_status__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t resp_get_wifi_status__pack\n                     (const RespGetWifiStatus *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &resp_get_wifi_status__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t resp_get_wifi_status__pack_to_buffer\n                     (const RespGetWifiStatus *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &resp_get_wifi_status__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nRespGetWifiStatus *\n       resp_get_wifi_status__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (RespGetWifiStatus *)\n     protobuf_c_message_unpack (&resp_get_wifi_status__descriptor,\n                                allocator, len, data);\n}\nvoid   resp_get_wifi_status__free_unpacked\n                     (RespGetWifiStatus *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &resp_get_wifi_status__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   cmd_get_thread_status__init\n                     (CmdGetThreadStatus         *message)\n{\n  static const CmdGetThreadStatus init_value = CMD_GET_THREAD_STATUS__INIT;\n  *message = init_value;\n}\nsize_t cmd_get_thread_status__get_packed_size\n                     (const CmdGetThreadStatus *message)\n{\n  assert(message->base.descriptor == &cmd_get_thread_status__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t cmd_get_thread_status__pack\n                     (const CmdGetThreadStatus *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &cmd_get_thread_status__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t cmd_get_thread_status__pack_to_buffer\n                     (const CmdGetThreadStatus *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &cmd_get_thread_status__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nCmdGetThreadStatus *\n       cmd_get_thread_status__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (CmdGetThreadStatus *)\n     protobuf_c_message_unpack (&cmd_get_thread_status__descriptor,\n                                allocator, len, data);\n}\nvoid   cmd_get_thread_status__free_unpacked\n                     (CmdGetThreadStatus *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &cmd_get_thread_status__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   resp_get_thread_status__init\n                     (RespGetThreadStatus         *message)\n{\n  static const RespGetThreadStatus init_value = RESP_GET_THREAD_STATUS__INIT;\n  *message = init_value;\n}\nsize_t resp_get_thread_status__get_packed_size\n                     (const RespGetThreadStatus *message)\n{\n  assert(message->base.descriptor == &resp_get_thread_status__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t resp_get_thread_status__pack\n                     (const RespGetThreadStatus *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &resp_get_thread_status__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t resp_get_thread_status__pack_to_buffer\n                     (const RespGetThreadStatus *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &resp_get_thread_status__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nRespGetThreadStatus *\n       resp_get_thread_status__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (RespGetThreadStatus *)\n     protobuf_c_message_unpack (&resp_get_thread_status__descriptor,\n                                allocator, len, data);\n}\nvoid   resp_get_thread_status__free_unpacked\n                     (RespGetThreadStatus *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &resp_get_thread_status__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   cmd_set_wifi_config__init\n                     (CmdSetWifiConfig         *message)\n{\n  static const CmdSetWifiConfig init_value = CMD_SET_WIFI_CONFIG__INIT;\n  *message = init_value;\n}\nsize_t cmd_set_wifi_config__get_packed_size\n                     (const CmdSetWifiConfig *message)\n{\n  assert(message->base.descriptor == &cmd_set_wifi_config__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t cmd_set_wifi_config__pack\n                     (const CmdSetWifiConfig *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &cmd_set_wifi_config__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t cmd_set_wifi_config__pack_to_buffer\n                     (const CmdSetWifiConfig *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &cmd_set_wifi_config__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nCmdSetWifiConfig *\n       cmd_set_wifi_config__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (CmdSetWifiConfig *)\n     protobuf_c_message_unpack (&cmd_set_wifi_config__descriptor,\n                                allocator, len, data);\n}\nvoid   cmd_set_wifi_config__free_unpacked\n                     (CmdSetWifiConfig *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &cmd_set_wifi_config__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   cmd_set_thread_config__init\n                     (CmdSetThreadConfig         *message)\n{\n  static const CmdSetThreadConfig init_value = CMD_SET_THREAD_CONFIG__INIT;\n  *message = init_value;\n}\nsize_t cmd_set_thread_config__get_packed_size\n                     (const CmdSetThreadConfig *message)\n{\n  assert(message->base.descriptor == &cmd_set_thread_config__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t cmd_set_thread_config__pack\n                     (const CmdSetThreadConfig *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &cmd_set_thread_config__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t cmd_set_thread_config__pack_to_buffer\n                     (const CmdSetThreadConfig *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &cmd_set_thread_config__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nCmdSetThreadConfig *\n       cmd_set_thread_config__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (CmdSetThreadConfig *)\n     protobuf_c_message_unpack (&cmd_set_thread_config__descriptor,\n                                allocator, len, data);\n}\nvoid   cmd_set_thread_config__free_unpacked\n                     (CmdSetThreadConfig *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &cmd_set_thread_config__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   resp_set_wifi_config__init\n                     (RespSetWifiConfig         *message)\n{\n  static const RespSetWifiConfig init_value = RESP_SET_WIFI_CONFIG__INIT;\n  *message = init_value;\n}\nsize_t resp_set_wifi_config__get_packed_size\n                     (const RespSetWifiConfig *message)\n{\n  assert(message->base.descriptor == &resp_set_wifi_config__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t resp_set_wifi_config__pack\n                     (const RespSetWifiConfig *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &resp_set_wifi_config__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t resp_set_wifi_config__pack_to_buffer\n                     (const RespSetWifiConfig *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &resp_set_wifi_config__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nRespSetWifiConfig *\n       resp_set_wifi_config__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (RespSetWifiConfig *)\n     protobuf_c_message_unpack (&resp_set_wifi_config__descriptor,\n                                allocator, len, data);\n}\nvoid   resp_set_wifi_config__free_unpacked\n                     (RespSetWifiConfig *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &resp_set_wifi_config__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   resp_set_thread_config__init\n                     (RespSetThreadConfig         *message)\n{\n  static const RespSetThreadConfig init_value = RESP_SET_THREAD_CONFIG__INIT;\n  *message = init_value;\n}\nsize_t resp_set_thread_config__get_packed_size\n                     (const RespSetThreadConfig *message)\n{\n  assert(message->base.descriptor == &resp_set_thread_config__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t resp_set_thread_config__pack\n                     (const RespSetThreadConfig *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &resp_set_thread_config__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t resp_set_thread_config__pack_to_buffer\n                     (const RespSetThreadConfig *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &resp_set_thread_config__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nRespSetThreadConfig *\n       resp_set_thread_config__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (RespSetThreadConfig *)\n     protobuf_c_message_unpack (&resp_set_thread_config__descriptor,\n                                allocator, len, data);\n}\nvoid   resp_set_thread_config__free_unpacked\n                     (RespSetThreadConfig *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &resp_set_thread_config__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   cmd_apply_wifi_config__init\n                     (CmdApplyWifiConfig         *message)\n{\n  static const CmdApplyWifiConfig init_value = CMD_APPLY_WIFI_CONFIG__INIT;\n  *message = init_value;\n}\nsize_t cmd_apply_wifi_config__get_packed_size\n                     (const CmdApplyWifiConfig *message)\n{\n  assert(message->base.descriptor == &cmd_apply_wifi_config__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t cmd_apply_wifi_config__pack\n                     (const CmdApplyWifiConfig *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &cmd_apply_wifi_config__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t cmd_apply_wifi_config__pack_to_buffer\n                     (const CmdApplyWifiConfig *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &cmd_apply_wifi_config__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nCmdApplyWifiConfig *\n       cmd_apply_wifi_config__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (CmdApplyWifiConfig *)\n     protobuf_c_message_unpack (&cmd_apply_wifi_config__descriptor,\n                                allocator, len, data);\n}\nvoid   cmd_apply_wifi_config__free_unpacked\n                     (CmdApplyWifiConfig *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &cmd_apply_wifi_config__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   cmd_apply_thread_config__init\n                     (CmdApplyThreadConfig         *message)\n{\n  static const CmdApplyThreadConfig init_value = CMD_APPLY_THREAD_CONFIG__INIT;\n  *message = init_value;\n}\nsize_t cmd_apply_thread_config__get_packed_size\n                     (const CmdApplyThreadConfig *message)\n{\n  assert(message->base.descriptor == &cmd_apply_thread_config__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t cmd_apply_thread_config__pack\n                     (const CmdApplyThreadConfig *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &cmd_apply_thread_config__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t cmd_apply_thread_config__pack_to_buffer\n                     (const CmdApplyThreadConfig *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &cmd_apply_thread_config__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nCmdApplyThreadConfig *\n       cmd_apply_thread_config__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (CmdApplyThreadConfig *)\n     protobuf_c_message_unpack (&cmd_apply_thread_config__descriptor,\n                                allocator, len, data);\n}\nvoid   cmd_apply_thread_config__free_unpacked\n                     (CmdApplyThreadConfig *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &cmd_apply_thread_config__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   resp_apply_wifi_config__init\n                     (RespApplyWifiConfig         *message)\n{\n  static const RespApplyWifiConfig init_value = RESP_APPLY_WIFI_CONFIG__INIT;\n  *message = init_value;\n}\nsize_t resp_apply_wifi_config__get_packed_size\n                     (const RespApplyWifiConfig *message)\n{\n  assert(message->base.descriptor == &resp_apply_wifi_config__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t resp_apply_wifi_config__pack\n                     (const RespApplyWifiConfig *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &resp_apply_wifi_config__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t resp_apply_wifi_config__pack_to_buffer\n                     (const RespApplyWifiConfig *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &resp_apply_wifi_config__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nRespApplyWifiConfig *\n       resp_apply_wifi_config__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (RespApplyWifiConfig *)\n     protobuf_c_message_unpack (&resp_apply_wifi_config__descriptor,\n                                allocator, len, data);\n}\nvoid   resp_apply_wifi_config__free_unpacked\n                     (RespApplyWifiConfig *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &resp_apply_wifi_config__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   resp_apply_thread_config__init\n                     (RespApplyThreadConfig         *message)\n{\n  static const RespApplyThreadConfig init_value = RESP_APPLY_THREAD_CONFIG__INIT;\n  *message = init_value;\n}\nsize_t resp_apply_thread_config__get_packed_size\n                     (const RespApplyThreadConfig *message)\n{\n  assert(message->base.descriptor == &resp_apply_thread_config__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t resp_apply_thread_config__pack\n                     (const RespApplyThreadConfig *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &resp_apply_thread_config__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t resp_apply_thread_config__pack_to_buffer\n                     (const RespApplyThreadConfig *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &resp_apply_thread_config__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nRespApplyThreadConfig *\n       resp_apply_thread_config__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (RespApplyThreadConfig *)\n     protobuf_c_message_unpack (&resp_apply_thread_config__descriptor,\n                                allocator, len, data);\n}\nvoid   resp_apply_thread_config__free_unpacked\n                     (RespApplyThreadConfig *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &resp_apply_thread_config__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   network_config_payload__init\n                     (NetworkConfigPayload         *message)\n{\n  static const NetworkConfigPayload init_value = NETWORK_CONFIG_PAYLOAD__INIT;\n  *message = init_value;\n}\nsize_t network_config_payload__get_packed_size\n                     (const NetworkConfigPayload *message)\n{\n  assert(message->base.descriptor == &network_config_payload__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t network_config_payload__pack\n                     (const NetworkConfigPayload *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &network_config_payload__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t network_config_payload__pack_to_buffer\n                     (const NetworkConfigPayload *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &network_config_payload__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nNetworkConfigPayload *\n       network_config_payload__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (NetworkConfigPayload *)\n     protobuf_c_message_unpack (&network_config_payload__descriptor,\n                                allocator, len, data);\n}\nvoid   network_config_payload__free_unpacked\n                     (NetworkConfigPayload *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &network_config_payload__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\n#define cmd_get_wifi_status__field_descriptors NULL\n#define cmd_get_wifi_status__field_indices_by_name NULL\n#define cmd_get_wifi_status__number_ranges NULL\nconst ProtobufCMessageDescriptor cmd_get_wifi_status__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"CmdGetWifiStatus\",\n  \"CmdGetWifiStatus\",\n  \"CmdGetWifiStatus\",\n  \"\",\n  sizeof(CmdGetWifiStatus),\n  0,\n  cmd_get_wifi_status__field_descriptors,\n  cmd_get_wifi_status__field_indices_by_name,\n  0,  cmd_get_wifi_status__number_ranges,\n  (ProtobufCMessageInit) cmd_get_wifi_status__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor resp_get_wifi_status__field_descriptors[5] =\n{\n  {\n    \"status\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_ENUM,\n    0,   /* quantifier_offset */\n    offsetof(RespGetWifiStatus, status),\n    &status__descriptor,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"wifi_sta_state\",\n    2,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_ENUM,\n    0,   /* quantifier_offset */\n    offsetof(RespGetWifiStatus, wifi_sta_state),\n    &wifi_station_state__descriptor,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"wifi_fail_reason\",\n    10,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_ENUM,\n    offsetof(RespGetWifiStatus, state_case),\n    offsetof(RespGetWifiStatus, wifi_fail_reason),\n    &wifi_connect_failed_reason__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"wifi_connected\",\n    11,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(RespGetWifiStatus, state_case),\n    offsetof(RespGetWifiStatus, wifi_connected),\n    &wifi_connected_state__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"attempt_failed\",\n    12,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(RespGetWifiStatus, state_case),\n    offsetof(RespGetWifiStatus, attempt_failed),\n    &wifi_attempt_failed__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned resp_get_wifi_status__field_indices_by_name[] = {\n  4,   /* field[4] = attempt_failed */\n  0,   /* field[0] = status */\n  3,   /* field[3] = wifi_connected */\n  2,   /* field[2] = wifi_fail_reason */\n  1,   /* field[1] = wifi_sta_state */\n};\nstatic const ProtobufCIntRange resp_get_wifi_status__number_ranges[2 + 1] =\n{\n  { 1, 0 },\n  { 10, 2 },\n  { 0, 5 }\n};\nconst ProtobufCMessageDescriptor resp_get_wifi_status__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"RespGetWifiStatus\",\n  \"RespGetWifiStatus\",\n  \"RespGetWifiStatus\",\n  \"\",\n  sizeof(RespGetWifiStatus),\n  5,\n  resp_get_wifi_status__field_descriptors,\n  resp_get_wifi_status__field_indices_by_name,\n  2,  resp_get_wifi_status__number_ranges,\n  (ProtobufCMessageInit) resp_get_wifi_status__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\n#define cmd_get_thread_status__field_descriptors NULL\n#define cmd_get_thread_status__field_indices_by_name NULL\n#define cmd_get_thread_status__number_ranges NULL\nconst ProtobufCMessageDescriptor cmd_get_thread_status__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"CmdGetThreadStatus\",\n  \"CmdGetThreadStatus\",\n  \"CmdGetThreadStatus\",\n  \"\",\n  sizeof(CmdGetThreadStatus),\n  0,\n  cmd_get_thread_status__field_descriptors,\n  cmd_get_thread_status__field_indices_by_name,\n  0,  cmd_get_thread_status__number_ranges,\n  (ProtobufCMessageInit) cmd_get_thread_status__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor resp_get_thread_status__field_descriptors[4] =\n{\n  {\n    \"status\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_ENUM,\n    0,   /* quantifier_offset */\n    offsetof(RespGetThreadStatus, status),\n    &status__descriptor,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"thread_state\",\n    2,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_ENUM,\n    0,   /* quantifier_offset */\n    offsetof(RespGetThreadStatus, thread_state),\n    &thread_network_state__descriptor,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"thread_fail_reason\",\n    10,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_ENUM,\n    offsetof(RespGetThreadStatus, state_case),\n    offsetof(RespGetThreadStatus, thread_fail_reason),\n    &thread_attach_failed_reason__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"thread_attached\",\n    11,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(RespGetThreadStatus, state_case),\n    offsetof(RespGetThreadStatus, thread_attached),\n    &thread_attach_state__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned resp_get_thread_status__field_indices_by_name[] = {\n  0,   /* field[0] = status */\n  3,   /* field[3] = thread_attached */\n  2,   /* field[2] = thread_fail_reason */\n  1,   /* field[1] = thread_state */\n};\nstatic const ProtobufCIntRange resp_get_thread_status__number_ranges[2 + 1] =\n{\n  { 1, 0 },\n  { 10, 2 },\n  { 0, 4 }\n};\nconst ProtobufCMessageDescriptor resp_get_thread_status__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"RespGetThreadStatus\",\n  \"RespGetThreadStatus\",\n  \"RespGetThreadStatus\",\n  \"\",\n  sizeof(RespGetThreadStatus),\n  4,\n  resp_get_thread_status__field_descriptors,\n  resp_get_thread_status__field_indices_by_name,\n  2,  resp_get_thread_status__number_ranges,\n  (ProtobufCMessageInit) resp_get_thread_status__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor cmd_set_wifi_config__field_descriptors[4] =\n{\n  {\n    \"ssid\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_BYTES,\n    0,   /* quantifier_offset */\n    offsetof(CmdSetWifiConfig, ssid),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"passphrase\",\n    2,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_BYTES,\n    0,   /* quantifier_offset */\n    offsetof(CmdSetWifiConfig, passphrase),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"bssid\",\n    3,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_BYTES,\n    0,   /* quantifier_offset */\n    offsetof(CmdSetWifiConfig, bssid),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"channel\",\n    4,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_INT32,\n    0,   /* quantifier_offset */\n    offsetof(CmdSetWifiConfig, channel),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned cmd_set_wifi_config__field_indices_by_name[] = {\n  2,   /* field[2] = bssid */\n  3,   /* field[3] = channel */\n  1,   /* field[1] = passphrase */\n  0,   /* field[0] = ssid */\n};\nstatic const ProtobufCIntRange cmd_set_wifi_config__number_ranges[1 + 1] =\n{\n  { 1, 0 },\n  { 0, 4 }\n};\nconst ProtobufCMessageDescriptor cmd_set_wifi_config__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"CmdSetWifiConfig\",\n  \"CmdSetWifiConfig\",\n  \"CmdSetWifiConfig\",\n  \"\",\n  sizeof(CmdSetWifiConfig),\n  4,\n  cmd_set_wifi_config__field_descriptors,\n  cmd_set_wifi_config__field_indices_by_name,\n  1,  cmd_set_wifi_config__number_ranges,\n  (ProtobufCMessageInit) cmd_set_wifi_config__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor cmd_set_thread_config__field_descriptors[1] =\n{\n  {\n    \"dataset\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_BYTES,\n    0,   /* quantifier_offset */\n    offsetof(CmdSetThreadConfig, dataset),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned cmd_set_thread_config__field_indices_by_name[] = {\n  0,   /* field[0] = dataset */\n};\nstatic const ProtobufCIntRange cmd_set_thread_config__number_ranges[1 + 1] =\n{\n  { 1, 0 },\n  { 0, 1 }\n};\nconst ProtobufCMessageDescriptor cmd_set_thread_config__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"CmdSetThreadConfig\",\n  \"CmdSetThreadConfig\",\n  \"CmdSetThreadConfig\",\n  \"\",\n  sizeof(CmdSetThreadConfig),\n  1,\n  cmd_set_thread_config__field_descriptors,\n  cmd_set_thread_config__field_indices_by_name,\n  1,  cmd_set_thread_config__number_ranges,\n  (ProtobufCMessageInit) cmd_set_thread_config__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor resp_set_wifi_config__field_descriptors[1] =\n{\n  {\n    \"status\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_ENUM,\n    0,   /* quantifier_offset */\n    offsetof(RespSetWifiConfig, status),\n    &status__descriptor,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned resp_set_wifi_config__field_indices_by_name[] = {\n  0,   /* field[0] = status */\n};\nstatic const ProtobufCIntRange resp_set_wifi_config__number_ranges[1 + 1] =\n{\n  { 1, 0 },\n  { 0, 1 }\n};\nconst ProtobufCMessageDescriptor resp_set_wifi_config__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"RespSetWifiConfig\",\n  \"RespSetWifiConfig\",\n  \"RespSetWifiConfig\",\n  \"\",\n  sizeof(RespSetWifiConfig),\n  1,\n  resp_set_wifi_config__field_descriptors,\n  resp_set_wifi_config__field_indices_by_name,\n  1,  resp_set_wifi_config__number_ranges,\n  (ProtobufCMessageInit) resp_set_wifi_config__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor resp_set_thread_config__field_descriptors[1] =\n{\n  {\n    \"status\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_ENUM,\n    0,   /* quantifier_offset */\n    offsetof(RespSetThreadConfig, status),\n    &status__descriptor,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned resp_set_thread_config__field_indices_by_name[] = {\n  0,   /* field[0] = status */\n};\nstatic const ProtobufCIntRange resp_set_thread_config__number_ranges[1 + 1] =\n{\n  { 1, 0 },\n  { 0, 1 }\n};\nconst ProtobufCMessageDescriptor resp_set_thread_config__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"RespSetThreadConfig\",\n  \"RespSetThreadConfig\",\n  \"RespSetThreadConfig\",\n  \"\",\n  sizeof(RespSetThreadConfig),\n  1,\n  resp_set_thread_config__field_descriptors,\n  resp_set_thread_config__field_indices_by_name,\n  1,  resp_set_thread_config__number_ranges,\n  (ProtobufCMessageInit) resp_set_thread_config__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\n#define cmd_apply_wifi_config__field_descriptors NULL\n#define cmd_apply_wifi_config__field_indices_by_name NULL\n#define cmd_apply_wifi_config__number_ranges NULL\nconst ProtobufCMessageDescriptor cmd_apply_wifi_config__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"CmdApplyWifiConfig\",\n  \"CmdApplyWifiConfig\",\n  \"CmdApplyWifiConfig\",\n  \"\",\n  sizeof(CmdApplyWifiConfig),\n  0,\n  cmd_apply_wifi_config__field_descriptors,\n  cmd_apply_wifi_config__field_indices_by_name,\n  0,  cmd_apply_wifi_config__number_ranges,\n  (ProtobufCMessageInit) cmd_apply_wifi_config__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\n#define cmd_apply_thread_config__field_descriptors NULL\n#define cmd_apply_thread_config__field_indices_by_name NULL\n#define cmd_apply_thread_config__number_ranges NULL\nconst ProtobufCMessageDescriptor cmd_apply_thread_config__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"CmdApplyThreadConfig\",\n  \"CmdApplyThreadConfig\",\n  \"CmdApplyThreadConfig\",\n  \"\",\n  sizeof(CmdApplyThreadConfig),\n  0,\n  cmd_apply_thread_config__field_descriptors,\n  cmd_apply_thread_config__field_indices_by_name,\n  0,  cmd_apply_thread_config__number_ranges,\n  (ProtobufCMessageInit) cmd_apply_thread_config__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor resp_apply_wifi_config__field_descriptors[1] =\n{\n  {\n    \"status\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_ENUM,\n    0,   /* quantifier_offset */\n    offsetof(RespApplyWifiConfig, status),\n    &status__descriptor,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned resp_apply_wifi_config__field_indices_by_name[] = {\n  0,   /* field[0] = status */\n};\nstatic const ProtobufCIntRange resp_apply_wifi_config__number_ranges[1 + 1] =\n{\n  { 1, 0 },\n  { 0, 1 }\n};\nconst ProtobufCMessageDescriptor resp_apply_wifi_config__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"RespApplyWifiConfig\",\n  \"RespApplyWifiConfig\",\n  \"RespApplyWifiConfig\",\n  \"\",\n  sizeof(RespApplyWifiConfig),\n  1,\n  resp_apply_wifi_config__field_descriptors,\n  resp_apply_wifi_config__field_indices_by_name,\n  1,  resp_apply_wifi_config__number_ranges,\n  (ProtobufCMessageInit) resp_apply_wifi_config__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor resp_apply_thread_config__field_descriptors[1] =\n{\n  {\n    \"status\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_ENUM,\n    0,   /* quantifier_offset */\n    offsetof(RespApplyThreadConfig, status),\n    &status__descriptor,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned resp_apply_thread_config__field_indices_by_name[] = {\n  0,   /* field[0] = status */\n};\nstatic const ProtobufCIntRange resp_apply_thread_config__number_ranges[1 + 1] =\n{\n  { 1, 0 },\n  { 0, 1 }\n};\nconst ProtobufCMessageDescriptor resp_apply_thread_config__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"RespApplyThreadConfig\",\n  \"RespApplyThreadConfig\",\n  \"RespApplyThreadConfig\",\n  \"\",\n  sizeof(RespApplyThreadConfig),\n  1,\n  resp_apply_thread_config__field_descriptors,\n  resp_apply_thread_config__field_indices_by_name,\n  1,  resp_apply_thread_config__number_ranges,\n  (ProtobufCMessageInit) resp_apply_thread_config__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor network_config_payload__field_descriptors[13] =\n{\n  {\n    \"msg\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_ENUM,\n    0,   /* quantifier_offset */\n    offsetof(NetworkConfigPayload, msg),\n    &network_config_msg_type__descriptor,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"cmd_get_wifi_status\",\n    10,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkConfigPayload, payload_case),\n    offsetof(NetworkConfigPayload, cmd_get_wifi_status),\n    &cmd_get_wifi_status__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"resp_get_wifi_status\",\n    11,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkConfigPayload, payload_case),\n    offsetof(NetworkConfigPayload, resp_get_wifi_status),\n    &resp_get_wifi_status__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"cmd_set_wifi_config\",\n    12,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkConfigPayload, payload_case),\n    offsetof(NetworkConfigPayload, cmd_set_wifi_config),\n    &cmd_set_wifi_config__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"resp_set_wifi_config\",\n    13,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkConfigPayload, payload_case),\n    offsetof(NetworkConfigPayload, resp_set_wifi_config),\n    &resp_set_wifi_config__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"cmd_apply_wifi_config\",\n    14,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkConfigPayload, payload_case),\n    offsetof(NetworkConfigPayload, cmd_apply_wifi_config),\n    &cmd_apply_wifi_config__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"resp_apply_wifi_config\",\n    15,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkConfigPayload, payload_case),\n    offsetof(NetworkConfigPayload, resp_apply_wifi_config),\n    &resp_apply_wifi_config__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"cmd_get_thread_status\",\n    16,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkConfigPayload, payload_case),\n    offsetof(NetworkConfigPayload, cmd_get_thread_status),\n    &cmd_get_thread_status__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"resp_get_thread_status\",\n    17,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkConfigPayload, payload_case),\n    offsetof(NetworkConfigPayload, resp_get_thread_status),\n    &resp_get_thread_status__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"cmd_set_thread_config\",\n    18,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkConfigPayload, payload_case),\n    offsetof(NetworkConfigPayload, cmd_set_thread_config),\n    &cmd_set_thread_config__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"resp_set_thread_config\",\n    19,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkConfigPayload, payload_case),\n    offsetof(NetworkConfigPayload, resp_set_thread_config),\n    &resp_set_thread_config__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"cmd_apply_thread_config\",\n    20,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkConfigPayload, payload_case),\n    offsetof(NetworkConfigPayload, cmd_apply_thread_config),\n    &cmd_apply_thread_config__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"resp_apply_thread_config\",\n    21,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkConfigPayload, payload_case),\n    offsetof(NetworkConfigPayload, resp_apply_thread_config),\n    &resp_apply_thread_config__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned network_config_payload__field_indices_by_name[] = {\n  11,   /* field[11] = cmd_apply_thread_config */\n  5,   /* field[5] = cmd_apply_wifi_config */\n  7,   /* field[7] = cmd_get_thread_status */\n  1,   /* field[1] = cmd_get_wifi_status */\n  9,   /* field[9] = cmd_set_thread_config */\n  3,   /* field[3] = cmd_set_wifi_config */\n  0,   /* field[0] = msg */\n  12,   /* field[12] = resp_apply_thread_config */\n  6,   /* field[6] = resp_apply_wifi_config */\n  8,   /* field[8] = resp_get_thread_status */\n  2,   /* field[2] = resp_get_wifi_status */\n  10,   /* field[10] = resp_set_thread_config */\n  4,   /* field[4] = resp_set_wifi_config */\n};\nstatic const ProtobufCIntRange network_config_payload__number_ranges[2 + 1] =\n{\n  { 1, 0 },\n  { 10, 1 },\n  { 0, 13 }\n};\nconst ProtobufCMessageDescriptor network_config_payload__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"NetworkConfigPayload\",\n  \"NetworkConfigPayload\",\n  \"NetworkConfigPayload\",\n  \"\",\n  sizeof(NetworkConfigPayload),\n  13,\n  network_config_payload__field_descriptors,\n  network_config_payload__field_indices_by_name,\n  2,  network_config_payload__number_ranges,\n  (ProtobufCMessageInit) network_config_payload__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCEnumValue network_config_msg_type__enum_values_by_number[12] =\n{\n  { \"TypeCmdGetWifiStatus\", \"NETWORK_CONFIG_MSG_TYPE__TypeCmdGetWifiStatus\", 0 },\n  { \"TypeRespGetWifiStatus\", \"NETWORK_CONFIG_MSG_TYPE__TypeRespGetWifiStatus\", 1 },\n  { \"TypeCmdSetWifiConfig\", \"NETWORK_CONFIG_MSG_TYPE__TypeCmdSetWifiConfig\", 2 },\n  { \"TypeRespSetWifiConfig\", \"NETWORK_CONFIG_MSG_TYPE__TypeRespSetWifiConfig\", 3 },\n  { \"TypeCmdApplyWifiConfig\", \"NETWORK_CONFIG_MSG_TYPE__TypeCmdApplyWifiConfig\", 4 },\n  { \"TypeRespApplyWifiConfig\", \"NETWORK_CONFIG_MSG_TYPE__TypeRespApplyWifiConfig\", 5 },\n  { \"TypeCmdGetThreadStatus\", \"NETWORK_CONFIG_MSG_TYPE__TypeCmdGetThreadStatus\", 6 },\n  { \"TypeRespGetThreadStatus\", \"NETWORK_CONFIG_MSG_TYPE__TypeRespGetThreadStatus\", 7 },\n  { \"TypeCmdSetThreadConfig\", \"NETWORK_CONFIG_MSG_TYPE__TypeCmdSetThreadConfig\", 8 },\n  { \"TypeRespSetThreadConfig\", \"NETWORK_CONFIG_MSG_TYPE__TypeRespSetThreadConfig\", 9 },\n  { \"TypeCmdApplyThreadConfig\", \"NETWORK_CONFIG_MSG_TYPE__TypeCmdApplyThreadConfig\", 10 },\n  { \"TypeRespApplyThreadConfig\", \"NETWORK_CONFIG_MSG_TYPE__TypeRespApplyThreadConfig\", 11 },\n};\nstatic const ProtobufCIntRange network_config_msg_type__value_ranges[] = {\n{0, 0},{0, 12}\n};\nstatic const ProtobufCEnumValueIndex network_config_msg_type__enum_values_by_name[12] =\n{\n  { \"TypeCmdApplyThreadConfig\", 10 },\n  { \"TypeCmdApplyWifiConfig\", 4 },\n  { \"TypeCmdGetThreadStatus\", 6 },\n  { \"TypeCmdGetWifiStatus\", 0 },\n  { \"TypeCmdSetThreadConfig\", 8 },\n  { \"TypeCmdSetWifiConfig\", 2 },\n  { \"TypeRespApplyThreadConfig\", 11 },\n  { \"TypeRespApplyWifiConfig\", 5 },\n  { \"TypeRespGetThreadStatus\", 7 },\n  { \"TypeRespGetWifiStatus\", 1 },\n  { \"TypeRespSetThreadConfig\", 9 },\n  { \"TypeRespSetWifiConfig\", 3 },\n};\nconst ProtobufCEnumDescriptor network_config_msg_type__descriptor =\n{\n  PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,\n  \"NetworkConfigMsgType\",\n  \"NetworkConfigMsgType\",\n  \"NetworkConfigMsgType\",\n  \"\",\n  12,\n  network_config_msg_type__enum_values_by_number,\n  12,\n  network_config_msg_type__enum_values_by_name,\n  1,\n  network_config_msg_type__value_ranges,\n  NULL,NULL,NULL,NULL   /* reserved[1234] */\n};\n"
  },
  {
    "path": "network_provisioning/proto-c/network_config.pb-c.h",
    "content": "/* Generated by the protocol buffer compiler.  DO NOT EDIT! */\n/* Generated from: network_config.proto */\n\n#ifndef PROTOBUF_C_network_5fconfig_2eproto__INCLUDED\n#define PROTOBUF_C_network_5fconfig_2eproto__INCLUDED\n\n#include <protobuf-c/protobuf-c.h>\n\nPROTOBUF_C__BEGIN_DECLS\n\n#if PROTOBUF_C_VERSION_NUMBER < 1003000\n# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.\n#elif 1004000 < PROTOBUF_C_MIN_COMPILER_VERSION\n# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.\n#endif\n\n#include \"constants.pb-c.h\"\n#include \"network_constants.pb-c.h\"\n\ntypedef struct CmdGetWifiStatus CmdGetWifiStatus;\ntypedef struct RespGetWifiStatus RespGetWifiStatus;\ntypedef struct CmdGetThreadStatus CmdGetThreadStatus;\ntypedef struct RespGetThreadStatus RespGetThreadStatus;\ntypedef struct CmdSetWifiConfig CmdSetWifiConfig;\ntypedef struct CmdSetThreadConfig CmdSetThreadConfig;\ntypedef struct RespSetWifiConfig RespSetWifiConfig;\ntypedef struct RespSetThreadConfig RespSetThreadConfig;\ntypedef struct CmdApplyWifiConfig CmdApplyWifiConfig;\ntypedef struct CmdApplyThreadConfig CmdApplyThreadConfig;\ntypedef struct RespApplyWifiConfig RespApplyWifiConfig;\ntypedef struct RespApplyThreadConfig RespApplyThreadConfig;\ntypedef struct NetworkConfigPayload NetworkConfigPayload;\n\n\n/* --- enums --- */\n\ntypedef enum _NetworkConfigMsgType {\n  NETWORK_CONFIG_MSG_TYPE__TypeCmdGetWifiStatus = 0,\n  NETWORK_CONFIG_MSG_TYPE__TypeRespGetWifiStatus = 1,\n  NETWORK_CONFIG_MSG_TYPE__TypeCmdSetWifiConfig = 2,\n  NETWORK_CONFIG_MSG_TYPE__TypeRespSetWifiConfig = 3,\n  NETWORK_CONFIG_MSG_TYPE__TypeCmdApplyWifiConfig = 4,\n  NETWORK_CONFIG_MSG_TYPE__TypeRespApplyWifiConfig = 5,\n  NETWORK_CONFIG_MSG_TYPE__TypeCmdGetThreadStatus = 6,\n  NETWORK_CONFIG_MSG_TYPE__TypeRespGetThreadStatus = 7,\n  NETWORK_CONFIG_MSG_TYPE__TypeCmdSetThreadConfig = 8,\n  NETWORK_CONFIG_MSG_TYPE__TypeRespSetThreadConfig = 9,\n  NETWORK_CONFIG_MSG_TYPE__TypeCmdApplyThreadConfig = 10,\n  NETWORK_CONFIG_MSG_TYPE__TypeRespApplyThreadConfig = 11\n    PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(NETWORK_CONFIG_MSG_TYPE)\n} NetworkConfigMsgType;\n\n/* --- messages --- */\n\nstruct  CmdGetWifiStatus\n{\n  ProtobufCMessage base;\n};\n#define CMD_GET_WIFI_STATUS__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&cmd_get_wifi_status__descriptor) \\\n     }\n\n\ntypedef enum {\n  RESP_GET_WIFI_STATUS__STATE__NOT_SET = 0,\n  RESP_GET_WIFI_STATUS__STATE_WIFI_FAIL_REASON = 10,\n  RESP_GET_WIFI_STATUS__STATE_WIFI_CONNECTED = 11,\n  RESP_GET_WIFI_STATUS__STATE_ATTEMPT_FAILED = 12\n    PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(RESP_GET_WIFI_STATUS__STATE__CASE)\n} RespGetWifiStatus__StateCase;\n\nstruct  RespGetWifiStatus\n{\n  ProtobufCMessage base;\n  Status status;\n  WifiStationState wifi_sta_state;\n  RespGetWifiStatus__StateCase state_case;\n  union {\n    WifiConnectFailedReason wifi_fail_reason;\n    WifiConnectedState *wifi_connected;\n    WifiAttemptFailed *attempt_failed;\n  };\n};\n#define RESP_GET_WIFI_STATUS__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&resp_get_wifi_status__descriptor) \\\n    , STATUS__Success, WIFI_STATION_STATE__Connected, RESP_GET_WIFI_STATUS__STATE__NOT_SET, {0} }\n\n\nstruct  CmdGetThreadStatus\n{\n  ProtobufCMessage base;\n};\n#define CMD_GET_THREAD_STATUS__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&cmd_get_thread_status__descriptor) \\\n     }\n\n\ntypedef enum {\n  RESP_GET_THREAD_STATUS__STATE__NOT_SET = 0,\n  RESP_GET_THREAD_STATUS__STATE_THREAD_FAIL_REASON = 10,\n  RESP_GET_THREAD_STATUS__STATE_THREAD_ATTACHED = 11\n    PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(RESP_GET_THREAD_STATUS__STATE__CASE)\n} RespGetThreadStatus__StateCase;\n\nstruct  RespGetThreadStatus\n{\n  ProtobufCMessage base;\n  Status status;\n  ThreadNetworkState thread_state;\n  RespGetThreadStatus__StateCase state_case;\n  union {\n    ThreadAttachFailedReason thread_fail_reason;\n    ThreadAttachState *thread_attached;\n  };\n};\n#define RESP_GET_THREAD_STATUS__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&resp_get_thread_status__descriptor) \\\n    , STATUS__Success, THREAD_NETWORK_STATE__Attached, RESP_GET_THREAD_STATUS__STATE__NOT_SET, {0} }\n\n\nstruct  CmdSetWifiConfig\n{\n  ProtobufCMessage base;\n  ProtobufCBinaryData ssid;\n  ProtobufCBinaryData passphrase;\n  ProtobufCBinaryData bssid;\n  int32_t channel;\n};\n#define CMD_SET_WIFI_CONFIG__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&cmd_set_wifi_config__descriptor) \\\n    , {0,NULL}, {0,NULL}, {0,NULL}, 0 }\n\n\nstruct  CmdSetThreadConfig\n{\n  ProtobufCMessage base;\n  ProtobufCBinaryData dataset;\n};\n#define CMD_SET_THREAD_CONFIG__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&cmd_set_thread_config__descriptor) \\\n    , {0,NULL} }\n\n\nstruct  RespSetWifiConfig\n{\n  ProtobufCMessage base;\n  Status status;\n};\n#define RESP_SET_WIFI_CONFIG__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&resp_set_wifi_config__descriptor) \\\n    , STATUS__Success }\n\n\nstruct  RespSetThreadConfig\n{\n  ProtobufCMessage base;\n  Status status;\n};\n#define RESP_SET_THREAD_CONFIG__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&resp_set_thread_config__descriptor) \\\n    , STATUS__Success }\n\n\nstruct  CmdApplyWifiConfig\n{\n  ProtobufCMessage base;\n};\n#define CMD_APPLY_WIFI_CONFIG__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&cmd_apply_wifi_config__descriptor) \\\n     }\n\n\nstruct  CmdApplyThreadConfig\n{\n  ProtobufCMessage base;\n};\n#define CMD_APPLY_THREAD_CONFIG__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&cmd_apply_thread_config__descriptor) \\\n     }\n\n\nstruct  RespApplyWifiConfig\n{\n  ProtobufCMessage base;\n  Status status;\n};\n#define RESP_APPLY_WIFI_CONFIG__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&resp_apply_wifi_config__descriptor) \\\n    , STATUS__Success }\n\n\nstruct  RespApplyThreadConfig\n{\n  ProtobufCMessage base;\n  Status status;\n};\n#define RESP_APPLY_THREAD_CONFIG__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&resp_apply_thread_config__descriptor) \\\n    , STATUS__Success }\n\n\ntypedef enum {\n  NETWORK_CONFIG_PAYLOAD__PAYLOAD__NOT_SET = 0,\n  NETWORK_CONFIG_PAYLOAD__PAYLOAD_CMD_GET_WIFI_STATUS = 10,\n  NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_GET_WIFI_STATUS = 11,\n  NETWORK_CONFIG_PAYLOAD__PAYLOAD_CMD_SET_WIFI_CONFIG = 12,\n  NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_SET_WIFI_CONFIG = 13,\n  NETWORK_CONFIG_PAYLOAD__PAYLOAD_CMD_APPLY_WIFI_CONFIG = 14,\n  NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_APPLY_WIFI_CONFIG = 15,\n  NETWORK_CONFIG_PAYLOAD__PAYLOAD_CMD_GET_THREAD_STATUS = 16,\n  NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_GET_THREAD_STATUS = 17,\n  NETWORK_CONFIG_PAYLOAD__PAYLOAD_CMD_SET_THREAD_CONFIG = 18,\n  NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_SET_THREAD_CONFIG = 19,\n  NETWORK_CONFIG_PAYLOAD__PAYLOAD_CMD_APPLY_THREAD_CONFIG = 20,\n  NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_APPLY_THREAD_CONFIG = 21\n    PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(NETWORK_CONFIG_PAYLOAD__PAYLOAD__CASE)\n} NetworkConfigPayload__PayloadCase;\n\nstruct  NetworkConfigPayload\n{\n  ProtobufCMessage base;\n  NetworkConfigMsgType msg;\n  NetworkConfigPayload__PayloadCase payload_case;\n  union {\n    CmdGetWifiStatus *cmd_get_wifi_status;\n    RespGetWifiStatus *resp_get_wifi_status;\n    CmdSetWifiConfig *cmd_set_wifi_config;\n    RespSetWifiConfig *resp_set_wifi_config;\n    CmdApplyWifiConfig *cmd_apply_wifi_config;\n    RespApplyWifiConfig *resp_apply_wifi_config;\n    CmdGetThreadStatus *cmd_get_thread_status;\n    RespGetThreadStatus *resp_get_thread_status;\n    CmdSetThreadConfig *cmd_set_thread_config;\n    RespSetThreadConfig *resp_set_thread_config;\n    CmdApplyThreadConfig *cmd_apply_thread_config;\n    RespApplyThreadConfig *resp_apply_thread_config;\n  };\n};\n#define NETWORK_CONFIG_PAYLOAD__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&network_config_payload__descriptor) \\\n    , NETWORK_CONFIG_MSG_TYPE__TypeCmdGetWifiStatus, NETWORK_CONFIG_PAYLOAD__PAYLOAD__NOT_SET, {0} }\n\n\n/* CmdGetWifiStatus methods */\nvoid   cmd_get_wifi_status__init\n                     (CmdGetWifiStatus         *message);\nsize_t cmd_get_wifi_status__get_packed_size\n                     (const CmdGetWifiStatus   *message);\nsize_t cmd_get_wifi_status__pack\n                     (const CmdGetWifiStatus   *message,\n                      uint8_t             *out);\nsize_t cmd_get_wifi_status__pack_to_buffer\n                     (const CmdGetWifiStatus   *message,\n                      ProtobufCBuffer     *buffer);\nCmdGetWifiStatus *\n       cmd_get_wifi_status__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   cmd_get_wifi_status__free_unpacked\n                     (CmdGetWifiStatus *message,\n                      ProtobufCAllocator *allocator);\n/* RespGetWifiStatus methods */\nvoid   resp_get_wifi_status__init\n                     (RespGetWifiStatus         *message);\nsize_t resp_get_wifi_status__get_packed_size\n                     (const RespGetWifiStatus   *message);\nsize_t resp_get_wifi_status__pack\n                     (const RespGetWifiStatus   *message,\n                      uint8_t             *out);\nsize_t resp_get_wifi_status__pack_to_buffer\n                     (const RespGetWifiStatus   *message,\n                      ProtobufCBuffer     *buffer);\nRespGetWifiStatus *\n       resp_get_wifi_status__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   resp_get_wifi_status__free_unpacked\n                     (RespGetWifiStatus *message,\n                      ProtobufCAllocator *allocator);\n/* CmdGetThreadStatus methods */\nvoid   cmd_get_thread_status__init\n                     (CmdGetThreadStatus         *message);\nsize_t cmd_get_thread_status__get_packed_size\n                     (const CmdGetThreadStatus   *message);\nsize_t cmd_get_thread_status__pack\n                     (const CmdGetThreadStatus   *message,\n                      uint8_t             *out);\nsize_t cmd_get_thread_status__pack_to_buffer\n                     (const CmdGetThreadStatus   *message,\n                      ProtobufCBuffer     *buffer);\nCmdGetThreadStatus *\n       cmd_get_thread_status__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   cmd_get_thread_status__free_unpacked\n                     (CmdGetThreadStatus *message,\n                      ProtobufCAllocator *allocator);\n/* RespGetThreadStatus methods */\nvoid   resp_get_thread_status__init\n                     (RespGetThreadStatus         *message);\nsize_t resp_get_thread_status__get_packed_size\n                     (const RespGetThreadStatus   *message);\nsize_t resp_get_thread_status__pack\n                     (const RespGetThreadStatus   *message,\n                      uint8_t             *out);\nsize_t resp_get_thread_status__pack_to_buffer\n                     (const RespGetThreadStatus   *message,\n                      ProtobufCBuffer     *buffer);\nRespGetThreadStatus *\n       resp_get_thread_status__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   resp_get_thread_status__free_unpacked\n                     (RespGetThreadStatus *message,\n                      ProtobufCAllocator *allocator);\n/* CmdSetWifiConfig methods */\nvoid   cmd_set_wifi_config__init\n                     (CmdSetWifiConfig         *message);\nsize_t cmd_set_wifi_config__get_packed_size\n                     (const CmdSetWifiConfig   *message);\nsize_t cmd_set_wifi_config__pack\n                     (const CmdSetWifiConfig   *message,\n                      uint8_t             *out);\nsize_t cmd_set_wifi_config__pack_to_buffer\n                     (const CmdSetWifiConfig   *message,\n                      ProtobufCBuffer     *buffer);\nCmdSetWifiConfig *\n       cmd_set_wifi_config__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   cmd_set_wifi_config__free_unpacked\n                     (CmdSetWifiConfig *message,\n                      ProtobufCAllocator *allocator);\n/* CmdSetThreadConfig methods */\nvoid   cmd_set_thread_config__init\n                     (CmdSetThreadConfig         *message);\nsize_t cmd_set_thread_config__get_packed_size\n                     (const CmdSetThreadConfig   *message);\nsize_t cmd_set_thread_config__pack\n                     (const CmdSetThreadConfig   *message,\n                      uint8_t             *out);\nsize_t cmd_set_thread_config__pack_to_buffer\n                     (const CmdSetThreadConfig   *message,\n                      ProtobufCBuffer     *buffer);\nCmdSetThreadConfig *\n       cmd_set_thread_config__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   cmd_set_thread_config__free_unpacked\n                     (CmdSetThreadConfig *message,\n                      ProtobufCAllocator *allocator);\n/* RespSetWifiConfig methods */\nvoid   resp_set_wifi_config__init\n                     (RespSetWifiConfig         *message);\nsize_t resp_set_wifi_config__get_packed_size\n                     (const RespSetWifiConfig   *message);\nsize_t resp_set_wifi_config__pack\n                     (const RespSetWifiConfig   *message,\n                      uint8_t             *out);\nsize_t resp_set_wifi_config__pack_to_buffer\n                     (const RespSetWifiConfig   *message,\n                      ProtobufCBuffer     *buffer);\nRespSetWifiConfig *\n       resp_set_wifi_config__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   resp_set_wifi_config__free_unpacked\n                     (RespSetWifiConfig *message,\n                      ProtobufCAllocator *allocator);\n/* RespSetThreadConfig methods */\nvoid   resp_set_thread_config__init\n                     (RespSetThreadConfig         *message);\nsize_t resp_set_thread_config__get_packed_size\n                     (const RespSetThreadConfig   *message);\nsize_t resp_set_thread_config__pack\n                     (const RespSetThreadConfig   *message,\n                      uint8_t             *out);\nsize_t resp_set_thread_config__pack_to_buffer\n                     (const RespSetThreadConfig   *message,\n                      ProtobufCBuffer     *buffer);\nRespSetThreadConfig *\n       resp_set_thread_config__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   resp_set_thread_config__free_unpacked\n                     (RespSetThreadConfig *message,\n                      ProtobufCAllocator *allocator);\n/* CmdApplyWifiConfig methods */\nvoid   cmd_apply_wifi_config__init\n                     (CmdApplyWifiConfig         *message);\nsize_t cmd_apply_wifi_config__get_packed_size\n                     (const CmdApplyWifiConfig   *message);\nsize_t cmd_apply_wifi_config__pack\n                     (const CmdApplyWifiConfig   *message,\n                      uint8_t             *out);\nsize_t cmd_apply_wifi_config__pack_to_buffer\n                     (const CmdApplyWifiConfig   *message,\n                      ProtobufCBuffer     *buffer);\nCmdApplyWifiConfig *\n       cmd_apply_wifi_config__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   cmd_apply_wifi_config__free_unpacked\n                     (CmdApplyWifiConfig *message,\n                      ProtobufCAllocator *allocator);\n/* CmdApplyThreadConfig methods */\nvoid   cmd_apply_thread_config__init\n                     (CmdApplyThreadConfig         *message);\nsize_t cmd_apply_thread_config__get_packed_size\n                     (const CmdApplyThreadConfig   *message);\nsize_t cmd_apply_thread_config__pack\n                     (const CmdApplyThreadConfig   *message,\n                      uint8_t             *out);\nsize_t cmd_apply_thread_config__pack_to_buffer\n                     (const CmdApplyThreadConfig   *message,\n                      ProtobufCBuffer     *buffer);\nCmdApplyThreadConfig *\n       cmd_apply_thread_config__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   cmd_apply_thread_config__free_unpacked\n                     (CmdApplyThreadConfig *message,\n                      ProtobufCAllocator *allocator);\n/* RespApplyWifiConfig methods */\nvoid   resp_apply_wifi_config__init\n                     (RespApplyWifiConfig         *message);\nsize_t resp_apply_wifi_config__get_packed_size\n                     (const RespApplyWifiConfig   *message);\nsize_t resp_apply_wifi_config__pack\n                     (const RespApplyWifiConfig   *message,\n                      uint8_t             *out);\nsize_t resp_apply_wifi_config__pack_to_buffer\n                     (const RespApplyWifiConfig   *message,\n                      ProtobufCBuffer     *buffer);\nRespApplyWifiConfig *\n       resp_apply_wifi_config__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   resp_apply_wifi_config__free_unpacked\n                     (RespApplyWifiConfig *message,\n                      ProtobufCAllocator *allocator);\n/* RespApplyThreadConfig methods */\nvoid   resp_apply_thread_config__init\n                     (RespApplyThreadConfig         *message);\nsize_t resp_apply_thread_config__get_packed_size\n                     (const RespApplyThreadConfig   *message);\nsize_t resp_apply_thread_config__pack\n                     (const RespApplyThreadConfig   *message,\n                      uint8_t             *out);\nsize_t resp_apply_thread_config__pack_to_buffer\n                     (const RespApplyThreadConfig   *message,\n                      ProtobufCBuffer     *buffer);\nRespApplyThreadConfig *\n       resp_apply_thread_config__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   resp_apply_thread_config__free_unpacked\n                     (RespApplyThreadConfig *message,\n                      ProtobufCAllocator *allocator);\n/* NetworkConfigPayload methods */\nvoid   network_config_payload__init\n                     (NetworkConfigPayload         *message);\nsize_t network_config_payload__get_packed_size\n                     (const NetworkConfigPayload   *message);\nsize_t network_config_payload__pack\n                     (const NetworkConfigPayload   *message,\n                      uint8_t             *out);\nsize_t network_config_payload__pack_to_buffer\n                     (const NetworkConfigPayload   *message,\n                      ProtobufCBuffer     *buffer);\nNetworkConfigPayload *\n       network_config_payload__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   network_config_payload__free_unpacked\n                     (NetworkConfigPayload *message,\n                      ProtobufCAllocator *allocator);\n/* --- per-message closures --- */\n\ntypedef void (*CmdGetWifiStatus_Closure)\n                 (const CmdGetWifiStatus *message,\n                  void *closure_data);\ntypedef void (*RespGetWifiStatus_Closure)\n                 (const RespGetWifiStatus *message,\n                  void *closure_data);\ntypedef void (*CmdGetThreadStatus_Closure)\n                 (const CmdGetThreadStatus *message,\n                  void *closure_data);\ntypedef void (*RespGetThreadStatus_Closure)\n                 (const RespGetThreadStatus *message,\n                  void *closure_data);\ntypedef void (*CmdSetWifiConfig_Closure)\n                 (const CmdSetWifiConfig *message,\n                  void *closure_data);\ntypedef void (*CmdSetThreadConfig_Closure)\n                 (const CmdSetThreadConfig *message,\n                  void *closure_data);\ntypedef void (*RespSetWifiConfig_Closure)\n                 (const RespSetWifiConfig *message,\n                  void *closure_data);\ntypedef void (*RespSetThreadConfig_Closure)\n                 (const RespSetThreadConfig *message,\n                  void *closure_data);\ntypedef void (*CmdApplyWifiConfig_Closure)\n                 (const CmdApplyWifiConfig *message,\n                  void *closure_data);\ntypedef void (*CmdApplyThreadConfig_Closure)\n                 (const CmdApplyThreadConfig *message,\n                  void *closure_data);\ntypedef void (*RespApplyWifiConfig_Closure)\n                 (const RespApplyWifiConfig *message,\n                  void *closure_data);\ntypedef void (*RespApplyThreadConfig_Closure)\n                 (const RespApplyThreadConfig *message,\n                  void *closure_data);\ntypedef void (*NetworkConfigPayload_Closure)\n                 (const NetworkConfigPayload *message,\n                  void *closure_data);\n\n/* --- services --- */\n\n\n/* --- descriptors --- */\n\nextern const ProtobufCEnumDescriptor    network_config_msg_type__descriptor;\nextern const ProtobufCMessageDescriptor cmd_get_wifi_status__descriptor;\nextern const ProtobufCMessageDescriptor resp_get_wifi_status__descriptor;\nextern const ProtobufCMessageDescriptor cmd_get_thread_status__descriptor;\nextern const ProtobufCMessageDescriptor resp_get_thread_status__descriptor;\nextern const ProtobufCMessageDescriptor cmd_set_wifi_config__descriptor;\nextern const ProtobufCMessageDescriptor cmd_set_thread_config__descriptor;\nextern const ProtobufCMessageDescriptor resp_set_wifi_config__descriptor;\nextern const ProtobufCMessageDescriptor resp_set_thread_config__descriptor;\nextern const ProtobufCMessageDescriptor cmd_apply_wifi_config__descriptor;\nextern const ProtobufCMessageDescriptor cmd_apply_thread_config__descriptor;\nextern const ProtobufCMessageDescriptor resp_apply_wifi_config__descriptor;\nextern const ProtobufCMessageDescriptor resp_apply_thread_config__descriptor;\nextern const ProtobufCMessageDescriptor network_config_payload__descriptor;\n\nPROTOBUF_C__END_DECLS\n\n\n#endif  /* PROTOBUF_C_network_5fconfig_2eproto__INCLUDED */\n"
  },
  {
    "path": "network_provisioning/proto-c/network_constants.pb-c.c",
    "content": "/* Generated by the protocol buffer compiler.  DO NOT EDIT! */\n/* Generated from: network_constants.proto */\n\n/* Do not generate deprecated warnings for self */\n#ifndef PROTOBUF_C__NO_DEPRECATED\n#define PROTOBUF_C__NO_DEPRECATED\n#endif\n\n#include \"network_constants.pb-c.h\"\nvoid   wifi_connected_state__init\n                     (WifiConnectedState         *message)\n{\n  static const WifiConnectedState init_value = WIFI_CONNECTED_STATE__INIT;\n  *message = init_value;\n}\nsize_t wifi_connected_state__get_packed_size\n                     (const WifiConnectedState *message)\n{\n  assert(message->base.descriptor == &wifi_connected_state__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t wifi_connected_state__pack\n                     (const WifiConnectedState *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &wifi_connected_state__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t wifi_connected_state__pack_to_buffer\n                     (const WifiConnectedState *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &wifi_connected_state__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nWifiConnectedState *\n       wifi_connected_state__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (WifiConnectedState *)\n     protobuf_c_message_unpack (&wifi_connected_state__descriptor,\n                                allocator, len, data);\n}\nvoid   wifi_connected_state__free_unpacked\n                     (WifiConnectedState *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &wifi_connected_state__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   wifi_attempt_failed__init\n                     (WifiAttemptFailed         *message)\n{\n  static const WifiAttemptFailed init_value = WIFI_ATTEMPT_FAILED__INIT;\n  *message = init_value;\n}\nsize_t wifi_attempt_failed__get_packed_size\n                     (const WifiAttemptFailed *message)\n{\n  assert(message->base.descriptor == &wifi_attempt_failed__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t wifi_attempt_failed__pack\n                     (const WifiAttemptFailed *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &wifi_attempt_failed__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t wifi_attempt_failed__pack_to_buffer\n                     (const WifiAttemptFailed *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &wifi_attempt_failed__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nWifiAttemptFailed *\n       wifi_attempt_failed__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (WifiAttemptFailed *)\n     protobuf_c_message_unpack (&wifi_attempt_failed__descriptor,\n                                allocator, len, data);\n}\nvoid   wifi_attempt_failed__free_unpacked\n                     (WifiAttemptFailed *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &wifi_attempt_failed__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   thread_attach_state__init\n                     (ThreadAttachState         *message)\n{\n  static const ThreadAttachState init_value = THREAD_ATTACH_STATE__INIT;\n  *message = init_value;\n}\nsize_t thread_attach_state__get_packed_size\n                     (const ThreadAttachState *message)\n{\n  assert(message->base.descriptor == &thread_attach_state__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t thread_attach_state__pack\n                     (const ThreadAttachState *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &thread_attach_state__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t thread_attach_state__pack_to_buffer\n                     (const ThreadAttachState *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &thread_attach_state__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nThreadAttachState *\n       thread_attach_state__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (ThreadAttachState *)\n     protobuf_c_message_unpack (&thread_attach_state__descriptor,\n                                allocator, len, data);\n}\nvoid   thread_attach_state__free_unpacked\n                     (ThreadAttachState *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &thread_attach_state__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nstatic const ProtobufCFieldDescriptor wifi_connected_state__field_descriptors[5] =\n{\n  {\n    \"ip4_addr\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_STRING,\n    0,   /* quantifier_offset */\n    offsetof(WifiConnectedState, ip4_addr),\n    NULL,\n    &protobuf_c_empty_string,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"auth_mode\",\n    2,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_ENUM,\n    0,   /* quantifier_offset */\n    offsetof(WifiConnectedState, auth_mode),\n    &wifi_auth_mode__descriptor,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"ssid\",\n    3,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_BYTES,\n    0,   /* quantifier_offset */\n    offsetof(WifiConnectedState, ssid),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"bssid\",\n    4,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_BYTES,\n    0,   /* quantifier_offset */\n    offsetof(WifiConnectedState, bssid),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"channel\",\n    5,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_INT32,\n    0,   /* quantifier_offset */\n    offsetof(WifiConnectedState, channel),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned wifi_connected_state__field_indices_by_name[] = {\n  1,   /* field[1] = auth_mode */\n  3,   /* field[3] = bssid */\n  4,   /* field[4] = channel */\n  0,   /* field[0] = ip4_addr */\n  2,   /* field[2] = ssid */\n};\nstatic const ProtobufCIntRange wifi_connected_state__number_ranges[1 + 1] =\n{\n  { 1, 0 },\n  { 0, 5 }\n};\nconst ProtobufCMessageDescriptor wifi_connected_state__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"WifiConnectedState\",\n  \"WifiConnectedState\",\n  \"WifiConnectedState\",\n  \"\",\n  sizeof(WifiConnectedState),\n  5,\n  wifi_connected_state__field_descriptors,\n  wifi_connected_state__field_indices_by_name,\n  1,  wifi_connected_state__number_ranges,\n  (ProtobufCMessageInit) wifi_connected_state__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor wifi_attempt_failed__field_descriptors[1] =\n{\n  {\n    \"attempts_remaining\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_UINT32,\n    0,   /* quantifier_offset */\n    offsetof(WifiAttemptFailed, attempts_remaining),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned wifi_attempt_failed__field_indices_by_name[] = {\n  0,   /* field[0] = attempts_remaining */\n};\nstatic const ProtobufCIntRange wifi_attempt_failed__number_ranges[1 + 1] =\n{\n  { 1, 0 },\n  { 0, 1 }\n};\nconst ProtobufCMessageDescriptor wifi_attempt_failed__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"WifiAttemptFailed\",\n  \"WifiAttemptFailed\",\n  \"WifiAttemptFailed\",\n  \"\",\n  sizeof(WifiAttemptFailed),\n  1,\n  wifi_attempt_failed__field_descriptors,\n  wifi_attempt_failed__field_indices_by_name,\n  1,  wifi_attempt_failed__number_ranges,\n  (ProtobufCMessageInit) wifi_attempt_failed__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor thread_attach_state__field_descriptors[4] =\n{\n  {\n    \"pan_id\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_UINT32,\n    0,   /* quantifier_offset */\n    offsetof(ThreadAttachState, pan_id),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"ext_pan_id\",\n    2,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_BYTES,\n    0,   /* quantifier_offset */\n    offsetof(ThreadAttachState, ext_pan_id),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"channel\",\n    3,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_UINT32,\n    0,   /* quantifier_offset */\n    offsetof(ThreadAttachState, channel),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"name\",\n    4,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_STRING,\n    0,   /* quantifier_offset */\n    offsetof(ThreadAttachState, name),\n    NULL,\n    &protobuf_c_empty_string,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned thread_attach_state__field_indices_by_name[] = {\n  2,   /* field[2] = channel */\n  1,   /* field[1] = ext_pan_id */\n  3,   /* field[3] = name */\n  0,   /* field[0] = pan_id */\n};\nstatic const ProtobufCIntRange thread_attach_state__number_ranges[1 + 1] =\n{\n  { 1, 0 },\n  { 0, 4 }\n};\nconst ProtobufCMessageDescriptor thread_attach_state__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"ThreadAttachState\",\n  \"ThreadAttachState\",\n  \"ThreadAttachState\",\n  \"\",\n  sizeof(ThreadAttachState),\n  4,\n  thread_attach_state__field_descriptors,\n  thread_attach_state__field_indices_by_name,\n  1,  thread_attach_state__number_ranges,\n  (ProtobufCMessageInit) thread_attach_state__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCEnumValue wifi_station_state__enum_values_by_number[4] =\n{\n  { \"Connected\", \"WIFI_STATION_STATE__Connected\", 0 },\n  { \"Connecting\", \"WIFI_STATION_STATE__Connecting\", 1 },\n  { \"Disconnected\", \"WIFI_STATION_STATE__Disconnected\", 2 },\n  { \"ConnectionFailed\", \"WIFI_STATION_STATE__ConnectionFailed\", 3 },\n};\nstatic const ProtobufCIntRange wifi_station_state__value_ranges[] = {\n{0, 0},{0, 4}\n};\nstatic const ProtobufCEnumValueIndex wifi_station_state__enum_values_by_name[4] =\n{\n  { \"Connected\", 0 },\n  { \"Connecting\", 1 },\n  { \"ConnectionFailed\", 3 },\n  { \"Disconnected\", 2 },\n};\nconst ProtobufCEnumDescriptor wifi_station_state__descriptor =\n{\n  PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,\n  \"WifiStationState\",\n  \"WifiStationState\",\n  \"WifiStationState\",\n  \"\",\n  4,\n  wifi_station_state__enum_values_by_number,\n  4,\n  wifi_station_state__enum_values_by_name,\n  1,\n  wifi_station_state__value_ranges,\n  NULL,NULL,NULL,NULL   /* reserved[1234] */\n};\nstatic const ProtobufCEnumValue wifi_connect_failed_reason__enum_values_by_number[2] =\n{\n  { \"AuthError\", \"WIFI_CONNECT_FAILED_REASON__AuthError\", 0 },\n  { \"WifiNetworkNotFound\", \"WIFI_CONNECT_FAILED_REASON__WifiNetworkNotFound\", 1 },\n};\nstatic const ProtobufCIntRange wifi_connect_failed_reason__value_ranges[] = {\n{0, 0},{0, 2}\n};\nstatic const ProtobufCEnumValueIndex wifi_connect_failed_reason__enum_values_by_name[2] =\n{\n  { \"AuthError\", 0 },\n  { \"WifiNetworkNotFound\", 1 },\n};\nconst ProtobufCEnumDescriptor wifi_connect_failed_reason__descriptor =\n{\n  PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,\n  \"WifiConnectFailedReason\",\n  \"WifiConnectFailedReason\",\n  \"WifiConnectFailedReason\",\n  \"\",\n  2,\n  wifi_connect_failed_reason__enum_values_by_number,\n  2,\n  wifi_connect_failed_reason__enum_values_by_name,\n  1,\n  wifi_connect_failed_reason__value_ranges,\n  NULL,NULL,NULL,NULL   /* reserved[1234] */\n};\nstatic const ProtobufCEnumValue wifi_auth_mode__enum_values_by_number[8] =\n{\n  { \"Open\", \"WIFI_AUTH_MODE__Open\", 0 },\n  { \"WEP\", \"WIFI_AUTH_MODE__WEP\", 1 },\n  { \"WPA_PSK\", \"WIFI_AUTH_MODE__WPA_PSK\", 2 },\n  { \"WPA2_PSK\", \"WIFI_AUTH_MODE__WPA2_PSK\", 3 },\n  { \"WPA_WPA2_PSK\", \"WIFI_AUTH_MODE__WPA_WPA2_PSK\", 4 },\n  { \"WPA2_ENTERPRISE\", \"WIFI_AUTH_MODE__WPA2_ENTERPRISE\", 5 },\n  { \"WPA3_PSK\", \"WIFI_AUTH_MODE__WPA3_PSK\", 6 },\n  { \"WPA2_WPA3_PSK\", \"WIFI_AUTH_MODE__WPA2_WPA3_PSK\", 7 },\n};\nstatic const ProtobufCIntRange wifi_auth_mode__value_ranges[] = {\n{0, 0},{0, 8}\n};\nstatic const ProtobufCEnumValueIndex wifi_auth_mode__enum_values_by_name[8] =\n{\n  { \"Open\", 0 },\n  { \"WEP\", 1 },\n  { \"WPA2_ENTERPRISE\", 5 },\n  { \"WPA2_PSK\", 3 },\n  { \"WPA2_WPA3_PSK\", 7 },\n  { \"WPA3_PSK\", 6 },\n  { \"WPA_PSK\", 2 },\n  { \"WPA_WPA2_PSK\", 4 },\n};\nconst ProtobufCEnumDescriptor wifi_auth_mode__descriptor =\n{\n  PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,\n  \"WifiAuthMode\",\n  \"WifiAuthMode\",\n  \"WifiAuthMode\",\n  \"\",\n  8,\n  wifi_auth_mode__enum_values_by_number,\n  8,\n  wifi_auth_mode__enum_values_by_name,\n  1,\n  wifi_auth_mode__value_ranges,\n  NULL,NULL,NULL,NULL   /* reserved[1234] */\n};\nstatic const ProtobufCEnumValue thread_network_state__enum_values_by_number[4] =\n{\n  { \"Attached\", \"THREAD_NETWORK_STATE__Attached\", 0 },\n  { \"Attaching\", \"THREAD_NETWORK_STATE__Attaching\", 1 },\n  { \"Dettached\", \"THREAD_NETWORK_STATE__Dettached\", 2 },\n  { \"AttachingFailed\", \"THREAD_NETWORK_STATE__AttachingFailed\", 3 },\n};\nstatic const ProtobufCIntRange thread_network_state__value_ranges[] = {\n{0, 0},{0, 4}\n};\nstatic const ProtobufCEnumValueIndex thread_network_state__enum_values_by_name[4] =\n{\n  { \"Attached\", 0 },\n  { \"Attaching\", 1 },\n  { \"AttachingFailed\", 3 },\n  { \"Dettached\", 2 },\n};\nconst ProtobufCEnumDescriptor thread_network_state__descriptor =\n{\n  PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,\n  \"ThreadNetworkState\",\n  \"ThreadNetworkState\",\n  \"ThreadNetworkState\",\n  \"\",\n  4,\n  thread_network_state__enum_values_by_number,\n  4,\n  thread_network_state__enum_values_by_name,\n  1,\n  thread_network_state__value_ranges,\n  NULL,NULL,NULL,NULL   /* reserved[1234] */\n};\nstatic const ProtobufCEnumValue thread_attach_failed_reason__enum_values_by_number[2] =\n{\n  { \"DatasetInvalid\", \"THREAD_ATTACH_FAILED_REASON__DatasetInvalid\", 0 },\n  { \"ThreadNetworkNotFound\", \"THREAD_ATTACH_FAILED_REASON__ThreadNetworkNotFound\", 1 },\n};\nstatic const ProtobufCIntRange thread_attach_failed_reason__value_ranges[] = {\n{0, 0},{0, 2}\n};\nstatic const ProtobufCEnumValueIndex thread_attach_failed_reason__enum_values_by_name[2] =\n{\n  { \"DatasetInvalid\", 0 },\n  { \"ThreadNetworkNotFound\", 1 },\n};\nconst ProtobufCEnumDescriptor thread_attach_failed_reason__descriptor =\n{\n  PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,\n  \"ThreadAttachFailedReason\",\n  \"ThreadAttachFailedReason\",\n  \"ThreadAttachFailedReason\",\n  \"\",\n  2,\n  thread_attach_failed_reason__enum_values_by_number,\n  2,\n  thread_attach_failed_reason__enum_values_by_name,\n  1,\n  thread_attach_failed_reason__value_ranges,\n  NULL,NULL,NULL,NULL   /* reserved[1234] */\n};\n"
  },
  {
    "path": "network_provisioning/proto-c/network_constants.pb-c.h",
    "content": "/* Generated by the protocol buffer compiler.  DO NOT EDIT! */\n/* Generated from: network_constants.proto */\n\n#ifndef PROTOBUF_C_network_5fconstants_2eproto__INCLUDED\n#define PROTOBUF_C_network_5fconstants_2eproto__INCLUDED\n\n#include <protobuf-c/protobuf-c.h>\n\nPROTOBUF_C__BEGIN_DECLS\n\n#if PROTOBUF_C_VERSION_NUMBER < 1003000\n# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.\n#elif 1004000 < PROTOBUF_C_MIN_COMPILER_VERSION\n# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.\n#endif\n\n\ntypedef struct WifiConnectedState WifiConnectedState;\ntypedef struct WifiAttemptFailed WifiAttemptFailed;\ntypedef struct ThreadAttachState ThreadAttachState;\n\n\n/* --- enums --- */\n\ntypedef enum _WifiStationState {\n  WIFI_STATION_STATE__Connected = 0,\n  WIFI_STATION_STATE__Connecting = 1,\n  WIFI_STATION_STATE__Disconnected = 2,\n  WIFI_STATION_STATE__ConnectionFailed = 3\n    PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(WIFI_STATION_STATE)\n} WifiStationState;\ntypedef enum _WifiConnectFailedReason {\n  WIFI_CONNECT_FAILED_REASON__AuthError = 0,\n  WIFI_CONNECT_FAILED_REASON__WifiNetworkNotFound = 1\n    PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(WIFI_CONNECT_FAILED_REASON)\n} WifiConnectFailedReason;\ntypedef enum _WifiAuthMode {\n  WIFI_AUTH_MODE__Open = 0,\n  WIFI_AUTH_MODE__WEP = 1,\n  WIFI_AUTH_MODE__WPA_PSK = 2,\n  WIFI_AUTH_MODE__WPA2_PSK = 3,\n  WIFI_AUTH_MODE__WPA_WPA2_PSK = 4,\n  WIFI_AUTH_MODE__WPA2_ENTERPRISE = 5,\n  WIFI_AUTH_MODE__WPA3_PSK = 6,\n  WIFI_AUTH_MODE__WPA2_WPA3_PSK = 7\n    PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(WIFI_AUTH_MODE)\n} WifiAuthMode;\ntypedef enum _ThreadNetworkState {\n  THREAD_NETWORK_STATE__Attached = 0,\n  THREAD_NETWORK_STATE__Attaching = 1,\n  THREAD_NETWORK_STATE__Dettached = 2,\n  THREAD_NETWORK_STATE__AttachingFailed = 3\n    PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(THREAD_NETWORK_STATE)\n} ThreadNetworkState;\ntypedef enum _ThreadAttachFailedReason {\n  THREAD_ATTACH_FAILED_REASON__DatasetInvalid = 0,\n  THREAD_ATTACH_FAILED_REASON__ThreadNetworkNotFound = 1\n    PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(THREAD_ATTACH_FAILED_REASON)\n} ThreadAttachFailedReason;\n\n/* --- messages --- */\n\nstruct  WifiConnectedState\n{\n  ProtobufCMessage base;\n  char *ip4_addr;\n  WifiAuthMode auth_mode;\n  ProtobufCBinaryData ssid;\n  ProtobufCBinaryData bssid;\n  int32_t channel;\n};\n#define WIFI_CONNECTED_STATE__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&wifi_connected_state__descriptor) \\\n    , (char *)protobuf_c_empty_string, WIFI_AUTH_MODE__Open, {0,NULL}, {0,NULL}, 0 }\n\n\nstruct  WifiAttemptFailed\n{\n  ProtobufCMessage base;\n  uint32_t attempts_remaining;\n};\n#define WIFI_ATTEMPT_FAILED__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&wifi_attempt_failed__descriptor) \\\n    , 0 }\n\n\nstruct  ThreadAttachState\n{\n  ProtobufCMessage base;\n  uint32_t pan_id;\n  ProtobufCBinaryData ext_pan_id;\n  uint32_t channel;\n  char *name;\n};\n#define THREAD_ATTACH_STATE__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&thread_attach_state__descriptor) \\\n    , 0, {0,NULL}, 0, (char *)protobuf_c_empty_string }\n\n\n/* WifiConnectedState methods */\nvoid   wifi_connected_state__init\n                     (WifiConnectedState         *message);\nsize_t wifi_connected_state__get_packed_size\n                     (const WifiConnectedState   *message);\nsize_t wifi_connected_state__pack\n                     (const WifiConnectedState   *message,\n                      uint8_t             *out);\nsize_t wifi_connected_state__pack_to_buffer\n                     (const WifiConnectedState   *message,\n                      ProtobufCBuffer     *buffer);\nWifiConnectedState *\n       wifi_connected_state__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   wifi_connected_state__free_unpacked\n                     (WifiConnectedState *message,\n                      ProtobufCAllocator *allocator);\n/* WifiAttemptFailed methods */\nvoid   wifi_attempt_failed__init\n                     (WifiAttemptFailed         *message);\nsize_t wifi_attempt_failed__get_packed_size\n                     (const WifiAttemptFailed   *message);\nsize_t wifi_attempt_failed__pack\n                     (const WifiAttemptFailed   *message,\n                      uint8_t             *out);\nsize_t wifi_attempt_failed__pack_to_buffer\n                     (const WifiAttemptFailed   *message,\n                      ProtobufCBuffer     *buffer);\nWifiAttemptFailed *\n       wifi_attempt_failed__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   wifi_attempt_failed__free_unpacked\n                     (WifiAttemptFailed *message,\n                      ProtobufCAllocator *allocator);\n/* ThreadAttachState methods */\nvoid   thread_attach_state__init\n                     (ThreadAttachState         *message);\nsize_t thread_attach_state__get_packed_size\n                     (const ThreadAttachState   *message);\nsize_t thread_attach_state__pack\n                     (const ThreadAttachState   *message,\n                      uint8_t             *out);\nsize_t thread_attach_state__pack_to_buffer\n                     (const ThreadAttachState   *message,\n                      ProtobufCBuffer     *buffer);\nThreadAttachState *\n       thread_attach_state__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   thread_attach_state__free_unpacked\n                     (ThreadAttachState *message,\n                      ProtobufCAllocator *allocator);\n/* --- per-message closures --- */\n\ntypedef void (*WifiConnectedState_Closure)\n                 (const WifiConnectedState *message,\n                  void *closure_data);\ntypedef void (*WifiAttemptFailed_Closure)\n                 (const WifiAttemptFailed *message,\n                  void *closure_data);\ntypedef void (*ThreadAttachState_Closure)\n                 (const ThreadAttachState *message,\n                  void *closure_data);\n\n/* --- services --- */\n\n\n/* --- descriptors --- */\n\nextern const ProtobufCEnumDescriptor    wifi_station_state__descriptor;\nextern const ProtobufCEnumDescriptor    wifi_connect_failed_reason__descriptor;\nextern const ProtobufCEnumDescriptor    wifi_auth_mode__descriptor;\nextern const ProtobufCEnumDescriptor    thread_network_state__descriptor;\nextern const ProtobufCEnumDescriptor    thread_attach_failed_reason__descriptor;\nextern const ProtobufCMessageDescriptor wifi_connected_state__descriptor;\nextern const ProtobufCMessageDescriptor wifi_attempt_failed__descriptor;\nextern const ProtobufCMessageDescriptor thread_attach_state__descriptor;\n\nPROTOBUF_C__END_DECLS\n\n\n#endif  /* PROTOBUF_C_network_5fconstants_2eproto__INCLUDED */\n"
  },
  {
    "path": "network_provisioning/proto-c/network_ctrl.pb-c.c",
    "content": "/* Generated by the protocol buffer compiler.  DO NOT EDIT! */\n/* Generated from: network_ctrl.proto */\n\n/* Do not generate deprecated warnings for self */\n#ifndef PROTOBUF_C__NO_DEPRECATED\n#define PROTOBUF_C__NO_DEPRECATED\n#endif\n\n#include \"network_ctrl.pb-c.h\"\nvoid   cmd_ctrl_wifi_reset__init\n                     (CmdCtrlWifiReset         *message)\n{\n  static const CmdCtrlWifiReset init_value = CMD_CTRL_WIFI_RESET__INIT;\n  *message = init_value;\n}\nsize_t cmd_ctrl_wifi_reset__get_packed_size\n                     (const CmdCtrlWifiReset *message)\n{\n  assert(message->base.descriptor == &cmd_ctrl_wifi_reset__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t cmd_ctrl_wifi_reset__pack\n                     (const CmdCtrlWifiReset *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &cmd_ctrl_wifi_reset__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t cmd_ctrl_wifi_reset__pack_to_buffer\n                     (const CmdCtrlWifiReset *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &cmd_ctrl_wifi_reset__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nCmdCtrlWifiReset *\n       cmd_ctrl_wifi_reset__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (CmdCtrlWifiReset *)\n     protobuf_c_message_unpack (&cmd_ctrl_wifi_reset__descriptor,\n                                allocator, len, data);\n}\nvoid   cmd_ctrl_wifi_reset__free_unpacked\n                     (CmdCtrlWifiReset *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &cmd_ctrl_wifi_reset__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   resp_ctrl_wifi_reset__init\n                     (RespCtrlWifiReset         *message)\n{\n  static const RespCtrlWifiReset init_value = RESP_CTRL_WIFI_RESET__INIT;\n  *message = init_value;\n}\nsize_t resp_ctrl_wifi_reset__get_packed_size\n                     (const RespCtrlWifiReset *message)\n{\n  assert(message->base.descriptor == &resp_ctrl_wifi_reset__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t resp_ctrl_wifi_reset__pack\n                     (const RespCtrlWifiReset *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &resp_ctrl_wifi_reset__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t resp_ctrl_wifi_reset__pack_to_buffer\n                     (const RespCtrlWifiReset *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &resp_ctrl_wifi_reset__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nRespCtrlWifiReset *\n       resp_ctrl_wifi_reset__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (RespCtrlWifiReset *)\n     protobuf_c_message_unpack (&resp_ctrl_wifi_reset__descriptor,\n                                allocator, len, data);\n}\nvoid   resp_ctrl_wifi_reset__free_unpacked\n                     (RespCtrlWifiReset *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &resp_ctrl_wifi_reset__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   cmd_ctrl_wifi_reprov__init\n                     (CmdCtrlWifiReprov         *message)\n{\n  static const CmdCtrlWifiReprov init_value = CMD_CTRL_WIFI_REPROV__INIT;\n  *message = init_value;\n}\nsize_t cmd_ctrl_wifi_reprov__get_packed_size\n                     (const CmdCtrlWifiReprov *message)\n{\n  assert(message->base.descriptor == &cmd_ctrl_wifi_reprov__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t cmd_ctrl_wifi_reprov__pack\n                     (const CmdCtrlWifiReprov *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &cmd_ctrl_wifi_reprov__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t cmd_ctrl_wifi_reprov__pack_to_buffer\n                     (const CmdCtrlWifiReprov *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &cmd_ctrl_wifi_reprov__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nCmdCtrlWifiReprov *\n       cmd_ctrl_wifi_reprov__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (CmdCtrlWifiReprov *)\n     protobuf_c_message_unpack (&cmd_ctrl_wifi_reprov__descriptor,\n                                allocator, len, data);\n}\nvoid   cmd_ctrl_wifi_reprov__free_unpacked\n                     (CmdCtrlWifiReprov *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &cmd_ctrl_wifi_reprov__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   resp_ctrl_wifi_reprov__init\n                     (RespCtrlWifiReprov         *message)\n{\n  static const RespCtrlWifiReprov init_value = RESP_CTRL_WIFI_REPROV__INIT;\n  *message = init_value;\n}\nsize_t resp_ctrl_wifi_reprov__get_packed_size\n                     (const RespCtrlWifiReprov *message)\n{\n  assert(message->base.descriptor == &resp_ctrl_wifi_reprov__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t resp_ctrl_wifi_reprov__pack\n                     (const RespCtrlWifiReprov *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &resp_ctrl_wifi_reprov__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t resp_ctrl_wifi_reprov__pack_to_buffer\n                     (const RespCtrlWifiReprov *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &resp_ctrl_wifi_reprov__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nRespCtrlWifiReprov *\n       resp_ctrl_wifi_reprov__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (RespCtrlWifiReprov *)\n     protobuf_c_message_unpack (&resp_ctrl_wifi_reprov__descriptor,\n                                allocator, len, data);\n}\nvoid   resp_ctrl_wifi_reprov__free_unpacked\n                     (RespCtrlWifiReprov *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &resp_ctrl_wifi_reprov__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   cmd_ctrl_thread_reset__init\n                     (CmdCtrlThreadReset         *message)\n{\n  static const CmdCtrlThreadReset init_value = CMD_CTRL_THREAD_RESET__INIT;\n  *message = init_value;\n}\nsize_t cmd_ctrl_thread_reset__get_packed_size\n                     (const CmdCtrlThreadReset *message)\n{\n  assert(message->base.descriptor == &cmd_ctrl_thread_reset__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t cmd_ctrl_thread_reset__pack\n                     (const CmdCtrlThreadReset *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &cmd_ctrl_thread_reset__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t cmd_ctrl_thread_reset__pack_to_buffer\n                     (const CmdCtrlThreadReset *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &cmd_ctrl_thread_reset__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nCmdCtrlThreadReset *\n       cmd_ctrl_thread_reset__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (CmdCtrlThreadReset *)\n     protobuf_c_message_unpack (&cmd_ctrl_thread_reset__descriptor,\n                                allocator, len, data);\n}\nvoid   cmd_ctrl_thread_reset__free_unpacked\n                     (CmdCtrlThreadReset *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &cmd_ctrl_thread_reset__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   resp_ctrl_thread_reset__init\n                     (RespCtrlThreadReset         *message)\n{\n  static const RespCtrlThreadReset init_value = RESP_CTRL_THREAD_RESET__INIT;\n  *message = init_value;\n}\nsize_t resp_ctrl_thread_reset__get_packed_size\n                     (const RespCtrlThreadReset *message)\n{\n  assert(message->base.descriptor == &resp_ctrl_thread_reset__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t resp_ctrl_thread_reset__pack\n                     (const RespCtrlThreadReset *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &resp_ctrl_thread_reset__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t resp_ctrl_thread_reset__pack_to_buffer\n                     (const RespCtrlThreadReset *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &resp_ctrl_thread_reset__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nRespCtrlThreadReset *\n       resp_ctrl_thread_reset__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (RespCtrlThreadReset *)\n     protobuf_c_message_unpack (&resp_ctrl_thread_reset__descriptor,\n                                allocator, len, data);\n}\nvoid   resp_ctrl_thread_reset__free_unpacked\n                     (RespCtrlThreadReset *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &resp_ctrl_thread_reset__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   cmd_ctrl_thread_reprov__init\n                     (CmdCtrlThreadReprov         *message)\n{\n  static const CmdCtrlThreadReprov init_value = CMD_CTRL_THREAD_REPROV__INIT;\n  *message = init_value;\n}\nsize_t cmd_ctrl_thread_reprov__get_packed_size\n                     (const CmdCtrlThreadReprov *message)\n{\n  assert(message->base.descriptor == &cmd_ctrl_thread_reprov__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t cmd_ctrl_thread_reprov__pack\n                     (const CmdCtrlThreadReprov *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &cmd_ctrl_thread_reprov__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t cmd_ctrl_thread_reprov__pack_to_buffer\n                     (const CmdCtrlThreadReprov *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &cmd_ctrl_thread_reprov__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nCmdCtrlThreadReprov *\n       cmd_ctrl_thread_reprov__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (CmdCtrlThreadReprov *)\n     protobuf_c_message_unpack (&cmd_ctrl_thread_reprov__descriptor,\n                                allocator, len, data);\n}\nvoid   cmd_ctrl_thread_reprov__free_unpacked\n                     (CmdCtrlThreadReprov *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &cmd_ctrl_thread_reprov__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   resp_ctrl_thread_reprov__init\n                     (RespCtrlThreadReprov         *message)\n{\n  static const RespCtrlThreadReprov init_value = RESP_CTRL_THREAD_REPROV__INIT;\n  *message = init_value;\n}\nsize_t resp_ctrl_thread_reprov__get_packed_size\n                     (const RespCtrlThreadReprov *message)\n{\n  assert(message->base.descriptor == &resp_ctrl_thread_reprov__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t resp_ctrl_thread_reprov__pack\n                     (const RespCtrlThreadReprov *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &resp_ctrl_thread_reprov__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t resp_ctrl_thread_reprov__pack_to_buffer\n                     (const RespCtrlThreadReprov *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &resp_ctrl_thread_reprov__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nRespCtrlThreadReprov *\n       resp_ctrl_thread_reprov__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (RespCtrlThreadReprov *)\n     protobuf_c_message_unpack (&resp_ctrl_thread_reprov__descriptor,\n                                allocator, len, data);\n}\nvoid   resp_ctrl_thread_reprov__free_unpacked\n                     (RespCtrlThreadReprov *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &resp_ctrl_thread_reprov__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   network_ctrl_payload__init\n                     (NetworkCtrlPayload         *message)\n{\n  static const NetworkCtrlPayload init_value = NETWORK_CTRL_PAYLOAD__INIT;\n  *message = init_value;\n}\nsize_t network_ctrl_payload__get_packed_size\n                     (const NetworkCtrlPayload *message)\n{\n  assert(message->base.descriptor == &network_ctrl_payload__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t network_ctrl_payload__pack\n                     (const NetworkCtrlPayload *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &network_ctrl_payload__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t network_ctrl_payload__pack_to_buffer\n                     (const NetworkCtrlPayload *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &network_ctrl_payload__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nNetworkCtrlPayload *\n       network_ctrl_payload__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (NetworkCtrlPayload *)\n     protobuf_c_message_unpack (&network_ctrl_payload__descriptor,\n                                allocator, len, data);\n}\nvoid   network_ctrl_payload__free_unpacked\n                     (NetworkCtrlPayload *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &network_ctrl_payload__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\n#define cmd_ctrl_wifi_reset__field_descriptors NULL\n#define cmd_ctrl_wifi_reset__field_indices_by_name NULL\n#define cmd_ctrl_wifi_reset__number_ranges NULL\nconst ProtobufCMessageDescriptor cmd_ctrl_wifi_reset__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"CmdCtrlWifiReset\",\n  \"CmdCtrlWifiReset\",\n  \"CmdCtrlWifiReset\",\n  \"\",\n  sizeof(CmdCtrlWifiReset),\n  0,\n  cmd_ctrl_wifi_reset__field_descriptors,\n  cmd_ctrl_wifi_reset__field_indices_by_name,\n  0,  cmd_ctrl_wifi_reset__number_ranges,\n  (ProtobufCMessageInit) cmd_ctrl_wifi_reset__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\n#define resp_ctrl_wifi_reset__field_descriptors NULL\n#define resp_ctrl_wifi_reset__field_indices_by_name NULL\n#define resp_ctrl_wifi_reset__number_ranges NULL\nconst ProtobufCMessageDescriptor resp_ctrl_wifi_reset__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"RespCtrlWifiReset\",\n  \"RespCtrlWifiReset\",\n  \"RespCtrlWifiReset\",\n  \"\",\n  sizeof(RespCtrlWifiReset),\n  0,\n  resp_ctrl_wifi_reset__field_descriptors,\n  resp_ctrl_wifi_reset__field_indices_by_name,\n  0,  resp_ctrl_wifi_reset__number_ranges,\n  (ProtobufCMessageInit) resp_ctrl_wifi_reset__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\n#define cmd_ctrl_wifi_reprov__field_descriptors NULL\n#define cmd_ctrl_wifi_reprov__field_indices_by_name NULL\n#define cmd_ctrl_wifi_reprov__number_ranges NULL\nconst ProtobufCMessageDescriptor cmd_ctrl_wifi_reprov__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"CmdCtrlWifiReprov\",\n  \"CmdCtrlWifiReprov\",\n  \"CmdCtrlWifiReprov\",\n  \"\",\n  sizeof(CmdCtrlWifiReprov),\n  0,\n  cmd_ctrl_wifi_reprov__field_descriptors,\n  cmd_ctrl_wifi_reprov__field_indices_by_name,\n  0,  cmd_ctrl_wifi_reprov__number_ranges,\n  (ProtobufCMessageInit) cmd_ctrl_wifi_reprov__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\n#define resp_ctrl_wifi_reprov__field_descriptors NULL\n#define resp_ctrl_wifi_reprov__field_indices_by_name NULL\n#define resp_ctrl_wifi_reprov__number_ranges NULL\nconst ProtobufCMessageDescriptor resp_ctrl_wifi_reprov__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"RespCtrlWifiReprov\",\n  \"RespCtrlWifiReprov\",\n  \"RespCtrlWifiReprov\",\n  \"\",\n  sizeof(RespCtrlWifiReprov),\n  0,\n  resp_ctrl_wifi_reprov__field_descriptors,\n  resp_ctrl_wifi_reprov__field_indices_by_name,\n  0,  resp_ctrl_wifi_reprov__number_ranges,\n  (ProtobufCMessageInit) resp_ctrl_wifi_reprov__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\n#define cmd_ctrl_thread_reset__field_descriptors NULL\n#define cmd_ctrl_thread_reset__field_indices_by_name NULL\n#define cmd_ctrl_thread_reset__number_ranges NULL\nconst ProtobufCMessageDescriptor cmd_ctrl_thread_reset__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"CmdCtrlThreadReset\",\n  \"CmdCtrlThreadReset\",\n  \"CmdCtrlThreadReset\",\n  \"\",\n  sizeof(CmdCtrlThreadReset),\n  0,\n  cmd_ctrl_thread_reset__field_descriptors,\n  cmd_ctrl_thread_reset__field_indices_by_name,\n  0,  cmd_ctrl_thread_reset__number_ranges,\n  (ProtobufCMessageInit) cmd_ctrl_thread_reset__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\n#define resp_ctrl_thread_reset__field_descriptors NULL\n#define resp_ctrl_thread_reset__field_indices_by_name NULL\n#define resp_ctrl_thread_reset__number_ranges NULL\nconst ProtobufCMessageDescriptor resp_ctrl_thread_reset__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"RespCtrlThreadReset\",\n  \"RespCtrlThreadReset\",\n  \"RespCtrlThreadReset\",\n  \"\",\n  sizeof(RespCtrlThreadReset),\n  0,\n  resp_ctrl_thread_reset__field_descriptors,\n  resp_ctrl_thread_reset__field_indices_by_name,\n  0,  resp_ctrl_thread_reset__number_ranges,\n  (ProtobufCMessageInit) resp_ctrl_thread_reset__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\n#define cmd_ctrl_thread_reprov__field_descriptors NULL\n#define cmd_ctrl_thread_reprov__field_indices_by_name NULL\n#define cmd_ctrl_thread_reprov__number_ranges NULL\nconst ProtobufCMessageDescriptor cmd_ctrl_thread_reprov__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"CmdCtrlThreadReprov\",\n  \"CmdCtrlThreadReprov\",\n  \"CmdCtrlThreadReprov\",\n  \"\",\n  sizeof(CmdCtrlThreadReprov),\n  0,\n  cmd_ctrl_thread_reprov__field_descriptors,\n  cmd_ctrl_thread_reprov__field_indices_by_name,\n  0,  cmd_ctrl_thread_reprov__number_ranges,\n  (ProtobufCMessageInit) cmd_ctrl_thread_reprov__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\n#define resp_ctrl_thread_reprov__field_descriptors NULL\n#define resp_ctrl_thread_reprov__field_indices_by_name NULL\n#define resp_ctrl_thread_reprov__number_ranges NULL\nconst ProtobufCMessageDescriptor resp_ctrl_thread_reprov__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"RespCtrlThreadReprov\",\n  \"RespCtrlThreadReprov\",\n  \"RespCtrlThreadReprov\",\n  \"\",\n  sizeof(RespCtrlThreadReprov),\n  0,\n  resp_ctrl_thread_reprov__field_descriptors,\n  resp_ctrl_thread_reprov__field_indices_by_name,\n  0,  resp_ctrl_thread_reprov__number_ranges,\n  (ProtobufCMessageInit) resp_ctrl_thread_reprov__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor network_ctrl_payload__field_descriptors[10] =\n{\n  {\n    \"msg\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_ENUM,\n    0,   /* quantifier_offset */\n    offsetof(NetworkCtrlPayload, msg),\n    &network_ctrl_msg_type__descriptor,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"status\",\n    2,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_ENUM,\n    0,   /* quantifier_offset */\n    offsetof(NetworkCtrlPayload, status),\n    &status__descriptor,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"cmd_ctrl_wifi_reset\",\n    11,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkCtrlPayload, payload_case),\n    offsetof(NetworkCtrlPayload, cmd_ctrl_wifi_reset),\n    &cmd_ctrl_wifi_reset__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"resp_ctrl_wifi_reset\",\n    12,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkCtrlPayload, payload_case),\n    offsetof(NetworkCtrlPayload, resp_ctrl_wifi_reset),\n    &resp_ctrl_wifi_reset__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"cmd_ctrl_wifi_reprov\",\n    13,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkCtrlPayload, payload_case),\n    offsetof(NetworkCtrlPayload, cmd_ctrl_wifi_reprov),\n    &cmd_ctrl_wifi_reprov__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"resp_ctrl_wifi_reprov\",\n    14,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkCtrlPayload, payload_case),\n    offsetof(NetworkCtrlPayload, resp_ctrl_wifi_reprov),\n    &resp_ctrl_wifi_reprov__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"cmd_ctrl_thread_reset\",\n    15,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkCtrlPayload, payload_case),\n    offsetof(NetworkCtrlPayload, cmd_ctrl_thread_reset),\n    &cmd_ctrl_thread_reset__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"resp_ctrl_thread_reset\",\n    16,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkCtrlPayload, payload_case),\n    offsetof(NetworkCtrlPayload, resp_ctrl_thread_reset),\n    &resp_ctrl_thread_reset__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"cmd_ctrl_thread_reprov\",\n    17,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkCtrlPayload, payload_case),\n    offsetof(NetworkCtrlPayload, cmd_ctrl_thread_reprov),\n    &cmd_ctrl_thread_reprov__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"resp_ctrl_thread_reprov\",\n    18,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkCtrlPayload, payload_case),\n    offsetof(NetworkCtrlPayload, resp_ctrl_thread_reprov),\n    &resp_ctrl_thread_reprov__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned network_ctrl_payload__field_indices_by_name[] = {\n  8,   /* field[8] = cmd_ctrl_thread_reprov */\n  6,   /* field[6] = cmd_ctrl_thread_reset */\n  4,   /* field[4] = cmd_ctrl_wifi_reprov */\n  2,   /* field[2] = cmd_ctrl_wifi_reset */\n  0,   /* field[0] = msg */\n  9,   /* field[9] = resp_ctrl_thread_reprov */\n  7,   /* field[7] = resp_ctrl_thread_reset */\n  5,   /* field[5] = resp_ctrl_wifi_reprov */\n  3,   /* field[3] = resp_ctrl_wifi_reset */\n  1,   /* field[1] = status */\n};\nstatic const ProtobufCIntRange network_ctrl_payload__number_ranges[2 + 1] =\n{\n  { 1, 0 },\n  { 11, 2 },\n  { 0, 10 }\n};\nconst ProtobufCMessageDescriptor network_ctrl_payload__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"NetworkCtrlPayload\",\n  \"NetworkCtrlPayload\",\n  \"NetworkCtrlPayload\",\n  \"\",\n  sizeof(NetworkCtrlPayload),\n  10,\n  network_ctrl_payload__field_descriptors,\n  network_ctrl_payload__field_indices_by_name,\n  2,  network_ctrl_payload__number_ranges,\n  (ProtobufCMessageInit) network_ctrl_payload__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCEnumValue network_ctrl_msg_type__enum_values_by_number[9] =\n{\n  { \"TypeCtrlReserved\", \"NETWORK_CTRL_MSG_TYPE__TypeCtrlReserved\", 0 },\n  { \"TypeCmdCtrlWifiReset\", \"NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlWifiReset\", 1 },\n  { \"TypeRespCtrlWifiReset\", \"NETWORK_CTRL_MSG_TYPE__TypeRespCtrlWifiReset\", 2 },\n  { \"TypeCmdCtrlWifiReprov\", \"NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlWifiReprov\", 3 },\n  { \"TypeRespCtrlWifiReprov\", \"NETWORK_CTRL_MSG_TYPE__TypeRespCtrlWifiReprov\", 4 },\n  { \"TypeCmdCtrlThreadReset\", \"NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlThreadReset\", 5 },\n  { \"TypeRespCtrlThreadReset\", \"NETWORK_CTRL_MSG_TYPE__TypeRespCtrlThreadReset\", 6 },\n  { \"TypeCmdCtrlThreadReprov\", \"NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlThreadReprov\", 7 },\n  { \"TypeRespCtrlThreadReprov\", \"NETWORK_CTRL_MSG_TYPE__TypeRespCtrlThreadReprov\", 8 },\n};\nstatic const ProtobufCIntRange network_ctrl_msg_type__value_ranges[] = {\n{0, 0},{0, 9}\n};\nstatic const ProtobufCEnumValueIndex network_ctrl_msg_type__enum_values_by_name[9] =\n{\n  { \"TypeCmdCtrlThreadReprov\", 7 },\n  { \"TypeCmdCtrlThreadReset\", 5 },\n  { \"TypeCmdCtrlWifiReprov\", 3 },\n  { \"TypeCmdCtrlWifiReset\", 1 },\n  { \"TypeCtrlReserved\", 0 },\n  { \"TypeRespCtrlThreadReprov\", 8 },\n  { \"TypeRespCtrlThreadReset\", 6 },\n  { \"TypeRespCtrlWifiReprov\", 4 },\n  { \"TypeRespCtrlWifiReset\", 2 },\n};\nconst ProtobufCEnumDescriptor network_ctrl_msg_type__descriptor =\n{\n  PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,\n  \"NetworkCtrlMsgType\",\n  \"NetworkCtrlMsgType\",\n  \"NetworkCtrlMsgType\",\n  \"\",\n  9,\n  network_ctrl_msg_type__enum_values_by_number,\n  9,\n  network_ctrl_msg_type__enum_values_by_name,\n  1,\n  network_ctrl_msg_type__value_ranges,\n  NULL,NULL,NULL,NULL   /* reserved[1234] */\n};\n"
  },
  {
    "path": "network_provisioning/proto-c/network_ctrl.pb-c.h",
    "content": "/* Generated by the protocol buffer compiler.  DO NOT EDIT! */\n/* Generated from: network_ctrl.proto */\n\n#ifndef PROTOBUF_C_network_5fctrl_2eproto__INCLUDED\n#define PROTOBUF_C_network_5fctrl_2eproto__INCLUDED\n\n#include <protobuf-c/protobuf-c.h>\n\nPROTOBUF_C__BEGIN_DECLS\n\n#if PROTOBUF_C_VERSION_NUMBER < 1003000\n# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.\n#elif 1004000 < PROTOBUF_C_MIN_COMPILER_VERSION\n# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.\n#endif\n\n#include \"constants.pb-c.h\"\n\ntypedef struct CmdCtrlWifiReset CmdCtrlWifiReset;\ntypedef struct RespCtrlWifiReset RespCtrlWifiReset;\ntypedef struct CmdCtrlWifiReprov CmdCtrlWifiReprov;\ntypedef struct RespCtrlWifiReprov RespCtrlWifiReprov;\ntypedef struct CmdCtrlThreadReset CmdCtrlThreadReset;\ntypedef struct RespCtrlThreadReset RespCtrlThreadReset;\ntypedef struct CmdCtrlThreadReprov CmdCtrlThreadReprov;\ntypedef struct RespCtrlThreadReprov RespCtrlThreadReprov;\ntypedef struct NetworkCtrlPayload NetworkCtrlPayload;\n\n\n/* --- enums --- */\n\ntypedef enum _NetworkCtrlMsgType {\n  NETWORK_CTRL_MSG_TYPE__TypeCtrlReserved = 0,\n  NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlWifiReset = 1,\n  NETWORK_CTRL_MSG_TYPE__TypeRespCtrlWifiReset = 2,\n  NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlWifiReprov = 3,\n  NETWORK_CTRL_MSG_TYPE__TypeRespCtrlWifiReprov = 4,\n  NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlThreadReset = 5,\n  NETWORK_CTRL_MSG_TYPE__TypeRespCtrlThreadReset = 6,\n  NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlThreadReprov = 7,\n  NETWORK_CTRL_MSG_TYPE__TypeRespCtrlThreadReprov = 8\n    PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(NETWORK_CTRL_MSG_TYPE)\n} NetworkCtrlMsgType;\n\n/* --- messages --- */\n\nstruct  CmdCtrlWifiReset\n{\n  ProtobufCMessage base;\n};\n#define CMD_CTRL_WIFI_RESET__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&cmd_ctrl_wifi_reset__descriptor) \\\n     }\n\n\nstruct  RespCtrlWifiReset\n{\n  ProtobufCMessage base;\n};\n#define RESP_CTRL_WIFI_RESET__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&resp_ctrl_wifi_reset__descriptor) \\\n     }\n\n\nstruct  CmdCtrlWifiReprov\n{\n  ProtobufCMessage base;\n};\n#define CMD_CTRL_WIFI_REPROV__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&cmd_ctrl_wifi_reprov__descriptor) \\\n     }\n\n\nstruct  RespCtrlWifiReprov\n{\n  ProtobufCMessage base;\n};\n#define RESP_CTRL_WIFI_REPROV__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&resp_ctrl_wifi_reprov__descriptor) \\\n     }\n\n\nstruct  CmdCtrlThreadReset\n{\n  ProtobufCMessage base;\n};\n#define CMD_CTRL_THREAD_RESET__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&cmd_ctrl_thread_reset__descriptor) \\\n     }\n\n\nstruct  RespCtrlThreadReset\n{\n  ProtobufCMessage base;\n};\n#define RESP_CTRL_THREAD_RESET__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&resp_ctrl_thread_reset__descriptor) \\\n     }\n\n\nstruct  CmdCtrlThreadReprov\n{\n  ProtobufCMessage base;\n};\n#define CMD_CTRL_THREAD_REPROV__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&cmd_ctrl_thread_reprov__descriptor) \\\n     }\n\n\nstruct  RespCtrlThreadReprov\n{\n  ProtobufCMessage base;\n};\n#define RESP_CTRL_THREAD_REPROV__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&resp_ctrl_thread_reprov__descriptor) \\\n     }\n\n\ntypedef enum {\n  NETWORK_CTRL_PAYLOAD__PAYLOAD__NOT_SET = 0,\n  NETWORK_CTRL_PAYLOAD__PAYLOAD_CMD_CTRL_WIFI_RESET = 11,\n  NETWORK_CTRL_PAYLOAD__PAYLOAD_RESP_CTRL_WIFI_RESET = 12,\n  NETWORK_CTRL_PAYLOAD__PAYLOAD_CMD_CTRL_WIFI_REPROV = 13,\n  NETWORK_CTRL_PAYLOAD__PAYLOAD_RESP_CTRL_WIFI_REPROV = 14,\n  NETWORK_CTRL_PAYLOAD__PAYLOAD_CMD_CTRL_THREAD_RESET = 15,\n  NETWORK_CTRL_PAYLOAD__PAYLOAD_RESP_CTRL_THREAD_RESET = 16,\n  NETWORK_CTRL_PAYLOAD__PAYLOAD_CMD_CTRL_THREAD_REPROV = 17,\n  NETWORK_CTRL_PAYLOAD__PAYLOAD_RESP_CTRL_THREAD_REPROV = 18\n    PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(NETWORK_CTRL_PAYLOAD__PAYLOAD__CASE)\n} NetworkCtrlPayload__PayloadCase;\n\nstruct  NetworkCtrlPayload\n{\n  ProtobufCMessage base;\n  NetworkCtrlMsgType msg;\n  Status status;\n  NetworkCtrlPayload__PayloadCase payload_case;\n  union {\n    CmdCtrlWifiReset *cmd_ctrl_wifi_reset;\n    RespCtrlWifiReset *resp_ctrl_wifi_reset;\n    CmdCtrlWifiReprov *cmd_ctrl_wifi_reprov;\n    RespCtrlWifiReprov *resp_ctrl_wifi_reprov;\n    CmdCtrlThreadReset *cmd_ctrl_thread_reset;\n    RespCtrlThreadReset *resp_ctrl_thread_reset;\n    CmdCtrlThreadReprov *cmd_ctrl_thread_reprov;\n    RespCtrlThreadReprov *resp_ctrl_thread_reprov;\n  };\n};\n#define NETWORK_CTRL_PAYLOAD__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&network_ctrl_payload__descriptor) \\\n    , NETWORK_CTRL_MSG_TYPE__TypeCtrlReserved, STATUS__Success, NETWORK_CTRL_PAYLOAD__PAYLOAD__NOT_SET, {0} }\n\n\n/* CmdCtrlWifiReset methods */\nvoid   cmd_ctrl_wifi_reset__init\n                     (CmdCtrlWifiReset         *message);\nsize_t cmd_ctrl_wifi_reset__get_packed_size\n                     (const CmdCtrlWifiReset   *message);\nsize_t cmd_ctrl_wifi_reset__pack\n                     (const CmdCtrlWifiReset   *message,\n                      uint8_t             *out);\nsize_t cmd_ctrl_wifi_reset__pack_to_buffer\n                     (const CmdCtrlWifiReset   *message,\n                      ProtobufCBuffer     *buffer);\nCmdCtrlWifiReset *\n       cmd_ctrl_wifi_reset__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   cmd_ctrl_wifi_reset__free_unpacked\n                     (CmdCtrlWifiReset *message,\n                      ProtobufCAllocator *allocator);\n/* RespCtrlWifiReset methods */\nvoid   resp_ctrl_wifi_reset__init\n                     (RespCtrlWifiReset         *message);\nsize_t resp_ctrl_wifi_reset__get_packed_size\n                     (const RespCtrlWifiReset   *message);\nsize_t resp_ctrl_wifi_reset__pack\n                     (const RespCtrlWifiReset   *message,\n                      uint8_t             *out);\nsize_t resp_ctrl_wifi_reset__pack_to_buffer\n                     (const RespCtrlWifiReset   *message,\n                      ProtobufCBuffer     *buffer);\nRespCtrlWifiReset *\n       resp_ctrl_wifi_reset__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   resp_ctrl_wifi_reset__free_unpacked\n                     (RespCtrlWifiReset *message,\n                      ProtobufCAllocator *allocator);\n/* CmdCtrlWifiReprov methods */\nvoid   cmd_ctrl_wifi_reprov__init\n                     (CmdCtrlWifiReprov         *message);\nsize_t cmd_ctrl_wifi_reprov__get_packed_size\n                     (const CmdCtrlWifiReprov   *message);\nsize_t cmd_ctrl_wifi_reprov__pack\n                     (const CmdCtrlWifiReprov   *message,\n                      uint8_t             *out);\nsize_t cmd_ctrl_wifi_reprov__pack_to_buffer\n                     (const CmdCtrlWifiReprov   *message,\n                      ProtobufCBuffer     *buffer);\nCmdCtrlWifiReprov *\n       cmd_ctrl_wifi_reprov__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   cmd_ctrl_wifi_reprov__free_unpacked\n                     (CmdCtrlWifiReprov *message,\n                      ProtobufCAllocator *allocator);\n/* RespCtrlWifiReprov methods */\nvoid   resp_ctrl_wifi_reprov__init\n                     (RespCtrlWifiReprov         *message);\nsize_t resp_ctrl_wifi_reprov__get_packed_size\n                     (const RespCtrlWifiReprov   *message);\nsize_t resp_ctrl_wifi_reprov__pack\n                     (const RespCtrlWifiReprov   *message,\n                      uint8_t             *out);\nsize_t resp_ctrl_wifi_reprov__pack_to_buffer\n                     (const RespCtrlWifiReprov   *message,\n                      ProtobufCBuffer     *buffer);\nRespCtrlWifiReprov *\n       resp_ctrl_wifi_reprov__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   resp_ctrl_wifi_reprov__free_unpacked\n                     (RespCtrlWifiReprov *message,\n                      ProtobufCAllocator *allocator);\n/* CmdCtrlThreadReset methods */\nvoid   cmd_ctrl_thread_reset__init\n                     (CmdCtrlThreadReset         *message);\nsize_t cmd_ctrl_thread_reset__get_packed_size\n                     (const CmdCtrlThreadReset   *message);\nsize_t cmd_ctrl_thread_reset__pack\n                     (const CmdCtrlThreadReset   *message,\n                      uint8_t             *out);\nsize_t cmd_ctrl_thread_reset__pack_to_buffer\n                     (const CmdCtrlThreadReset   *message,\n                      ProtobufCBuffer     *buffer);\nCmdCtrlThreadReset *\n       cmd_ctrl_thread_reset__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   cmd_ctrl_thread_reset__free_unpacked\n                     (CmdCtrlThreadReset *message,\n                      ProtobufCAllocator *allocator);\n/* RespCtrlThreadReset methods */\nvoid   resp_ctrl_thread_reset__init\n                     (RespCtrlThreadReset         *message);\nsize_t resp_ctrl_thread_reset__get_packed_size\n                     (const RespCtrlThreadReset   *message);\nsize_t resp_ctrl_thread_reset__pack\n                     (const RespCtrlThreadReset   *message,\n                      uint8_t             *out);\nsize_t resp_ctrl_thread_reset__pack_to_buffer\n                     (const RespCtrlThreadReset   *message,\n                      ProtobufCBuffer     *buffer);\nRespCtrlThreadReset *\n       resp_ctrl_thread_reset__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   resp_ctrl_thread_reset__free_unpacked\n                     (RespCtrlThreadReset *message,\n                      ProtobufCAllocator *allocator);\n/* CmdCtrlThreadReprov methods */\nvoid   cmd_ctrl_thread_reprov__init\n                     (CmdCtrlThreadReprov         *message);\nsize_t cmd_ctrl_thread_reprov__get_packed_size\n                     (const CmdCtrlThreadReprov   *message);\nsize_t cmd_ctrl_thread_reprov__pack\n                     (const CmdCtrlThreadReprov   *message,\n                      uint8_t             *out);\nsize_t cmd_ctrl_thread_reprov__pack_to_buffer\n                     (const CmdCtrlThreadReprov   *message,\n                      ProtobufCBuffer     *buffer);\nCmdCtrlThreadReprov *\n       cmd_ctrl_thread_reprov__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   cmd_ctrl_thread_reprov__free_unpacked\n                     (CmdCtrlThreadReprov *message,\n                      ProtobufCAllocator *allocator);\n/* RespCtrlThreadReprov methods */\nvoid   resp_ctrl_thread_reprov__init\n                     (RespCtrlThreadReprov         *message);\nsize_t resp_ctrl_thread_reprov__get_packed_size\n                     (const RespCtrlThreadReprov   *message);\nsize_t resp_ctrl_thread_reprov__pack\n                     (const RespCtrlThreadReprov   *message,\n                      uint8_t             *out);\nsize_t resp_ctrl_thread_reprov__pack_to_buffer\n                     (const RespCtrlThreadReprov   *message,\n                      ProtobufCBuffer     *buffer);\nRespCtrlThreadReprov *\n       resp_ctrl_thread_reprov__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   resp_ctrl_thread_reprov__free_unpacked\n                     (RespCtrlThreadReprov *message,\n                      ProtobufCAllocator *allocator);\n/* NetworkCtrlPayload methods */\nvoid   network_ctrl_payload__init\n                     (NetworkCtrlPayload         *message);\nsize_t network_ctrl_payload__get_packed_size\n                     (const NetworkCtrlPayload   *message);\nsize_t network_ctrl_payload__pack\n                     (const NetworkCtrlPayload   *message,\n                      uint8_t             *out);\nsize_t network_ctrl_payload__pack_to_buffer\n                     (const NetworkCtrlPayload   *message,\n                      ProtobufCBuffer     *buffer);\nNetworkCtrlPayload *\n       network_ctrl_payload__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   network_ctrl_payload__free_unpacked\n                     (NetworkCtrlPayload *message,\n                      ProtobufCAllocator *allocator);\n/* --- per-message closures --- */\n\ntypedef void (*CmdCtrlWifiReset_Closure)\n                 (const CmdCtrlWifiReset *message,\n                  void *closure_data);\ntypedef void (*RespCtrlWifiReset_Closure)\n                 (const RespCtrlWifiReset *message,\n                  void *closure_data);\ntypedef void (*CmdCtrlWifiReprov_Closure)\n                 (const CmdCtrlWifiReprov *message,\n                  void *closure_data);\ntypedef void (*RespCtrlWifiReprov_Closure)\n                 (const RespCtrlWifiReprov *message,\n                  void *closure_data);\ntypedef void (*CmdCtrlThreadReset_Closure)\n                 (const CmdCtrlThreadReset *message,\n                  void *closure_data);\ntypedef void (*RespCtrlThreadReset_Closure)\n                 (const RespCtrlThreadReset *message,\n                  void *closure_data);\ntypedef void (*CmdCtrlThreadReprov_Closure)\n                 (const CmdCtrlThreadReprov *message,\n                  void *closure_data);\ntypedef void (*RespCtrlThreadReprov_Closure)\n                 (const RespCtrlThreadReprov *message,\n                  void *closure_data);\ntypedef void (*NetworkCtrlPayload_Closure)\n                 (const NetworkCtrlPayload *message,\n                  void *closure_data);\n\n/* --- services --- */\n\n\n/* --- descriptors --- */\n\nextern const ProtobufCEnumDescriptor    network_ctrl_msg_type__descriptor;\nextern const ProtobufCMessageDescriptor cmd_ctrl_wifi_reset__descriptor;\nextern const ProtobufCMessageDescriptor resp_ctrl_wifi_reset__descriptor;\nextern const ProtobufCMessageDescriptor cmd_ctrl_wifi_reprov__descriptor;\nextern const ProtobufCMessageDescriptor resp_ctrl_wifi_reprov__descriptor;\nextern const ProtobufCMessageDescriptor cmd_ctrl_thread_reset__descriptor;\nextern const ProtobufCMessageDescriptor resp_ctrl_thread_reset__descriptor;\nextern const ProtobufCMessageDescriptor cmd_ctrl_thread_reprov__descriptor;\nextern const ProtobufCMessageDescriptor resp_ctrl_thread_reprov__descriptor;\nextern const ProtobufCMessageDescriptor network_ctrl_payload__descriptor;\n\nPROTOBUF_C__END_DECLS\n\n\n#endif  /* PROTOBUF_C_network_5fctrl_2eproto__INCLUDED */\n"
  },
  {
    "path": "network_provisioning/proto-c/network_scan.pb-c.c",
    "content": "/* Generated by the protocol buffer compiler.  DO NOT EDIT! */\n/* Generated from: network_scan.proto */\n\n/* Do not generate deprecated warnings for self */\n#ifndef PROTOBUF_C__NO_DEPRECATED\n#define PROTOBUF_C__NO_DEPRECATED\n#endif\n\n#include \"network_scan.pb-c.h\"\nvoid   cmd_scan_wifi_start__init\n                     (CmdScanWifiStart         *message)\n{\n  static const CmdScanWifiStart init_value = CMD_SCAN_WIFI_START__INIT;\n  *message = init_value;\n}\nsize_t cmd_scan_wifi_start__get_packed_size\n                     (const CmdScanWifiStart *message)\n{\n  assert(message->base.descriptor == &cmd_scan_wifi_start__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t cmd_scan_wifi_start__pack\n                     (const CmdScanWifiStart *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &cmd_scan_wifi_start__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t cmd_scan_wifi_start__pack_to_buffer\n                     (const CmdScanWifiStart *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &cmd_scan_wifi_start__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nCmdScanWifiStart *\n       cmd_scan_wifi_start__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (CmdScanWifiStart *)\n     protobuf_c_message_unpack (&cmd_scan_wifi_start__descriptor,\n                                allocator, len, data);\n}\nvoid   cmd_scan_wifi_start__free_unpacked\n                     (CmdScanWifiStart *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &cmd_scan_wifi_start__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   cmd_scan_thread_start__init\n                     (CmdScanThreadStart         *message)\n{\n  static const CmdScanThreadStart init_value = CMD_SCAN_THREAD_START__INIT;\n  *message = init_value;\n}\nsize_t cmd_scan_thread_start__get_packed_size\n                     (const CmdScanThreadStart *message)\n{\n  assert(message->base.descriptor == &cmd_scan_thread_start__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t cmd_scan_thread_start__pack\n                     (const CmdScanThreadStart *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &cmd_scan_thread_start__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t cmd_scan_thread_start__pack_to_buffer\n                     (const CmdScanThreadStart *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &cmd_scan_thread_start__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nCmdScanThreadStart *\n       cmd_scan_thread_start__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (CmdScanThreadStart *)\n     protobuf_c_message_unpack (&cmd_scan_thread_start__descriptor,\n                                allocator, len, data);\n}\nvoid   cmd_scan_thread_start__free_unpacked\n                     (CmdScanThreadStart *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &cmd_scan_thread_start__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   resp_scan_wifi_start__init\n                     (RespScanWifiStart         *message)\n{\n  static const RespScanWifiStart init_value = RESP_SCAN_WIFI_START__INIT;\n  *message = init_value;\n}\nsize_t resp_scan_wifi_start__get_packed_size\n                     (const RespScanWifiStart *message)\n{\n  assert(message->base.descriptor == &resp_scan_wifi_start__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t resp_scan_wifi_start__pack\n                     (const RespScanWifiStart *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &resp_scan_wifi_start__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t resp_scan_wifi_start__pack_to_buffer\n                     (const RespScanWifiStart *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &resp_scan_wifi_start__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nRespScanWifiStart *\n       resp_scan_wifi_start__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (RespScanWifiStart *)\n     protobuf_c_message_unpack (&resp_scan_wifi_start__descriptor,\n                                allocator, len, data);\n}\nvoid   resp_scan_wifi_start__free_unpacked\n                     (RespScanWifiStart *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &resp_scan_wifi_start__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   resp_scan_thread_start__init\n                     (RespScanThreadStart         *message)\n{\n  static const RespScanThreadStart init_value = RESP_SCAN_THREAD_START__INIT;\n  *message = init_value;\n}\nsize_t resp_scan_thread_start__get_packed_size\n                     (const RespScanThreadStart *message)\n{\n  assert(message->base.descriptor == &resp_scan_thread_start__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t resp_scan_thread_start__pack\n                     (const RespScanThreadStart *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &resp_scan_thread_start__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t resp_scan_thread_start__pack_to_buffer\n                     (const RespScanThreadStart *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &resp_scan_thread_start__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nRespScanThreadStart *\n       resp_scan_thread_start__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (RespScanThreadStart *)\n     protobuf_c_message_unpack (&resp_scan_thread_start__descriptor,\n                                allocator, len, data);\n}\nvoid   resp_scan_thread_start__free_unpacked\n                     (RespScanThreadStart *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &resp_scan_thread_start__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   cmd_scan_wifi_status__init\n                     (CmdScanWifiStatus         *message)\n{\n  static const CmdScanWifiStatus init_value = CMD_SCAN_WIFI_STATUS__INIT;\n  *message = init_value;\n}\nsize_t cmd_scan_wifi_status__get_packed_size\n                     (const CmdScanWifiStatus *message)\n{\n  assert(message->base.descriptor == &cmd_scan_wifi_status__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t cmd_scan_wifi_status__pack\n                     (const CmdScanWifiStatus *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &cmd_scan_wifi_status__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t cmd_scan_wifi_status__pack_to_buffer\n                     (const CmdScanWifiStatus *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &cmd_scan_wifi_status__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nCmdScanWifiStatus *\n       cmd_scan_wifi_status__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (CmdScanWifiStatus *)\n     protobuf_c_message_unpack (&cmd_scan_wifi_status__descriptor,\n                                allocator, len, data);\n}\nvoid   cmd_scan_wifi_status__free_unpacked\n                     (CmdScanWifiStatus *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &cmd_scan_wifi_status__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   cmd_scan_thread_status__init\n                     (CmdScanThreadStatus         *message)\n{\n  static const CmdScanThreadStatus init_value = CMD_SCAN_THREAD_STATUS__INIT;\n  *message = init_value;\n}\nsize_t cmd_scan_thread_status__get_packed_size\n                     (const CmdScanThreadStatus *message)\n{\n  assert(message->base.descriptor == &cmd_scan_thread_status__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t cmd_scan_thread_status__pack\n                     (const CmdScanThreadStatus *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &cmd_scan_thread_status__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t cmd_scan_thread_status__pack_to_buffer\n                     (const CmdScanThreadStatus *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &cmd_scan_thread_status__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nCmdScanThreadStatus *\n       cmd_scan_thread_status__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (CmdScanThreadStatus *)\n     protobuf_c_message_unpack (&cmd_scan_thread_status__descriptor,\n                                allocator, len, data);\n}\nvoid   cmd_scan_thread_status__free_unpacked\n                     (CmdScanThreadStatus *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &cmd_scan_thread_status__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   resp_scan_wifi_status__init\n                     (RespScanWifiStatus         *message)\n{\n  static const RespScanWifiStatus init_value = RESP_SCAN_WIFI_STATUS__INIT;\n  *message = init_value;\n}\nsize_t resp_scan_wifi_status__get_packed_size\n                     (const RespScanWifiStatus *message)\n{\n  assert(message->base.descriptor == &resp_scan_wifi_status__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t resp_scan_wifi_status__pack\n                     (const RespScanWifiStatus *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &resp_scan_wifi_status__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t resp_scan_wifi_status__pack_to_buffer\n                     (const RespScanWifiStatus *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &resp_scan_wifi_status__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nRespScanWifiStatus *\n       resp_scan_wifi_status__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (RespScanWifiStatus *)\n     protobuf_c_message_unpack (&resp_scan_wifi_status__descriptor,\n                                allocator, len, data);\n}\nvoid   resp_scan_wifi_status__free_unpacked\n                     (RespScanWifiStatus *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &resp_scan_wifi_status__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   resp_scan_thread_status__init\n                     (RespScanThreadStatus         *message)\n{\n  static const RespScanThreadStatus init_value = RESP_SCAN_THREAD_STATUS__INIT;\n  *message = init_value;\n}\nsize_t resp_scan_thread_status__get_packed_size\n                     (const RespScanThreadStatus *message)\n{\n  assert(message->base.descriptor == &resp_scan_thread_status__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t resp_scan_thread_status__pack\n                     (const RespScanThreadStatus *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &resp_scan_thread_status__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t resp_scan_thread_status__pack_to_buffer\n                     (const RespScanThreadStatus *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &resp_scan_thread_status__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nRespScanThreadStatus *\n       resp_scan_thread_status__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (RespScanThreadStatus *)\n     protobuf_c_message_unpack (&resp_scan_thread_status__descriptor,\n                                allocator, len, data);\n}\nvoid   resp_scan_thread_status__free_unpacked\n                     (RespScanThreadStatus *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &resp_scan_thread_status__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   cmd_scan_wifi_result__init\n                     (CmdScanWifiResult         *message)\n{\n  static const CmdScanWifiResult init_value = CMD_SCAN_WIFI_RESULT__INIT;\n  *message = init_value;\n}\nsize_t cmd_scan_wifi_result__get_packed_size\n                     (const CmdScanWifiResult *message)\n{\n  assert(message->base.descriptor == &cmd_scan_wifi_result__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t cmd_scan_wifi_result__pack\n                     (const CmdScanWifiResult *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &cmd_scan_wifi_result__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t cmd_scan_wifi_result__pack_to_buffer\n                     (const CmdScanWifiResult *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &cmd_scan_wifi_result__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nCmdScanWifiResult *\n       cmd_scan_wifi_result__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (CmdScanWifiResult *)\n     protobuf_c_message_unpack (&cmd_scan_wifi_result__descriptor,\n                                allocator, len, data);\n}\nvoid   cmd_scan_wifi_result__free_unpacked\n                     (CmdScanWifiResult *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &cmd_scan_wifi_result__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   cmd_scan_thread_result__init\n                     (CmdScanThreadResult         *message)\n{\n  static const CmdScanThreadResult init_value = CMD_SCAN_THREAD_RESULT__INIT;\n  *message = init_value;\n}\nsize_t cmd_scan_thread_result__get_packed_size\n                     (const CmdScanThreadResult *message)\n{\n  assert(message->base.descriptor == &cmd_scan_thread_result__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t cmd_scan_thread_result__pack\n                     (const CmdScanThreadResult *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &cmd_scan_thread_result__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t cmd_scan_thread_result__pack_to_buffer\n                     (const CmdScanThreadResult *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &cmd_scan_thread_result__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nCmdScanThreadResult *\n       cmd_scan_thread_result__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (CmdScanThreadResult *)\n     protobuf_c_message_unpack (&cmd_scan_thread_result__descriptor,\n                                allocator, len, data);\n}\nvoid   cmd_scan_thread_result__free_unpacked\n                     (CmdScanThreadResult *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &cmd_scan_thread_result__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   wi_fi_scan_result__init\n                     (WiFiScanResult         *message)\n{\n  static const WiFiScanResult init_value = WI_FI_SCAN_RESULT__INIT;\n  *message = init_value;\n}\nsize_t wi_fi_scan_result__get_packed_size\n                     (const WiFiScanResult *message)\n{\n  assert(message->base.descriptor == &wi_fi_scan_result__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t wi_fi_scan_result__pack\n                     (const WiFiScanResult *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &wi_fi_scan_result__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t wi_fi_scan_result__pack_to_buffer\n                     (const WiFiScanResult *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &wi_fi_scan_result__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nWiFiScanResult *\n       wi_fi_scan_result__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (WiFiScanResult *)\n     protobuf_c_message_unpack (&wi_fi_scan_result__descriptor,\n                                allocator, len, data);\n}\nvoid   wi_fi_scan_result__free_unpacked\n                     (WiFiScanResult *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &wi_fi_scan_result__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   thread_scan_result__init\n                     (ThreadScanResult         *message)\n{\n  static const ThreadScanResult init_value = THREAD_SCAN_RESULT__INIT;\n  *message = init_value;\n}\nsize_t thread_scan_result__get_packed_size\n                     (const ThreadScanResult *message)\n{\n  assert(message->base.descriptor == &thread_scan_result__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t thread_scan_result__pack\n                     (const ThreadScanResult *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &thread_scan_result__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t thread_scan_result__pack_to_buffer\n                     (const ThreadScanResult *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &thread_scan_result__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nThreadScanResult *\n       thread_scan_result__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (ThreadScanResult *)\n     protobuf_c_message_unpack (&thread_scan_result__descriptor,\n                                allocator, len, data);\n}\nvoid   thread_scan_result__free_unpacked\n                     (ThreadScanResult *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &thread_scan_result__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   resp_scan_wifi_result__init\n                     (RespScanWifiResult         *message)\n{\n  static const RespScanWifiResult init_value = RESP_SCAN_WIFI_RESULT__INIT;\n  *message = init_value;\n}\nsize_t resp_scan_wifi_result__get_packed_size\n                     (const RespScanWifiResult *message)\n{\n  assert(message->base.descriptor == &resp_scan_wifi_result__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t resp_scan_wifi_result__pack\n                     (const RespScanWifiResult *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &resp_scan_wifi_result__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t resp_scan_wifi_result__pack_to_buffer\n                     (const RespScanWifiResult *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &resp_scan_wifi_result__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nRespScanWifiResult *\n       resp_scan_wifi_result__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (RespScanWifiResult *)\n     protobuf_c_message_unpack (&resp_scan_wifi_result__descriptor,\n                                allocator, len, data);\n}\nvoid   resp_scan_wifi_result__free_unpacked\n                     (RespScanWifiResult *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &resp_scan_wifi_result__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   resp_scan_thread_result__init\n                     (RespScanThreadResult         *message)\n{\n  static const RespScanThreadResult init_value = RESP_SCAN_THREAD_RESULT__INIT;\n  *message = init_value;\n}\nsize_t resp_scan_thread_result__get_packed_size\n                     (const RespScanThreadResult *message)\n{\n  assert(message->base.descriptor == &resp_scan_thread_result__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t resp_scan_thread_result__pack\n                     (const RespScanThreadResult *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &resp_scan_thread_result__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t resp_scan_thread_result__pack_to_buffer\n                     (const RespScanThreadResult *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &resp_scan_thread_result__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nRespScanThreadResult *\n       resp_scan_thread_result__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (RespScanThreadResult *)\n     protobuf_c_message_unpack (&resp_scan_thread_result__descriptor,\n                                allocator, len, data);\n}\nvoid   resp_scan_thread_result__free_unpacked\n                     (RespScanThreadResult *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &resp_scan_thread_result__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nvoid   network_scan_payload__init\n                     (NetworkScanPayload         *message)\n{\n  static const NetworkScanPayload init_value = NETWORK_SCAN_PAYLOAD__INIT;\n  *message = init_value;\n}\nsize_t network_scan_payload__get_packed_size\n                     (const NetworkScanPayload *message)\n{\n  assert(message->base.descriptor == &network_scan_payload__descriptor);\n  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));\n}\nsize_t network_scan_payload__pack\n                     (const NetworkScanPayload *message,\n                      uint8_t       *out)\n{\n  assert(message->base.descriptor == &network_scan_payload__descriptor);\n  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);\n}\nsize_t network_scan_payload__pack_to_buffer\n                     (const NetworkScanPayload *message,\n                      ProtobufCBuffer *buffer)\n{\n  assert(message->base.descriptor == &network_scan_payload__descriptor);\n  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);\n}\nNetworkScanPayload *\n       network_scan_payload__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data)\n{\n  return (NetworkScanPayload *)\n     protobuf_c_message_unpack (&network_scan_payload__descriptor,\n                                allocator, len, data);\n}\nvoid   network_scan_payload__free_unpacked\n                     (NetworkScanPayload *message,\n                      ProtobufCAllocator *allocator)\n{\n  if(!message)\n    return;\n  assert(message->base.descriptor == &network_scan_payload__descriptor);\n  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n}\nstatic const ProtobufCFieldDescriptor cmd_scan_wifi_start__field_descriptors[4] =\n{\n  {\n    \"blocking\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_BOOL,\n    0,   /* quantifier_offset */\n    offsetof(CmdScanWifiStart, blocking),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"passive\",\n    2,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_BOOL,\n    0,   /* quantifier_offset */\n    offsetof(CmdScanWifiStart, passive),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"group_channels\",\n    3,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_UINT32,\n    0,   /* quantifier_offset */\n    offsetof(CmdScanWifiStart, group_channels),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"period_ms\",\n    4,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_UINT32,\n    0,   /* quantifier_offset */\n    offsetof(CmdScanWifiStart, period_ms),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned cmd_scan_wifi_start__field_indices_by_name[] = {\n  0,   /* field[0] = blocking */\n  2,   /* field[2] = group_channels */\n  1,   /* field[1] = passive */\n  3,   /* field[3] = period_ms */\n};\nstatic const ProtobufCIntRange cmd_scan_wifi_start__number_ranges[1 + 1] =\n{\n  { 1, 0 },\n  { 0, 4 }\n};\nconst ProtobufCMessageDescriptor cmd_scan_wifi_start__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"CmdScanWifiStart\",\n  \"CmdScanWifiStart\",\n  \"CmdScanWifiStart\",\n  \"\",\n  sizeof(CmdScanWifiStart),\n  4,\n  cmd_scan_wifi_start__field_descriptors,\n  cmd_scan_wifi_start__field_indices_by_name,\n  1,  cmd_scan_wifi_start__number_ranges,\n  (ProtobufCMessageInit) cmd_scan_wifi_start__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor cmd_scan_thread_start__field_descriptors[2] =\n{\n  {\n    \"blocking\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_BOOL,\n    0,   /* quantifier_offset */\n    offsetof(CmdScanThreadStart, blocking),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"channel_mask\",\n    2,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_UINT32,\n    0,   /* quantifier_offset */\n    offsetof(CmdScanThreadStart, channel_mask),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned cmd_scan_thread_start__field_indices_by_name[] = {\n  0,   /* field[0] = blocking */\n  1,   /* field[1] = channel_mask */\n};\nstatic const ProtobufCIntRange cmd_scan_thread_start__number_ranges[1 + 1] =\n{\n  { 1, 0 },\n  { 0, 2 }\n};\nconst ProtobufCMessageDescriptor cmd_scan_thread_start__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"CmdScanThreadStart\",\n  \"CmdScanThreadStart\",\n  \"CmdScanThreadStart\",\n  \"\",\n  sizeof(CmdScanThreadStart),\n  2,\n  cmd_scan_thread_start__field_descriptors,\n  cmd_scan_thread_start__field_indices_by_name,\n  1,  cmd_scan_thread_start__number_ranges,\n  (ProtobufCMessageInit) cmd_scan_thread_start__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\n#define resp_scan_wifi_start__field_descriptors NULL\n#define resp_scan_wifi_start__field_indices_by_name NULL\n#define resp_scan_wifi_start__number_ranges NULL\nconst ProtobufCMessageDescriptor resp_scan_wifi_start__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"RespScanWifiStart\",\n  \"RespScanWifiStart\",\n  \"RespScanWifiStart\",\n  \"\",\n  sizeof(RespScanWifiStart),\n  0,\n  resp_scan_wifi_start__field_descriptors,\n  resp_scan_wifi_start__field_indices_by_name,\n  0,  resp_scan_wifi_start__number_ranges,\n  (ProtobufCMessageInit) resp_scan_wifi_start__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\n#define resp_scan_thread_start__field_descriptors NULL\n#define resp_scan_thread_start__field_indices_by_name NULL\n#define resp_scan_thread_start__number_ranges NULL\nconst ProtobufCMessageDescriptor resp_scan_thread_start__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"RespScanThreadStart\",\n  \"RespScanThreadStart\",\n  \"RespScanThreadStart\",\n  \"\",\n  sizeof(RespScanThreadStart),\n  0,\n  resp_scan_thread_start__field_descriptors,\n  resp_scan_thread_start__field_indices_by_name,\n  0,  resp_scan_thread_start__number_ranges,\n  (ProtobufCMessageInit) resp_scan_thread_start__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\n#define cmd_scan_wifi_status__field_descriptors NULL\n#define cmd_scan_wifi_status__field_indices_by_name NULL\n#define cmd_scan_wifi_status__number_ranges NULL\nconst ProtobufCMessageDescriptor cmd_scan_wifi_status__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"CmdScanWifiStatus\",\n  \"CmdScanWifiStatus\",\n  \"CmdScanWifiStatus\",\n  \"\",\n  sizeof(CmdScanWifiStatus),\n  0,\n  cmd_scan_wifi_status__field_descriptors,\n  cmd_scan_wifi_status__field_indices_by_name,\n  0,  cmd_scan_wifi_status__number_ranges,\n  (ProtobufCMessageInit) cmd_scan_wifi_status__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\n#define cmd_scan_thread_status__field_descriptors NULL\n#define cmd_scan_thread_status__field_indices_by_name NULL\n#define cmd_scan_thread_status__number_ranges NULL\nconst ProtobufCMessageDescriptor cmd_scan_thread_status__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"CmdScanThreadStatus\",\n  \"CmdScanThreadStatus\",\n  \"CmdScanThreadStatus\",\n  \"\",\n  sizeof(CmdScanThreadStatus),\n  0,\n  cmd_scan_thread_status__field_descriptors,\n  cmd_scan_thread_status__field_indices_by_name,\n  0,  cmd_scan_thread_status__number_ranges,\n  (ProtobufCMessageInit) cmd_scan_thread_status__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor resp_scan_wifi_status__field_descriptors[2] =\n{\n  {\n    \"scan_finished\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_BOOL,\n    0,   /* quantifier_offset */\n    offsetof(RespScanWifiStatus, scan_finished),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"result_count\",\n    2,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_UINT32,\n    0,   /* quantifier_offset */\n    offsetof(RespScanWifiStatus, result_count),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned resp_scan_wifi_status__field_indices_by_name[] = {\n  1,   /* field[1] = result_count */\n  0,   /* field[0] = scan_finished */\n};\nstatic const ProtobufCIntRange resp_scan_wifi_status__number_ranges[1 + 1] =\n{\n  { 1, 0 },\n  { 0, 2 }\n};\nconst ProtobufCMessageDescriptor resp_scan_wifi_status__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"RespScanWifiStatus\",\n  \"RespScanWifiStatus\",\n  \"RespScanWifiStatus\",\n  \"\",\n  sizeof(RespScanWifiStatus),\n  2,\n  resp_scan_wifi_status__field_descriptors,\n  resp_scan_wifi_status__field_indices_by_name,\n  1,  resp_scan_wifi_status__number_ranges,\n  (ProtobufCMessageInit) resp_scan_wifi_status__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor resp_scan_thread_status__field_descriptors[2] =\n{\n  {\n    \"scan_finished\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_BOOL,\n    0,   /* quantifier_offset */\n    offsetof(RespScanThreadStatus, scan_finished),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"result_count\",\n    2,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_UINT32,\n    0,   /* quantifier_offset */\n    offsetof(RespScanThreadStatus, result_count),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned resp_scan_thread_status__field_indices_by_name[] = {\n  1,   /* field[1] = result_count */\n  0,   /* field[0] = scan_finished */\n};\nstatic const ProtobufCIntRange resp_scan_thread_status__number_ranges[1 + 1] =\n{\n  { 1, 0 },\n  { 0, 2 }\n};\nconst ProtobufCMessageDescriptor resp_scan_thread_status__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"RespScanThreadStatus\",\n  \"RespScanThreadStatus\",\n  \"RespScanThreadStatus\",\n  \"\",\n  sizeof(RespScanThreadStatus),\n  2,\n  resp_scan_thread_status__field_descriptors,\n  resp_scan_thread_status__field_indices_by_name,\n  1,  resp_scan_thread_status__number_ranges,\n  (ProtobufCMessageInit) resp_scan_thread_status__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor cmd_scan_wifi_result__field_descriptors[2] =\n{\n  {\n    \"start_index\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_UINT32,\n    0,   /* quantifier_offset */\n    offsetof(CmdScanWifiResult, start_index),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"count\",\n    2,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_UINT32,\n    0,   /* quantifier_offset */\n    offsetof(CmdScanWifiResult, count),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned cmd_scan_wifi_result__field_indices_by_name[] = {\n  1,   /* field[1] = count */\n  0,   /* field[0] = start_index */\n};\nstatic const ProtobufCIntRange cmd_scan_wifi_result__number_ranges[1 + 1] =\n{\n  { 1, 0 },\n  { 0, 2 }\n};\nconst ProtobufCMessageDescriptor cmd_scan_wifi_result__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"CmdScanWifiResult\",\n  \"CmdScanWifiResult\",\n  \"CmdScanWifiResult\",\n  \"\",\n  sizeof(CmdScanWifiResult),\n  2,\n  cmd_scan_wifi_result__field_descriptors,\n  cmd_scan_wifi_result__field_indices_by_name,\n  1,  cmd_scan_wifi_result__number_ranges,\n  (ProtobufCMessageInit) cmd_scan_wifi_result__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor cmd_scan_thread_result__field_descriptors[2] =\n{\n  {\n    \"start_index\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_UINT32,\n    0,   /* quantifier_offset */\n    offsetof(CmdScanThreadResult, start_index),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"count\",\n    2,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_UINT32,\n    0,   /* quantifier_offset */\n    offsetof(CmdScanThreadResult, count),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned cmd_scan_thread_result__field_indices_by_name[] = {\n  1,   /* field[1] = count */\n  0,   /* field[0] = start_index */\n};\nstatic const ProtobufCIntRange cmd_scan_thread_result__number_ranges[1 + 1] =\n{\n  { 1, 0 },\n  { 0, 2 }\n};\nconst ProtobufCMessageDescriptor cmd_scan_thread_result__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"CmdScanThreadResult\",\n  \"CmdScanThreadResult\",\n  \"CmdScanThreadResult\",\n  \"\",\n  sizeof(CmdScanThreadResult),\n  2,\n  cmd_scan_thread_result__field_descriptors,\n  cmd_scan_thread_result__field_indices_by_name,\n  1,  cmd_scan_thread_result__number_ranges,\n  (ProtobufCMessageInit) cmd_scan_thread_result__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor wi_fi_scan_result__field_descriptors[5] =\n{\n  {\n    \"ssid\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_BYTES,\n    0,   /* quantifier_offset */\n    offsetof(WiFiScanResult, ssid),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"channel\",\n    2,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_UINT32,\n    0,   /* quantifier_offset */\n    offsetof(WiFiScanResult, channel),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"rssi\",\n    3,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_INT32,\n    0,   /* quantifier_offset */\n    offsetof(WiFiScanResult, rssi),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"bssid\",\n    4,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_BYTES,\n    0,   /* quantifier_offset */\n    offsetof(WiFiScanResult, bssid),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"auth\",\n    5,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_ENUM,\n    0,   /* quantifier_offset */\n    offsetof(WiFiScanResult, auth),\n    &wifi_auth_mode__descriptor,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned wi_fi_scan_result__field_indices_by_name[] = {\n  4,   /* field[4] = auth */\n  3,   /* field[3] = bssid */\n  1,   /* field[1] = channel */\n  2,   /* field[2] = rssi */\n  0,   /* field[0] = ssid */\n};\nstatic const ProtobufCIntRange wi_fi_scan_result__number_ranges[1 + 1] =\n{\n  { 1, 0 },\n  { 0, 5 }\n};\nconst ProtobufCMessageDescriptor wi_fi_scan_result__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"WiFiScanResult\",\n  \"WiFiScanResult\",\n  \"WiFiScanResult\",\n  \"\",\n  sizeof(WiFiScanResult),\n  5,\n  wi_fi_scan_result__field_descriptors,\n  wi_fi_scan_result__field_indices_by_name,\n  1,  wi_fi_scan_result__number_ranges,\n  (ProtobufCMessageInit) wi_fi_scan_result__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor thread_scan_result__field_descriptors[7] =\n{\n  {\n    \"pan_id\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_UINT32,\n    0,   /* quantifier_offset */\n    offsetof(ThreadScanResult, pan_id),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"channel\",\n    2,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_UINT32,\n    0,   /* quantifier_offset */\n    offsetof(ThreadScanResult, channel),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"rssi\",\n    3,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_INT32,\n    0,   /* quantifier_offset */\n    offsetof(ThreadScanResult, rssi),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"lqi\",\n    4,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_UINT32,\n    0,   /* quantifier_offset */\n    offsetof(ThreadScanResult, lqi),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"ext_addr\",\n    5,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_BYTES,\n    0,   /* quantifier_offset */\n    offsetof(ThreadScanResult, ext_addr),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"network_name\",\n    6,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_STRING,\n    0,   /* quantifier_offset */\n    offsetof(ThreadScanResult, network_name),\n    NULL,\n    &protobuf_c_empty_string,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"ext_pan_id\",\n    7,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_BYTES,\n    0,   /* quantifier_offset */\n    offsetof(ThreadScanResult, ext_pan_id),\n    NULL,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned thread_scan_result__field_indices_by_name[] = {\n  1,   /* field[1] = channel */\n  4,   /* field[4] = ext_addr */\n  6,   /* field[6] = ext_pan_id */\n  3,   /* field[3] = lqi */\n  5,   /* field[5] = network_name */\n  0,   /* field[0] = pan_id */\n  2,   /* field[2] = rssi */\n};\nstatic const ProtobufCIntRange thread_scan_result__number_ranges[1 + 1] =\n{\n  { 1, 0 },\n  { 0, 7 }\n};\nconst ProtobufCMessageDescriptor thread_scan_result__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"ThreadScanResult\",\n  \"ThreadScanResult\",\n  \"ThreadScanResult\",\n  \"\",\n  sizeof(ThreadScanResult),\n  7,\n  thread_scan_result__field_descriptors,\n  thread_scan_result__field_indices_by_name,\n  1,  thread_scan_result__number_ranges,\n  (ProtobufCMessageInit) thread_scan_result__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor resp_scan_wifi_result__field_descriptors[1] =\n{\n  {\n    \"entries\",\n    1,\n    PROTOBUF_C_LABEL_REPEATED,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(RespScanWifiResult, n_entries),\n    offsetof(RespScanWifiResult, entries),\n    &wi_fi_scan_result__descriptor,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned resp_scan_wifi_result__field_indices_by_name[] = {\n  0,   /* field[0] = entries */\n};\nstatic const ProtobufCIntRange resp_scan_wifi_result__number_ranges[1 + 1] =\n{\n  { 1, 0 },\n  { 0, 1 }\n};\nconst ProtobufCMessageDescriptor resp_scan_wifi_result__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"RespScanWifiResult\",\n  \"RespScanWifiResult\",\n  \"RespScanWifiResult\",\n  \"\",\n  sizeof(RespScanWifiResult),\n  1,\n  resp_scan_wifi_result__field_descriptors,\n  resp_scan_wifi_result__field_indices_by_name,\n  1,  resp_scan_wifi_result__number_ranges,\n  (ProtobufCMessageInit) resp_scan_wifi_result__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor resp_scan_thread_result__field_descriptors[1] =\n{\n  {\n    \"entries\",\n    1,\n    PROTOBUF_C_LABEL_REPEATED,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(RespScanThreadResult, n_entries),\n    offsetof(RespScanThreadResult, entries),\n    &thread_scan_result__descriptor,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned resp_scan_thread_result__field_indices_by_name[] = {\n  0,   /* field[0] = entries */\n};\nstatic const ProtobufCIntRange resp_scan_thread_result__number_ranges[1 + 1] =\n{\n  { 1, 0 },\n  { 0, 1 }\n};\nconst ProtobufCMessageDescriptor resp_scan_thread_result__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"RespScanThreadResult\",\n  \"RespScanThreadResult\",\n  \"RespScanThreadResult\",\n  \"\",\n  sizeof(RespScanThreadResult),\n  1,\n  resp_scan_thread_result__field_descriptors,\n  resp_scan_thread_result__field_indices_by_name,\n  1,  resp_scan_thread_result__number_ranges,\n  (ProtobufCMessageInit) resp_scan_thread_result__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCFieldDescriptor network_scan_payload__field_descriptors[14] =\n{\n  {\n    \"msg\",\n    1,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_ENUM,\n    0,   /* quantifier_offset */\n    offsetof(NetworkScanPayload, msg),\n    &network_scan_msg_type__descriptor,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"status\",\n    2,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_ENUM,\n    0,   /* quantifier_offset */\n    offsetof(NetworkScanPayload, status),\n    &status__descriptor,\n    NULL,\n    0,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"cmd_scan_wifi_start\",\n    10,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkScanPayload, payload_case),\n    offsetof(NetworkScanPayload, cmd_scan_wifi_start),\n    &cmd_scan_wifi_start__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"resp_scan_wifi_start\",\n    11,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkScanPayload, payload_case),\n    offsetof(NetworkScanPayload, resp_scan_wifi_start),\n    &resp_scan_wifi_start__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"cmd_scan_wifi_status\",\n    12,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkScanPayload, payload_case),\n    offsetof(NetworkScanPayload, cmd_scan_wifi_status),\n    &cmd_scan_wifi_status__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"resp_scan_wifi_status\",\n    13,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkScanPayload, payload_case),\n    offsetof(NetworkScanPayload, resp_scan_wifi_status),\n    &resp_scan_wifi_status__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"cmd_scan_wifi_result\",\n    14,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkScanPayload, payload_case),\n    offsetof(NetworkScanPayload, cmd_scan_wifi_result),\n    &cmd_scan_wifi_result__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"resp_scan_wifi_result\",\n    15,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkScanPayload, payload_case),\n    offsetof(NetworkScanPayload, resp_scan_wifi_result),\n    &resp_scan_wifi_result__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"cmd_scan_thread_start\",\n    16,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkScanPayload, payload_case),\n    offsetof(NetworkScanPayload, cmd_scan_thread_start),\n    &cmd_scan_thread_start__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"resp_scan_thread_start\",\n    17,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkScanPayload, payload_case),\n    offsetof(NetworkScanPayload, resp_scan_thread_start),\n    &resp_scan_thread_start__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"cmd_scan_thread_status\",\n    18,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkScanPayload, payload_case),\n    offsetof(NetworkScanPayload, cmd_scan_thread_status),\n    &cmd_scan_thread_status__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"resp_scan_thread_status\",\n    19,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkScanPayload, payload_case),\n    offsetof(NetworkScanPayload, resp_scan_thread_status),\n    &resp_scan_thread_status__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"cmd_scan_thread_result\",\n    20,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkScanPayload, payload_case),\n    offsetof(NetworkScanPayload, cmd_scan_thread_result),\n    &cmd_scan_thread_result__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n  {\n    \"resp_scan_thread_result\",\n    21,\n    PROTOBUF_C_LABEL_NONE,\n    PROTOBUF_C_TYPE_MESSAGE,\n    offsetof(NetworkScanPayload, payload_case),\n    offsetof(NetworkScanPayload, resp_scan_thread_result),\n    &resp_scan_thread_result__descriptor,\n    NULL,\n    0 | PROTOBUF_C_FIELD_FLAG_ONEOF,             /* flags */\n    0,NULL,NULL    /* reserved1,reserved2, etc */\n  },\n};\nstatic const unsigned network_scan_payload__field_indices_by_name[] = {\n  12,   /* field[12] = cmd_scan_thread_result */\n  8,   /* field[8] = cmd_scan_thread_start */\n  10,   /* field[10] = cmd_scan_thread_status */\n  6,   /* field[6] = cmd_scan_wifi_result */\n  2,   /* field[2] = cmd_scan_wifi_start */\n  4,   /* field[4] = cmd_scan_wifi_status */\n  0,   /* field[0] = msg */\n  13,   /* field[13] = resp_scan_thread_result */\n  9,   /* field[9] = resp_scan_thread_start */\n  11,   /* field[11] = resp_scan_thread_status */\n  7,   /* field[7] = resp_scan_wifi_result */\n  3,   /* field[3] = resp_scan_wifi_start */\n  5,   /* field[5] = resp_scan_wifi_status */\n  1,   /* field[1] = status */\n};\nstatic const ProtobufCIntRange network_scan_payload__number_ranges[2 + 1] =\n{\n  { 1, 0 },\n  { 10, 2 },\n  { 0, 14 }\n};\nconst ProtobufCMessageDescriptor network_scan_payload__descriptor =\n{\n  PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,\n  \"NetworkScanPayload\",\n  \"NetworkScanPayload\",\n  \"NetworkScanPayload\",\n  \"\",\n  sizeof(NetworkScanPayload),\n  14,\n  network_scan_payload__field_descriptors,\n  network_scan_payload__field_indices_by_name,\n  2,  network_scan_payload__number_ranges,\n  (ProtobufCMessageInit) network_scan_payload__init,\n  NULL,NULL,NULL    /* reserved[123] */\n};\nstatic const ProtobufCEnumValue network_scan_msg_type__enum_values_by_number[12] =\n{\n  { \"TypeCmdScanWifiStart\", \"NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiStart\", 0 },\n  { \"TypeRespScanWifiStart\", \"NETWORK_SCAN_MSG_TYPE__TypeRespScanWifiStart\", 1 },\n  { \"TypeCmdScanWifiStatus\", \"NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiStatus\", 2 },\n  { \"TypeRespScanWifiStatus\", \"NETWORK_SCAN_MSG_TYPE__TypeRespScanWifiStatus\", 3 },\n  { \"TypeCmdScanWifiResult\", \"NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiResult\", 4 },\n  { \"TypeRespScanWifiResult\", \"NETWORK_SCAN_MSG_TYPE__TypeRespScanWifiResult\", 5 },\n  { \"TypeCmdScanThreadStart\", \"NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadStart\", 6 },\n  { \"TypeRespScanThreadStart\", \"NETWORK_SCAN_MSG_TYPE__TypeRespScanThreadStart\", 7 },\n  { \"TypeCmdScanThreadStatus\", \"NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadStatus\", 8 },\n  { \"TypeRespScanThreadStatus\", \"NETWORK_SCAN_MSG_TYPE__TypeRespScanThreadStatus\", 9 },\n  { \"TypeCmdScanThreadResult\", \"NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadResult\", 10 },\n  { \"TypeRespScanThreadResult\", \"NETWORK_SCAN_MSG_TYPE__TypeRespScanThreadResult\", 11 },\n};\nstatic const ProtobufCIntRange network_scan_msg_type__value_ranges[] = {\n{0, 0},{0, 12}\n};\nstatic const ProtobufCEnumValueIndex network_scan_msg_type__enum_values_by_name[12] =\n{\n  { \"TypeCmdScanThreadResult\", 10 },\n  { \"TypeCmdScanThreadStart\", 6 },\n  { \"TypeCmdScanThreadStatus\", 8 },\n  { \"TypeCmdScanWifiResult\", 4 },\n  { \"TypeCmdScanWifiStart\", 0 },\n  { \"TypeCmdScanWifiStatus\", 2 },\n  { \"TypeRespScanThreadResult\", 11 },\n  { \"TypeRespScanThreadStart\", 7 },\n  { \"TypeRespScanThreadStatus\", 9 },\n  { \"TypeRespScanWifiResult\", 5 },\n  { \"TypeRespScanWifiStart\", 1 },\n  { \"TypeRespScanWifiStatus\", 3 },\n};\nconst ProtobufCEnumDescriptor network_scan_msg_type__descriptor =\n{\n  PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,\n  \"NetworkScanMsgType\",\n  \"NetworkScanMsgType\",\n  \"NetworkScanMsgType\",\n  \"\",\n  12,\n  network_scan_msg_type__enum_values_by_number,\n  12,\n  network_scan_msg_type__enum_values_by_name,\n  1,\n  network_scan_msg_type__value_ranges,\n  NULL,NULL,NULL,NULL   /* reserved[1234] */\n};\n"
  },
  {
    "path": "network_provisioning/proto-c/network_scan.pb-c.h",
    "content": "/* Generated by the protocol buffer compiler.  DO NOT EDIT! */\n/* Generated from: network_scan.proto */\n\n#ifndef PROTOBUF_C_network_5fscan_2eproto__INCLUDED\n#define PROTOBUF_C_network_5fscan_2eproto__INCLUDED\n\n#include <protobuf-c/protobuf-c.h>\n\nPROTOBUF_C__BEGIN_DECLS\n\n#if PROTOBUF_C_VERSION_NUMBER < 1003000\n# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.\n#elif 1004000 < PROTOBUF_C_MIN_COMPILER_VERSION\n# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.\n#endif\n\n#include \"constants.pb-c.h\"\n#include \"network_constants.pb-c.h\"\n\ntypedef struct CmdScanWifiStart CmdScanWifiStart;\ntypedef struct CmdScanThreadStart CmdScanThreadStart;\ntypedef struct RespScanWifiStart RespScanWifiStart;\ntypedef struct RespScanThreadStart RespScanThreadStart;\ntypedef struct CmdScanWifiStatus CmdScanWifiStatus;\ntypedef struct CmdScanThreadStatus CmdScanThreadStatus;\ntypedef struct RespScanWifiStatus RespScanWifiStatus;\ntypedef struct RespScanThreadStatus RespScanThreadStatus;\ntypedef struct CmdScanWifiResult CmdScanWifiResult;\ntypedef struct CmdScanThreadResult CmdScanThreadResult;\ntypedef struct WiFiScanResult WiFiScanResult;\ntypedef struct ThreadScanResult ThreadScanResult;\ntypedef struct RespScanWifiResult RespScanWifiResult;\ntypedef struct RespScanThreadResult RespScanThreadResult;\ntypedef struct NetworkScanPayload NetworkScanPayload;\n\n\n/* --- enums --- */\n\ntypedef enum _NetworkScanMsgType {\n  NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiStart = 0,\n  NETWORK_SCAN_MSG_TYPE__TypeRespScanWifiStart = 1,\n  NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiStatus = 2,\n  NETWORK_SCAN_MSG_TYPE__TypeRespScanWifiStatus = 3,\n  NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiResult = 4,\n  NETWORK_SCAN_MSG_TYPE__TypeRespScanWifiResult = 5,\n  NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadStart = 6,\n  NETWORK_SCAN_MSG_TYPE__TypeRespScanThreadStart = 7,\n  NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadStatus = 8,\n  NETWORK_SCAN_MSG_TYPE__TypeRespScanThreadStatus = 9,\n  NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadResult = 10,\n  NETWORK_SCAN_MSG_TYPE__TypeRespScanThreadResult = 11\n    PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(NETWORK_SCAN_MSG_TYPE)\n} NetworkScanMsgType;\n\n/* --- messages --- */\n\nstruct  CmdScanWifiStart\n{\n  ProtobufCMessage base;\n  protobuf_c_boolean blocking;\n  protobuf_c_boolean passive;\n  uint32_t group_channels;\n  uint32_t period_ms;\n};\n#define CMD_SCAN_WIFI_START__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&cmd_scan_wifi_start__descriptor) \\\n    , 0, 0, 0, 0 }\n\n\nstruct  CmdScanThreadStart\n{\n  ProtobufCMessage base;\n  protobuf_c_boolean blocking;\n  uint32_t channel_mask;\n};\n#define CMD_SCAN_THREAD_START__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&cmd_scan_thread_start__descriptor) \\\n    , 0, 0 }\n\n\nstruct  RespScanWifiStart\n{\n  ProtobufCMessage base;\n};\n#define RESP_SCAN_WIFI_START__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&resp_scan_wifi_start__descriptor) \\\n     }\n\n\nstruct  RespScanThreadStart\n{\n  ProtobufCMessage base;\n};\n#define RESP_SCAN_THREAD_START__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&resp_scan_thread_start__descriptor) \\\n     }\n\n\nstruct  CmdScanWifiStatus\n{\n  ProtobufCMessage base;\n};\n#define CMD_SCAN_WIFI_STATUS__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&cmd_scan_wifi_status__descriptor) \\\n     }\n\n\nstruct  CmdScanThreadStatus\n{\n  ProtobufCMessage base;\n};\n#define CMD_SCAN_THREAD_STATUS__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&cmd_scan_thread_status__descriptor) \\\n     }\n\n\nstruct  RespScanWifiStatus\n{\n  ProtobufCMessage base;\n  protobuf_c_boolean scan_finished;\n  uint32_t result_count;\n};\n#define RESP_SCAN_WIFI_STATUS__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&resp_scan_wifi_status__descriptor) \\\n    , 0, 0 }\n\n\nstruct  RespScanThreadStatus\n{\n  ProtobufCMessage base;\n  protobuf_c_boolean scan_finished;\n  uint32_t result_count;\n};\n#define RESP_SCAN_THREAD_STATUS__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&resp_scan_thread_status__descriptor) \\\n    , 0, 0 }\n\n\nstruct  CmdScanWifiResult\n{\n  ProtobufCMessage base;\n  uint32_t start_index;\n  uint32_t count;\n};\n#define CMD_SCAN_WIFI_RESULT__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&cmd_scan_wifi_result__descriptor) \\\n    , 0, 0 }\n\n\nstruct  CmdScanThreadResult\n{\n  ProtobufCMessage base;\n  uint32_t start_index;\n  uint32_t count;\n};\n#define CMD_SCAN_THREAD_RESULT__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&cmd_scan_thread_result__descriptor) \\\n    , 0, 0 }\n\n\nstruct  WiFiScanResult\n{\n  ProtobufCMessage base;\n  ProtobufCBinaryData ssid;\n  uint32_t channel;\n  int32_t rssi;\n  ProtobufCBinaryData bssid;\n  WifiAuthMode auth;\n};\n#define WI_FI_SCAN_RESULT__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&wi_fi_scan_result__descriptor) \\\n    , {0,NULL}, 0, 0, {0,NULL}, WIFI_AUTH_MODE__Open }\n\n\nstruct  ThreadScanResult\n{\n  ProtobufCMessage base;\n  uint32_t pan_id;\n  uint32_t channel;\n  int32_t rssi;\n  uint32_t lqi;\n  ProtobufCBinaryData ext_addr;\n  char *network_name;\n  ProtobufCBinaryData ext_pan_id;\n};\n#define THREAD_SCAN_RESULT__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&thread_scan_result__descriptor) \\\n    , 0, 0, 0, 0, {0,NULL}, (char *)protobuf_c_empty_string, {0,NULL} }\n\n\nstruct  RespScanWifiResult\n{\n  ProtobufCMessage base;\n  size_t n_entries;\n  WiFiScanResult **entries;\n};\n#define RESP_SCAN_WIFI_RESULT__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&resp_scan_wifi_result__descriptor) \\\n    , 0,NULL }\n\n\nstruct  RespScanThreadResult\n{\n  ProtobufCMessage base;\n  size_t n_entries;\n  ThreadScanResult **entries;\n};\n#define RESP_SCAN_THREAD_RESULT__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&resp_scan_thread_result__descriptor) \\\n    , 0,NULL }\n\n\ntypedef enum {\n  NETWORK_SCAN_PAYLOAD__PAYLOAD__NOT_SET = 0,\n  NETWORK_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_WIFI_START = 10,\n  NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_WIFI_START = 11,\n  NETWORK_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_WIFI_STATUS = 12,\n  NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_WIFI_STATUS = 13,\n  NETWORK_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_WIFI_RESULT = 14,\n  NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_WIFI_RESULT = 15,\n  NETWORK_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_THREAD_START = 16,\n  NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_THREAD_START = 17,\n  NETWORK_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_THREAD_STATUS = 18,\n  NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_THREAD_STATUS = 19,\n  NETWORK_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_THREAD_RESULT = 20,\n  NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_THREAD_RESULT = 21\n    PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(NETWORK_SCAN_PAYLOAD__PAYLOAD__CASE)\n} NetworkScanPayload__PayloadCase;\n\nstruct  NetworkScanPayload\n{\n  ProtobufCMessage base;\n  NetworkScanMsgType msg;\n  Status status;\n  NetworkScanPayload__PayloadCase payload_case;\n  union {\n    CmdScanWifiStart *cmd_scan_wifi_start;\n    RespScanWifiStart *resp_scan_wifi_start;\n    CmdScanWifiStatus *cmd_scan_wifi_status;\n    RespScanWifiStatus *resp_scan_wifi_status;\n    CmdScanWifiResult *cmd_scan_wifi_result;\n    RespScanWifiResult *resp_scan_wifi_result;\n    CmdScanThreadStart *cmd_scan_thread_start;\n    RespScanThreadStart *resp_scan_thread_start;\n    CmdScanThreadStatus *cmd_scan_thread_status;\n    RespScanThreadStatus *resp_scan_thread_status;\n    CmdScanThreadResult *cmd_scan_thread_result;\n    RespScanThreadResult *resp_scan_thread_result;\n  };\n};\n#define NETWORK_SCAN_PAYLOAD__INIT \\\n { PROTOBUF_C_MESSAGE_INIT (&network_scan_payload__descriptor) \\\n    , NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiStart, STATUS__Success, NETWORK_SCAN_PAYLOAD__PAYLOAD__NOT_SET, {0} }\n\n\n/* CmdScanWifiStart methods */\nvoid   cmd_scan_wifi_start__init\n                     (CmdScanWifiStart         *message);\nsize_t cmd_scan_wifi_start__get_packed_size\n                     (const CmdScanWifiStart   *message);\nsize_t cmd_scan_wifi_start__pack\n                     (const CmdScanWifiStart   *message,\n                      uint8_t             *out);\nsize_t cmd_scan_wifi_start__pack_to_buffer\n                     (const CmdScanWifiStart   *message,\n                      ProtobufCBuffer     *buffer);\nCmdScanWifiStart *\n       cmd_scan_wifi_start__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   cmd_scan_wifi_start__free_unpacked\n                     (CmdScanWifiStart *message,\n                      ProtobufCAllocator *allocator);\n/* CmdScanThreadStart methods */\nvoid   cmd_scan_thread_start__init\n                     (CmdScanThreadStart         *message);\nsize_t cmd_scan_thread_start__get_packed_size\n                     (const CmdScanThreadStart   *message);\nsize_t cmd_scan_thread_start__pack\n                     (const CmdScanThreadStart   *message,\n                      uint8_t             *out);\nsize_t cmd_scan_thread_start__pack_to_buffer\n                     (const CmdScanThreadStart   *message,\n                      ProtobufCBuffer     *buffer);\nCmdScanThreadStart *\n       cmd_scan_thread_start__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   cmd_scan_thread_start__free_unpacked\n                     (CmdScanThreadStart *message,\n                      ProtobufCAllocator *allocator);\n/* RespScanWifiStart methods */\nvoid   resp_scan_wifi_start__init\n                     (RespScanWifiStart         *message);\nsize_t resp_scan_wifi_start__get_packed_size\n                     (const RespScanWifiStart   *message);\nsize_t resp_scan_wifi_start__pack\n                     (const RespScanWifiStart   *message,\n                      uint8_t             *out);\nsize_t resp_scan_wifi_start__pack_to_buffer\n                     (const RespScanWifiStart   *message,\n                      ProtobufCBuffer     *buffer);\nRespScanWifiStart *\n       resp_scan_wifi_start__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   resp_scan_wifi_start__free_unpacked\n                     (RespScanWifiStart *message,\n                      ProtobufCAllocator *allocator);\n/* RespScanThreadStart methods */\nvoid   resp_scan_thread_start__init\n                     (RespScanThreadStart         *message);\nsize_t resp_scan_thread_start__get_packed_size\n                     (const RespScanThreadStart   *message);\nsize_t resp_scan_thread_start__pack\n                     (const RespScanThreadStart   *message,\n                      uint8_t             *out);\nsize_t resp_scan_thread_start__pack_to_buffer\n                     (const RespScanThreadStart   *message,\n                      ProtobufCBuffer     *buffer);\nRespScanThreadStart *\n       resp_scan_thread_start__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   resp_scan_thread_start__free_unpacked\n                     (RespScanThreadStart *message,\n                      ProtobufCAllocator *allocator);\n/* CmdScanWifiStatus methods */\nvoid   cmd_scan_wifi_status__init\n                     (CmdScanWifiStatus         *message);\nsize_t cmd_scan_wifi_status__get_packed_size\n                     (const CmdScanWifiStatus   *message);\nsize_t cmd_scan_wifi_status__pack\n                     (const CmdScanWifiStatus   *message,\n                      uint8_t             *out);\nsize_t cmd_scan_wifi_status__pack_to_buffer\n                     (const CmdScanWifiStatus   *message,\n                      ProtobufCBuffer     *buffer);\nCmdScanWifiStatus *\n       cmd_scan_wifi_status__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   cmd_scan_wifi_status__free_unpacked\n                     (CmdScanWifiStatus *message,\n                      ProtobufCAllocator *allocator);\n/* CmdScanThreadStatus methods */\nvoid   cmd_scan_thread_status__init\n                     (CmdScanThreadStatus         *message);\nsize_t cmd_scan_thread_status__get_packed_size\n                     (const CmdScanThreadStatus   *message);\nsize_t cmd_scan_thread_status__pack\n                     (const CmdScanThreadStatus   *message,\n                      uint8_t             *out);\nsize_t cmd_scan_thread_status__pack_to_buffer\n                     (const CmdScanThreadStatus   *message,\n                      ProtobufCBuffer     *buffer);\nCmdScanThreadStatus *\n       cmd_scan_thread_status__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   cmd_scan_thread_status__free_unpacked\n                     (CmdScanThreadStatus *message,\n                      ProtobufCAllocator *allocator);\n/* RespScanWifiStatus methods */\nvoid   resp_scan_wifi_status__init\n                     (RespScanWifiStatus         *message);\nsize_t resp_scan_wifi_status__get_packed_size\n                     (const RespScanWifiStatus   *message);\nsize_t resp_scan_wifi_status__pack\n                     (const RespScanWifiStatus   *message,\n                      uint8_t             *out);\nsize_t resp_scan_wifi_status__pack_to_buffer\n                     (const RespScanWifiStatus   *message,\n                      ProtobufCBuffer     *buffer);\nRespScanWifiStatus *\n       resp_scan_wifi_status__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   resp_scan_wifi_status__free_unpacked\n                     (RespScanWifiStatus *message,\n                      ProtobufCAllocator *allocator);\n/* RespScanThreadStatus methods */\nvoid   resp_scan_thread_status__init\n                     (RespScanThreadStatus         *message);\nsize_t resp_scan_thread_status__get_packed_size\n                     (const RespScanThreadStatus   *message);\nsize_t resp_scan_thread_status__pack\n                     (const RespScanThreadStatus   *message,\n                      uint8_t             *out);\nsize_t resp_scan_thread_status__pack_to_buffer\n                     (const RespScanThreadStatus   *message,\n                      ProtobufCBuffer     *buffer);\nRespScanThreadStatus *\n       resp_scan_thread_status__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   resp_scan_thread_status__free_unpacked\n                     (RespScanThreadStatus *message,\n                      ProtobufCAllocator *allocator);\n/* CmdScanWifiResult methods */\nvoid   cmd_scan_wifi_result__init\n                     (CmdScanWifiResult         *message);\nsize_t cmd_scan_wifi_result__get_packed_size\n                     (const CmdScanWifiResult   *message);\nsize_t cmd_scan_wifi_result__pack\n                     (const CmdScanWifiResult   *message,\n                      uint8_t             *out);\nsize_t cmd_scan_wifi_result__pack_to_buffer\n                     (const CmdScanWifiResult   *message,\n                      ProtobufCBuffer     *buffer);\nCmdScanWifiResult *\n       cmd_scan_wifi_result__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   cmd_scan_wifi_result__free_unpacked\n                     (CmdScanWifiResult *message,\n                      ProtobufCAllocator *allocator);\n/* CmdScanThreadResult methods */\nvoid   cmd_scan_thread_result__init\n                     (CmdScanThreadResult         *message);\nsize_t cmd_scan_thread_result__get_packed_size\n                     (const CmdScanThreadResult   *message);\nsize_t cmd_scan_thread_result__pack\n                     (const CmdScanThreadResult   *message,\n                      uint8_t             *out);\nsize_t cmd_scan_thread_result__pack_to_buffer\n                     (const CmdScanThreadResult   *message,\n                      ProtobufCBuffer     *buffer);\nCmdScanThreadResult *\n       cmd_scan_thread_result__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   cmd_scan_thread_result__free_unpacked\n                     (CmdScanThreadResult *message,\n                      ProtobufCAllocator *allocator);\n/* WiFiScanResult methods */\nvoid   wi_fi_scan_result__init\n                     (WiFiScanResult         *message);\nsize_t wi_fi_scan_result__get_packed_size\n                     (const WiFiScanResult   *message);\nsize_t wi_fi_scan_result__pack\n                     (const WiFiScanResult   *message,\n                      uint8_t             *out);\nsize_t wi_fi_scan_result__pack_to_buffer\n                     (const WiFiScanResult   *message,\n                      ProtobufCBuffer     *buffer);\nWiFiScanResult *\n       wi_fi_scan_result__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   wi_fi_scan_result__free_unpacked\n                     (WiFiScanResult *message,\n                      ProtobufCAllocator *allocator);\n/* ThreadScanResult methods */\nvoid   thread_scan_result__init\n                     (ThreadScanResult         *message);\nsize_t thread_scan_result__get_packed_size\n                     (const ThreadScanResult   *message);\nsize_t thread_scan_result__pack\n                     (const ThreadScanResult   *message,\n                      uint8_t             *out);\nsize_t thread_scan_result__pack_to_buffer\n                     (const ThreadScanResult   *message,\n                      ProtobufCBuffer     *buffer);\nThreadScanResult *\n       thread_scan_result__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   thread_scan_result__free_unpacked\n                     (ThreadScanResult *message,\n                      ProtobufCAllocator *allocator);\n/* RespScanWifiResult methods */\nvoid   resp_scan_wifi_result__init\n                     (RespScanWifiResult         *message);\nsize_t resp_scan_wifi_result__get_packed_size\n                     (const RespScanWifiResult   *message);\nsize_t resp_scan_wifi_result__pack\n                     (const RespScanWifiResult   *message,\n                      uint8_t             *out);\nsize_t resp_scan_wifi_result__pack_to_buffer\n                     (const RespScanWifiResult   *message,\n                      ProtobufCBuffer     *buffer);\nRespScanWifiResult *\n       resp_scan_wifi_result__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   resp_scan_wifi_result__free_unpacked\n                     (RespScanWifiResult *message,\n                      ProtobufCAllocator *allocator);\n/* RespScanThreadResult methods */\nvoid   resp_scan_thread_result__init\n                     (RespScanThreadResult         *message);\nsize_t resp_scan_thread_result__get_packed_size\n                     (const RespScanThreadResult   *message);\nsize_t resp_scan_thread_result__pack\n                     (const RespScanThreadResult   *message,\n                      uint8_t             *out);\nsize_t resp_scan_thread_result__pack_to_buffer\n                     (const RespScanThreadResult   *message,\n                      ProtobufCBuffer     *buffer);\nRespScanThreadResult *\n       resp_scan_thread_result__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   resp_scan_thread_result__free_unpacked\n                     (RespScanThreadResult *message,\n                      ProtobufCAllocator *allocator);\n/* NetworkScanPayload methods */\nvoid   network_scan_payload__init\n                     (NetworkScanPayload         *message);\nsize_t network_scan_payload__get_packed_size\n                     (const NetworkScanPayload   *message);\nsize_t network_scan_payload__pack\n                     (const NetworkScanPayload   *message,\n                      uint8_t             *out);\nsize_t network_scan_payload__pack_to_buffer\n                     (const NetworkScanPayload   *message,\n                      ProtobufCBuffer     *buffer);\nNetworkScanPayload *\n       network_scan_payload__unpack\n                     (ProtobufCAllocator  *allocator,\n                      size_t               len,\n                      const uint8_t       *data);\nvoid   network_scan_payload__free_unpacked\n                     (NetworkScanPayload *message,\n                      ProtobufCAllocator *allocator);\n/* --- per-message closures --- */\n\ntypedef void (*CmdScanWifiStart_Closure)\n                 (const CmdScanWifiStart *message,\n                  void *closure_data);\ntypedef void (*CmdScanThreadStart_Closure)\n                 (const CmdScanThreadStart *message,\n                  void *closure_data);\ntypedef void (*RespScanWifiStart_Closure)\n                 (const RespScanWifiStart *message,\n                  void *closure_data);\ntypedef void (*RespScanThreadStart_Closure)\n                 (const RespScanThreadStart *message,\n                  void *closure_data);\ntypedef void (*CmdScanWifiStatus_Closure)\n                 (const CmdScanWifiStatus *message,\n                  void *closure_data);\ntypedef void (*CmdScanThreadStatus_Closure)\n                 (const CmdScanThreadStatus *message,\n                  void *closure_data);\ntypedef void (*RespScanWifiStatus_Closure)\n                 (const RespScanWifiStatus *message,\n                  void *closure_data);\ntypedef void (*RespScanThreadStatus_Closure)\n                 (const RespScanThreadStatus *message,\n                  void *closure_data);\ntypedef void (*CmdScanWifiResult_Closure)\n                 (const CmdScanWifiResult *message,\n                  void *closure_data);\ntypedef void (*CmdScanThreadResult_Closure)\n                 (const CmdScanThreadResult *message,\n                  void *closure_data);\ntypedef void (*WiFiScanResult_Closure)\n                 (const WiFiScanResult *message,\n                  void *closure_data);\ntypedef void (*ThreadScanResult_Closure)\n                 (const ThreadScanResult *message,\n                  void *closure_data);\ntypedef void (*RespScanWifiResult_Closure)\n                 (const RespScanWifiResult *message,\n                  void *closure_data);\ntypedef void (*RespScanThreadResult_Closure)\n                 (const RespScanThreadResult *message,\n                  void *closure_data);\ntypedef void (*NetworkScanPayload_Closure)\n                 (const NetworkScanPayload *message,\n                  void *closure_data);\n\n/* --- services --- */\n\n\n/* --- descriptors --- */\n\nextern const ProtobufCEnumDescriptor    network_scan_msg_type__descriptor;\nextern const ProtobufCMessageDescriptor cmd_scan_wifi_start__descriptor;\nextern const ProtobufCMessageDescriptor cmd_scan_thread_start__descriptor;\nextern const ProtobufCMessageDescriptor resp_scan_wifi_start__descriptor;\nextern const ProtobufCMessageDescriptor resp_scan_thread_start__descriptor;\nextern const ProtobufCMessageDescriptor cmd_scan_wifi_status__descriptor;\nextern const ProtobufCMessageDescriptor cmd_scan_thread_status__descriptor;\nextern const ProtobufCMessageDescriptor resp_scan_wifi_status__descriptor;\nextern const ProtobufCMessageDescriptor resp_scan_thread_status__descriptor;\nextern const ProtobufCMessageDescriptor cmd_scan_wifi_result__descriptor;\nextern const ProtobufCMessageDescriptor cmd_scan_thread_result__descriptor;\nextern const ProtobufCMessageDescriptor wi_fi_scan_result__descriptor;\nextern const ProtobufCMessageDescriptor thread_scan_result__descriptor;\nextern const ProtobufCMessageDescriptor resp_scan_wifi_result__descriptor;\nextern const ProtobufCMessageDescriptor resp_scan_thread_result__descriptor;\nextern const ProtobufCMessageDescriptor network_scan_payload__descriptor;\n\nPROTOBUF_C__END_DECLS\n\n\n#endif  /* PROTOBUF_C_network_5fscan_2eproto__INCLUDED */\n"
  },
  {
    "path": "network_provisioning/python/network_config_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: network_config.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf.internal import builder as _builder\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import symbol_database as _symbol_database\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nimport constants_pb2 as constants__pb2\nimport network_constants_pb2 as network__constants__pb2\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\\n\\x14network_config.proto\\x1a\\x0f\\x63onstants.proto\\x1a\\x17network_constants.proto\\\"\\x12\\n\\x10\\x43mdGetWifiStatus\\\"\\xf3\\x01\\n\\x11RespGetWifiStatus\\x12\\x17\\n\\x06status\\x18\\x01 \\x01(\\x0e\\x32\\x07.Status\\x12)\\n\\x0ewifi_sta_state\\x18\\x02 \\x01(\\x0e\\x32\\x11.WifiStationState\\x12\\x34\\n\\x10wifi_fail_reason\\x18\\n \\x01(\\x0e\\x32\\x18.WifiConnectFailedReasonH\\x00\\x12-\\n\\x0ewifi_connected\\x18\\x0b \\x01(\\x0b\\x32\\x13.WifiConnectedStateH\\x00\\x12,\\n\\x0e\\x61ttempt_failed\\x18\\x0c \\x01(\\x0b\\x32\\x12.WifiAttemptFailedH\\x00\\x42\\x07\\n\\x05state\\\"\\x14\\n\\x12\\x43mdGetThreadStatus\\\"\\xca\\x01\\n\\x13RespGetThreadStatus\\x12\\x17\\n\\x06status\\x18\\x01 \\x01(\\x0e\\x32\\x07.Status\\x12)\\n\\x0cthread_state\\x18\\x02 \\x01(\\x0e\\x32\\x13.ThreadNetworkState\\x12\\x37\\n\\x12thread_fail_reason\\x18\\n \\x01(\\x0e\\x32\\x19.ThreadAttachFailedReasonH\\x00\\x12-\\n\\x0fthread_attached\\x18\\x0b \\x01(\\x0b\\x32\\x12.ThreadAttachStateH\\x00\\x42\\x07\\n\\x05state\\\"T\\n\\x10\\x43mdSetWifiConfig\\x12\\x0c\\n\\x04ssid\\x18\\x01 \\x01(\\x0c\\x12\\x12\\n\\npassphrase\\x18\\x02 \\x01(\\x0c\\x12\\r\\n\\x05\\x62ssid\\x18\\x03 \\x01(\\x0c\\x12\\x0f\\n\\x07\\x63hannel\\x18\\x04 \\x01(\\x05\\\"%\\n\\x12\\x43mdSetThreadConfig\\x12\\x0f\\n\\x07\\x64\\x61taset\\x18\\x01 \\x01(\\x0c\\\",\\n\\x11RespSetWifiConfig\\x12\\x17\\n\\x06status\\x18\\x01 \\x01(\\x0e\\x32\\x07.Status\\\".\\n\\x13RespSetThreadConfig\\x12\\x17\\n\\x06status\\x18\\x01 \\x01(\\x0e\\x32\\x07.Status\\\"\\x14\\n\\x12\\x43mdApplyWifiConfig\\\"\\x16\\n\\x14\\x43mdApplyThreadConfig\\\".\\n\\x13RespApplyWifiConfig\\x12\\x17\\n\\x06status\\x18\\x01 \\x01(\\x0e\\x32\\x07.Status\\\"0\\n\\x15RespApplyThreadConfig\\x12\\x17\\n\\x06status\\x18\\x01 \\x01(\\x0e\\x32\\x07.Status\\\"\\xd1\\x05\\n\\x14NetworkConfigPayload\\x12\\\"\\n\\x03msg\\x18\\x01 \\x01(\\x0e\\x32\\x15.NetworkConfigMsgType\\x12\\x30\\n\\x13\\x63md_get_wifi_status\\x18\\n \\x01(\\x0b\\x32\\x11.CmdGetWifiStatusH\\x00\\x12\\x32\\n\\x14resp_get_wifi_status\\x18\\x0b \\x01(\\x0b\\x32\\x12.RespGetWifiStatusH\\x00\\x12\\x30\\n\\x13\\x63md_set_wifi_config\\x18\\x0c \\x01(\\x0b\\x32\\x11.CmdSetWifiConfigH\\x00\\x12\\x32\\n\\x14resp_set_wifi_config\\x18\\r \\x01(\\x0b\\x32\\x12.RespSetWifiConfigH\\x00\\x12\\x34\\n\\x15\\x63md_apply_wifi_config\\x18\\x0e \\x01(\\x0b\\x32\\x13.CmdApplyWifiConfigH\\x00\\x12\\x36\\n\\x16resp_apply_wifi_config\\x18\\x0f \\x01(\\x0b\\x32\\x14.RespApplyWifiConfigH\\x00\\x12\\x34\\n\\x15\\x63md_get_thread_status\\x18\\x10 \\x01(\\x0b\\x32\\x13.CmdGetThreadStatusH\\x00\\x12\\x36\\n\\x16resp_get_thread_status\\x18\\x11 \\x01(\\x0b\\x32\\x14.RespGetThreadStatusH\\x00\\x12\\x34\\n\\x15\\x63md_set_thread_config\\x18\\x12 \\x01(\\x0b\\x32\\x13.CmdSetThreadConfigH\\x00\\x12\\x36\\n\\x16resp_set_thread_config\\x18\\x13 \\x01(\\x0b\\x32\\x14.RespSetThreadConfigH\\x00\\x12\\x38\\n\\x17\\x63md_apply_thread_config\\x18\\x14 \\x01(\\x0b\\x32\\x15.CmdApplyThreadConfigH\\x00\\x12:\\n\\x18resp_apply_thread_config\\x18\\x15 \\x01(\\x0b\\x32\\x16.RespApplyThreadConfigH\\x00\\x42\\t\\n\\x07payload*\\xe8\\x02\\n\\x14NetworkConfigMsgType\\x12\\x18\\n\\x14TypeCmdGetWifiStatus\\x10\\x00\\x12\\x19\\n\\x15TypeRespGetWifiStatus\\x10\\x01\\x12\\x18\\n\\x14TypeCmdSetWifiConfig\\x10\\x02\\x12\\x19\\n\\x15TypeRespSetWifiConfig\\x10\\x03\\x12\\x1a\\n\\x16TypeCmdApplyWifiConfig\\x10\\x04\\x12\\x1b\\n\\x17TypeRespApplyWifiConfig\\x10\\x05\\x12\\x1a\\n\\x16TypeCmdGetThreadStatus\\x10\\x06\\x12\\x1b\\n\\x17TypeRespGetThreadStatus\\x10\\x07\\x12\\x1a\\n\\x16TypeCmdSetThreadConfig\\x10\\x08\\x12\\x1b\\n\\x17TypeRespSetThreadConfig\\x10\\t\\x12\\x1c\\n\\x18TypeCmdApplyThreadConfig\\x10\\n\\x12\\x1d\\n\\x19TypeRespApplyThreadConfig\\x10\\x0b\\x62\\x06proto3')\n\n_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())\n_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'network_config_pb2', globals())\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n  DESCRIPTOR._options = None\n  _NETWORKCONFIGMSGTYPE._serialized_start=1647\n  _NETWORKCONFIGMSGTYPE._serialized_end=2007\n  _CMDGETWIFISTATUS._serialized_start=66\n  _CMDGETWIFISTATUS._serialized_end=84\n  _RESPGETWIFISTATUS._serialized_start=87\n  _RESPGETWIFISTATUS._serialized_end=330\n  _CMDGETTHREADSTATUS._serialized_start=332\n  _CMDGETTHREADSTATUS._serialized_end=352\n  _RESPGETTHREADSTATUS._serialized_start=355\n  _RESPGETTHREADSTATUS._serialized_end=557\n  _CMDSETWIFICONFIG._serialized_start=559\n  _CMDSETWIFICONFIG._serialized_end=643\n  _CMDSETTHREADCONFIG._serialized_start=645\n  _CMDSETTHREADCONFIG._serialized_end=682\n  _RESPSETWIFICONFIG._serialized_start=684\n  _RESPSETWIFICONFIG._serialized_end=728\n  _RESPSETTHREADCONFIG._serialized_start=730\n  _RESPSETTHREADCONFIG._serialized_end=776\n  _CMDAPPLYWIFICONFIG._serialized_start=778\n  _CMDAPPLYWIFICONFIG._serialized_end=798\n  _CMDAPPLYTHREADCONFIG._serialized_start=800\n  _CMDAPPLYTHREADCONFIG._serialized_end=822\n  _RESPAPPLYWIFICONFIG._serialized_start=824\n  _RESPAPPLYWIFICONFIG._serialized_end=870\n  _RESPAPPLYTHREADCONFIG._serialized_start=872\n  _RESPAPPLYTHREADCONFIG._serialized_end=920\n  _NETWORKCONFIGPAYLOAD._serialized_start=923\n  _NETWORKCONFIGPAYLOAD._serialized_end=1644\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "network_provisioning/python/network_constants_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: network_constants.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf.internal import builder as _builder\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import symbol_database as _symbol_database\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\\n\\x17network_constants.proto\\\"v\\n\\x12WifiConnectedState\\x12\\x10\\n\\x08ip4_addr\\x18\\x01 \\x01(\\t\\x12 \\n\\tauth_mode\\x18\\x02 \\x01(\\x0e\\x32\\r.WifiAuthMode\\x12\\x0c\\n\\x04ssid\\x18\\x03 \\x01(\\x0c\\x12\\r\\n\\x05\\x62ssid\\x18\\x04 \\x01(\\x0c\\x12\\x0f\\n\\x07\\x63hannel\\x18\\x05 \\x01(\\x05\\\"/\\n\\x11WifiAttemptFailed\\x12\\x1a\\n\\x12\\x61ttempts_remaining\\x18\\x01 \\x01(\\r\\\"V\\n\\x11ThreadAttachState\\x12\\x0e\\n\\x06pan_id\\x18\\x01 \\x01(\\r\\x12\\x12\\n\\next_pan_id\\x18\\x02 \\x01(\\x0c\\x12\\x0f\\n\\x07\\x63hannel\\x18\\x03 \\x01(\\r\\x12\\x0c\\n\\x04name\\x18\\x04 \\x01(\\t*Y\\n\\x10WifiStationState\\x12\\r\\n\\tConnected\\x10\\x00\\x12\\x0e\\n\\nConnecting\\x10\\x01\\x12\\x10\\n\\x0c\\x44isconnected\\x10\\x02\\x12\\x14\\n\\x10\\x43onnectionFailed\\x10\\x03*A\\n\\x17WifiConnectFailedReason\\x12\\r\\n\\tAuthError\\x10\\x00\\x12\\x17\\n\\x13WifiNetworkNotFound\\x10\\x01*\\x84\\x01\\n\\x0cWifiAuthMode\\x12\\x08\\n\\x04Open\\x10\\x00\\x12\\x07\\n\\x03WEP\\x10\\x01\\x12\\x0b\\n\\x07WPA_PSK\\x10\\x02\\x12\\x0c\\n\\x08WPA2_PSK\\x10\\x03\\x12\\x10\\n\\x0cWPA_WPA2_PSK\\x10\\x04\\x12\\x13\\n\\x0fWPA2_ENTERPRISE\\x10\\x05\\x12\\x0c\\n\\x08WPA3_PSK\\x10\\x06\\x12\\x11\\n\\rWPA2_WPA3_PSK\\x10\\x07*U\\n\\x12ThreadNetworkState\\x12\\x0c\\n\\x08\\x41ttached\\x10\\x00\\x12\\r\\n\\tAttaching\\x10\\x01\\x12\\r\\n\\tDettached\\x10\\x02\\x12\\x13\\n\\x0f\\x41ttachingFailed\\x10\\x03*I\\n\\x18ThreadAttachFailedReason\\x12\\x12\\n\\x0e\\x44\\x61tasetInvalid\\x10\\x00\\x12\\x19\\n\\x15ThreadNetworkNotFound\\x10\\x01\\x62\\x06proto3')\n\n_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())\n_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'network_constants_pb2', globals())\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n  DESCRIPTOR._options = None\n  _WIFISTATIONSTATE._serialized_start=284\n  _WIFISTATIONSTATE._serialized_end=373\n  _WIFICONNECTFAILEDREASON._serialized_start=375\n  _WIFICONNECTFAILEDREASON._serialized_end=440\n  _WIFIAUTHMODE._serialized_start=443\n  _WIFIAUTHMODE._serialized_end=575\n  _THREADNETWORKSTATE._serialized_start=577\n  _THREADNETWORKSTATE._serialized_end=662\n  _THREADATTACHFAILEDREASON._serialized_start=664\n  _THREADATTACHFAILEDREASON._serialized_end=737\n  _WIFICONNECTEDSTATE._serialized_start=27\n  _WIFICONNECTEDSTATE._serialized_end=145\n  _WIFIATTEMPTFAILED._serialized_start=147\n  _WIFIATTEMPTFAILED._serialized_end=194\n  _THREADATTACHSTATE._serialized_start=196\n  _THREADATTACHSTATE._serialized_end=282\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "network_provisioning/python/network_ctrl_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: network_ctrl.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf.internal import builder as _builder\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import symbol_database as _symbol_database\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nimport constants_pb2 as constants__pb2\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\\n\\x12network_ctrl.proto\\x1a\\x0f\\x63onstants.proto\\\"\\x12\\n\\x10\\x43mdCtrlWifiReset\\\"\\x13\\n\\x11RespCtrlWifiReset\\\"\\x13\\n\\x11\\x43mdCtrlWifiReprov\\\"\\x14\\n\\x12RespCtrlWifiReprov\\\"\\x14\\n\\x12\\x43mdCtrlThreadReset\\\"\\x15\\n\\x13RespCtrlThreadReset\\\"\\x15\\n\\x13\\x43mdCtrlThreadReprov\\\"\\x16\\n\\x14RespCtrlThreadReprov\\\"\\x8a\\x04\\n\\x12NetworkCtrlPayload\\x12 \\n\\x03msg\\x18\\x01 \\x01(\\x0e\\x32\\x13.NetworkCtrlMsgType\\x12\\x17\\n\\x06status\\x18\\x02 \\x01(\\x0e\\x32\\x07.Status\\x12\\x30\\n\\x13\\x63md_ctrl_wifi_reset\\x18\\x0b \\x01(\\x0b\\x32\\x11.CmdCtrlWifiResetH\\x00\\x12\\x32\\n\\x14resp_ctrl_wifi_reset\\x18\\x0c \\x01(\\x0b\\x32\\x12.RespCtrlWifiResetH\\x00\\x12\\x32\\n\\x14\\x63md_ctrl_wifi_reprov\\x18\\r \\x01(\\x0b\\x32\\x12.CmdCtrlWifiReprovH\\x00\\x12\\x34\\n\\x15resp_ctrl_wifi_reprov\\x18\\x0e \\x01(\\x0b\\x32\\x13.RespCtrlWifiReprovH\\x00\\x12\\x34\\n\\x15\\x63md_ctrl_thread_reset\\x18\\x0f \\x01(\\x0b\\x32\\x13.CmdCtrlThreadResetH\\x00\\x12\\x36\\n\\x16resp_ctrl_thread_reset\\x18\\x10 \\x01(\\x0b\\x32\\x14.RespCtrlThreadResetH\\x00\\x12\\x36\\n\\x16\\x63md_ctrl_thread_reprov\\x18\\x11 \\x01(\\x0b\\x32\\x14.CmdCtrlThreadReprovH\\x00\\x12\\x38\\n\\x17resp_ctrl_thread_reprov\\x18\\x12 \\x01(\\x0b\\x32\\x15.RespCtrlThreadReprovH\\x00\\x42\\t\\n\\x07payload*\\x8a\\x02\\n\\x12NetworkCtrlMsgType\\x12\\x14\\n\\x10TypeCtrlReserved\\x10\\x00\\x12\\x18\\n\\x14TypeCmdCtrlWifiReset\\x10\\x01\\x12\\x19\\n\\x15TypeRespCtrlWifiReset\\x10\\x02\\x12\\x19\\n\\x15TypeCmdCtrlWifiReprov\\x10\\x03\\x12\\x1a\\n\\x16TypeRespCtrlWifiReprov\\x10\\x04\\x12\\x1a\\n\\x16TypeCmdCtrlThreadReset\\x10\\x05\\x12\\x1b\\n\\x17TypeRespCtrlThreadReset\\x10\\x06\\x12\\x1b\\n\\x17TypeCmdCtrlThreadReprov\\x10\\x07\\x12\\x1c\\n\\x18TypeRespCtrlThreadReprov\\x10\\x08\\x62\\x06proto3')\n\n_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())\n_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'network_ctrl_pb2', globals())\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n  DESCRIPTOR._options = None\n  _NETWORKCTRLMSGTYPE._serialized_start=741\n  _NETWORKCTRLMSGTYPE._serialized_end=1007\n  _CMDCTRLWIFIRESET._serialized_start=39\n  _CMDCTRLWIFIRESET._serialized_end=57\n  _RESPCTRLWIFIRESET._serialized_start=59\n  _RESPCTRLWIFIRESET._serialized_end=78\n  _CMDCTRLWIFIREPROV._serialized_start=80\n  _CMDCTRLWIFIREPROV._serialized_end=99\n  _RESPCTRLWIFIREPROV._serialized_start=101\n  _RESPCTRLWIFIREPROV._serialized_end=121\n  _CMDCTRLTHREADRESET._serialized_start=123\n  _CMDCTRLTHREADRESET._serialized_end=143\n  _RESPCTRLTHREADRESET._serialized_start=145\n  _RESPCTRLTHREADRESET._serialized_end=166\n  _CMDCTRLTHREADREPROV._serialized_start=168\n  _CMDCTRLTHREADREPROV._serialized_end=189\n  _RESPCTRLTHREADREPROV._serialized_start=191\n  _RESPCTRLTHREADREPROV._serialized_end=213\n  _NETWORKCTRLPAYLOAD._serialized_start=216\n  _NETWORKCTRLPAYLOAD._serialized_end=738\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "network_provisioning/python/network_scan_pb2.py",
    "content": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler.  DO NOT EDIT!\n# source: network_scan.proto\n\"\"\"Generated protocol buffer code.\"\"\"\nfrom google.protobuf.internal import builder as _builder\nfrom google.protobuf import descriptor as _descriptor\nfrom google.protobuf import descriptor_pool as _descriptor_pool\nfrom google.protobuf import symbol_database as _symbol_database\n# @@protoc_insertion_point(imports)\n\n_sym_db = _symbol_database.Default()\n\n\nimport constants_pb2 as constants__pb2\nimport network_constants_pb2 as network__constants__pb2\n\n\nDESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\\n\\x12network_scan.proto\\x1a\\x0f\\x63onstants.proto\\x1a\\x17network_constants.proto\\\"`\\n\\x10\\x43mdScanWifiStart\\x12\\x10\\n\\x08\\x62locking\\x18\\x01 \\x01(\\x08\\x12\\x0f\\n\\x07passive\\x18\\x02 \\x01(\\x08\\x12\\x16\\n\\x0egroup_channels\\x18\\x03 \\x01(\\r\\x12\\x11\\n\\tperiod_ms\\x18\\x04 \\x01(\\r\\\"<\\n\\x12\\x43mdScanThreadStart\\x12\\x10\\n\\x08\\x62locking\\x18\\x01 \\x01(\\x08\\x12\\x14\\n\\x0c\\x63hannel_mask\\x18\\x02 \\x01(\\r\\\"\\x13\\n\\x11RespScanWifiStart\\\"\\x15\\n\\x13RespScanThreadStart\\\"\\x13\\n\\x11\\x43mdScanWifiStatus\\\"\\x15\\n\\x13\\x43mdScanThreadStatus\\\"A\\n\\x12RespScanWifiStatus\\x12\\x15\\n\\rscan_finished\\x18\\x01 \\x01(\\x08\\x12\\x14\\n\\x0cresult_count\\x18\\x02 \\x01(\\r\\\"C\\n\\x14RespScanThreadStatus\\x12\\x15\\n\\rscan_finished\\x18\\x01 \\x01(\\x08\\x12\\x14\\n\\x0cresult_count\\x18\\x02 \\x01(\\r\\\"7\\n\\x11\\x43mdScanWifiResult\\x12\\x13\\n\\x0bstart_index\\x18\\x01 \\x01(\\r\\x12\\r\\n\\x05\\x63ount\\x18\\x02 \\x01(\\r\\\"9\\n\\x13\\x43mdScanThreadResult\\x12\\x13\\n\\x0bstart_index\\x18\\x01 \\x01(\\r\\x12\\r\\n\\x05\\x63ount\\x18\\x02 \\x01(\\r\\\"i\\n\\x0eWiFiScanResult\\x12\\x0c\\n\\x04ssid\\x18\\x01 \\x01(\\x0c\\x12\\x0f\\n\\x07\\x63hannel\\x18\\x02 \\x01(\\r\\x12\\x0c\\n\\x04rssi\\x18\\x03 \\x01(\\x05\\x12\\r\\n\\x05\\x62ssid\\x18\\x04 \\x01(\\x0c\\x12\\x1b\\n\\x04\\x61uth\\x18\\x05 \\x01(\\x0e\\x32\\r.WifiAuthMode\\\"\\x8a\\x01\\n\\x10ThreadScanResult\\x12\\x0e\\n\\x06pan_id\\x18\\x01 \\x01(\\r\\x12\\x0f\\n\\x07\\x63hannel\\x18\\x02 \\x01(\\r\\x12\\x0c\\n\\x04rssi\\x18\\x03 \\x01(\\x05\\x12\\x0b\\n\\x03lqi\\x18\\x04 \\x01(\\r\\x12\\x10\\n\\x08\\x65xt_addr\\x18\\x05 \\x01(\\x0c\\x12\\x14\\n\\x0cnetwork_name\\x18\\x06 \\x01(\\t\\x12\\x12\\n\\next_pan_id\\x18\\x07 \\x01(\\x0c\\\"6\\n\\x12RespScanWifiResult\\x12 \\n\\x07\\x65ntries\\x18\\x01 \\x03(\\x0b\\x32\\x0f.WiFiScanResult\\\":\\n\\x14RespScanThreadResult\\x12\\\"\\n\\x07\\x65ntries\\x18\\x01 \\x03(\\x0b\\x32\\x11.ThreadScanResult\\\"\\xe6\\x05\\n\\x12NetworkScanPayload\\x12 \\n\\x03msg\\x18\\x01 \\x01(\\x0e\\x32\\x13.NetworkScanMsgType\\x12\\x17\\n\\x06status\\x18\\x02 \\x01(\\x0e\\x32\\x07.Status\\x12\\x30\\n\\x13\\x63md_scan_wifi_start\\x18\\n \\x01(\\x0b\\x32\\x11.CmdScanWifiStartH\\x00\\x12\\x32\\n\\x14resp_scan_wifi_start\\x18\\x0b \\x01(\\x0b\\x32\\x12.RespScanWifiStartH\\x00\\x12\\x32\\n\\x14\\x63md_scan_wifi_status\\x18\\x0c \\x01(\\x0b\\x32\\x12.CmdScanWifiStatusH\\x00\\x12\\x34\\n\\x15resp_scan_wifi_status\\x18\\r \\x01(\\x0b\\x32\\x13.RespScanWifiStatusH\\x00\\x12\\x32\\n\\x14\\x63md_scan_wifi_result\\x18\\x0e \\x01(\\x0b\\x32\\x12.CmdScanWifiResultH\\x00\\x12\\x34\\n\\x15resp_scan_wifi_result\\x18\\x0f \\x01(\\x0b\\x32\\x13.RespScanWifiResultH\\x00\\x12\\x34\\n\\x15\\x63md_scan_thread_start\\x18\\x10 \\x01(\\x0b\\x32\\x13.CmdScanThreadStartH\\x00\\x12\\x36\\n\\x16resp_scan_thread_start\\x18\\x11 \\x01(\\x0b\\x32\\x14.RespScanThreadStartH\\x00\\x12\\x36\\n\\x16\\x63md_scan_thread_status\\x18\\x12 \\x01(\\x0b\\x32\\x14.CmdScanThreadStatusH\\x00\\x12\\x38\\n\\x17resp_scan_thread_status\\x18\\x13 \\x01(\\x0b\\x32\\x15.RespScanThreadStatusH\\x00\\x12\\x36\\n\\x16\\x63md_scan_thread_result\\x18\\x14 \\x01(\\x0b\\x32\\x14.CmdScanThreadResultH\\x00\\x12\\x38\\n\\x17resp_scan_thread_result\\x18\\x15 \\x01(\\x0b\\x32\\x15.RespScanThreadResultH\\x00\\x42\\t\\n\\x07payload*\\xe6\\x02\\n\\x12NetworkScanMsgType\\x12\\x18\\n\\x14TypeCmdScanWifiStart\\x10\\x00\\x12\\x19\\n\\x15TypeRespScanWifiStart\\x10\\x01\\x12\\x19\\n\\x15TypeCmdScanWifiStatus\\x10\\x02\\x12\\x1a\\n\\x16TypeRespScanWifiStatus\\x10\\x03\\x12\\x19\\n\\x15TypeCmdScanWifiResult\\x10\\x04\\x12\\x1a\\n\\x16TypeRespScanWifiResult\\x10\\x05\\x12\\x1a\\n\\x16TypeCmdScanThreadStart\\x10\\x06\\x12\\x1b\\n\\x17TypeRespScanThreadStart\\x10\\x07\\x12\\x1b\\n\\x17TypeCmdScanThreadStatus\\x10\\x08\\x12\\x1c\\n\\x18TypeRespScanThreadStatus\\x10\\t\\x12\\x1b\\n\\x17TypeCmdScanThreadResult\\x10\\n\\x12\\x1c\\n\\x18TypeRespScanThreadResult\\x10\\x0b\\x62\\x06proto3')\n\n_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())\n_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'network_scan_pb2', globals())\nif _descriptor._USE_C_DESCRIPTORS == False:\n\n  DESCRIPTOR._options = None\n  _NETWORKSCANMSGTYPE._serialized_start=1674\n  _NETWORKSCANMSGTYPE._serialized_end=2032\n  _CMDSCANWIFISTART._serialized_start=64\n  _CMDSCANWIFISTART._serialized_end=160\n  _CMDSCANTHREADSTART._serialized_start=162\n  _CMDSCANTHREADSTART._serialized_end=222\n  _RESPSCANWIFISTART._serialized_start=224\n  _RESPSCANWIFISTART._serialized_end=243\n  _RESPSCANTHREADSTART._serialized_start=245\n  _RESPSCANTHREADSTART._serialized_end=266\n  _CMDSCANWIFISTATUS._serialized_start=268\n  _CMDSCANWIFISTATUS._serialized_end=287\n  _CMDSCANTHREADSTATUS._serialized_start=289\n  _CMDSCANTHREADSTATUS._serialized_end=310\n  _RESPSCANWIFISTATUS._serialized_start=312\n  _RESPSCANWIFISTATUS._serialized_end=377\n  _RESPSCANTHREADSTATUS._serialized_start=379\n  _RESPSCANTHREADSTATUS._serialized_end=446\n  _CMDSCANWIFIRESULT._serialized_start=448\n  _CMDSCANWIFIRESULT._serialized_end=503\n  _CMDSCANTHREADRESULT._serialized_start=505\n  _CMDSCANTHREADRESULT._serialized_end=562\n  _WIFISCANRESULT._serialized_start=564\n  _WIFISCANRESULT._serialized_end=669\n  _THREADSCANRESULT._serialized_start=672\n  _THREADSCANRESULT._serialized_end=810\n  _RESPSCANWIFIRESULT._serialized_start=812\n  _RESPSCANWIFIRESULT._serialized_end=866\n  _RESPSCANTHREADRESULT._serialized_start=868\n  _RESPSCANTHREADRESULT._serialized_end=926\n  _NETWORKSCANPAYLOAD._serialized_start=929\n  _NETWORKSCANPAYLOAD._serialized_end=1671\n# @@protoc_insertion_point(module_scope)\n"
  },
  {
    "path": "network_provisioning/src/handlers.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <esp_err.h>\n#include <esp_log.h>\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n#include <esp_wifi.h>\n#endif\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n#include <esp_openthread.h>\n#endif\n#include <esp_netif.h>\n\n#include \"network_provisioning/network_config.h\"\n#include \"network_provisioning/network_scan.h\"\n#include \"network_ctrl.h\"\n#include \"network_provisioning/manager.h\"\n#include \"network_provisioning_priv.h\"\n\n#if defined(CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI) || defined(CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD)\nstatic const char *TAG = \"network_prov_handlers\";\n\n/* Provide definition of network_prov_ctx_t */\nstruct network_prov_ctx {\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    wifi_config_t wifi_cfg;\n#endif\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    otOperationalDatasetTlvs thread_dataset;\n#endif\n};\n\nstatic void free_network_prov_ctx(network_prov_ctx_t **ctx)\n{\n    free(*ctx);\n    *ctx = NULL;\n}\n#endif\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\nstatic wifi_config_t *get_wifi_config(network_prov_ctx_t **ctx)\n{\n    return (*ctx ? & (*ctx)->wifi_cfg : NULL);\n}\n\nstatic wifi_config_t *new_wifi_config(network_prov_ctx_t **ctx)\n{\n    free(*ctx);\n    (*ctx) = (network_prov_ctx_t *) calloc(1, sizeof(network_prov_ctx_t));\n    return get_wifi_config(ctx);\n}\n\nstatic esp_err_t wifi_get_status_handler(network_prov_config_get_wifi_data_t *resp_data, network_prov_ctx_t **ctx)\n{\n    /* Initialize to zero */\n    memset(resp_data, 0, sizeof(network_prov_config_get_wifi_data_t));\n\n    if (network_prov_mgr_get_wifi_state(&resp_data->wifi_state) != ESP_OK) {\n        ESP_LOGW(TAG, \"Network provisioning manager for Wi-Fi not running\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    if (resp_data->wifi_state == NETWORK_PROV_WIFI_STA_CONNECTED) {\n        ESP_LOGD(TAG, \"Got state : connected\");\n\n        /* IP Addr assigned to STA */\n        esp_netif_ip_info_t ip_info;\n        esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey(\"WIFI_STA_DEF\"), &ip_info);\n        esp_ip4addr_ntoa(&ip_info.ip, resp_data->conn_info.ip_addr, sizeof(resp_data->conn_info.ip_addr));\n\n\n        /* AP information to which STA is connected */\n        wifi_ap_record_t ap_info;\n        esp_wifi_sta_get_ap_info(&ap_info);\n        memcpy(resp_data->conn_info.bssid, (char *)ap_info.bssid, sizeof(ap_info.bssid));\n        memcpy(resp_data->conn_info.ssid,  (char *)ap_info.ssid,  sizeof(ap_info.ssid));\n        resp_data->conn_info.channel   = ap_info.primary;\n        resp_data->conn_info.auth_mode = ap_info.authmode;\n\n        /* Tell manager to stop provisioning service */\n        network_prov_mgr_done();\n    } else if (resp_data->wifi_state == NETWORK_PROV_WIFI_STA_DISCONNECTED) {\n        ESP_LOGD(TAG, \"Got state : disconnected\");\n\n        /* If disconnected, convey reason */\n        network_prov_mgr_get_wifi_disconnect_reason(&resp_data->fail_reason);\n    } else {\n        if (network_prov_mgr_get_wifi_remaining_conn_attempts(&resp_data->connecting_info.attempts_remaining) != ESP_OK) {\n            ESP_LOGW(TAG, \"network provisioning manager not running\");\n            return ESP_ERR_INVALID_STATE;\n        }\n        ESP_LOGD(TAG, \"Got state : connecting\");\n    }\n    return ESP_OK;\n}\n\nstatic esp_err_t wifi_set_config_handler(const network_prov_config_set_wifi_data_t *req_data, network_prov_ctx_t **ctx)\n{\n    wifi_config_t *wifi_cfg = get_wifi_config(ctx);\n    if (wifi_cfg) {\n        free_network_prov_ctx(ctx);\n    }\n\n    wifi_cfg = new_wifi_config(ctx);\n    if (!wifi_cfg) {\n        ESP_LOGE(TAG, \"Unable to allocate Wi-Fi config\");\n        return ESP_ERR_NO_MEM;\n    }\n\n    ESP_LOGD(TAG, \"Wi-Fi Credentials Received\");\n\n    /* Using memcpy allows the max SSID length to be 32 bytes (as per 802.11 standard).\n     * But this doesn't guarantee that the saved SSID will be null terminated, because\n     * wifi_cfg->sta.ssid is also 32 bytes long (without extra 1 byte for null character).\n     * Although, this is not a matter for concern because esp_wifi library reads the SSID\n     * upto 32 bytes in absence of null termination */\n    const size_t ssid_len = strnlen(req_data->ssid, sizeof(wifi_cfg->sta.ssid));\n    /* Ensure SSID less than 32 bytes is null terminated */\n    memset(wifi_cfg->sta.ssid, 0, sizeof(wifi_cfg->sta.ssid));\n    memcpy(wifi_cfg->sta.ssid, req_data->ssid, ssid_len);\n\n    /* Using strlcpy allows both max passphrase length (63 bytes) and ensures null termination\n     * because size of wifi_cfg->sta.password is 64 bytes (1 extra byte for null character) */\n    strlcpy((char *) wifi_cfg->sta.password, req_data->password, sizeof(wifi_cfg->sta.password));\n\n#ifdef CONFIG_NETWORK_PROV_WIFI_STA_ALL_CHANNEL_SCAN\n    wifi_cfg->sta.scan_method = WIFI_ALL_CHANNEL_SCAN;\n#else /* CONFIG_NETWORK_PROV_WIFI_STA_FAST_SCAN */\n    wifi_cfg->sta.scan_method = WIFI_FAST_SCAN;\n#endif\n\n    return ESP_OK;\n}\n\nstatic esp_err_t wifi_apply_config_handler(network_prov_ctx_t **ctx)\n{\n    wifi_config_t *wifi_cfg = get_wifi_config(ctx);\n    if (!wifi_cfg) {\n        ESP_LOGE(TAG, \"Wi-Fi config not set\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    esp_err_t ret = network_prov_mgr_configure_wifi_sta(wifi_cfg);\n    if (ret == ESP_OK) {\n        ESP_LOGD(TAG, \"Wi-Fi Credentials Applied\");\n    } else {\n        ESP_LOGE(TAG, \"Failed to apply Wi-Fi Credentials\");\n    }\n\n    free_network_prov_ctx(ctx);\n    return ret;\n}\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\nstatic otOperationalDatasetTlvs *get_thread_dataset(network_prov_ctx_t **ctx)\n{\n    return (*ctx ? & (*ctx)->thread_dataset : NULL);\n}\n\nstatic otOperationalDatasetTlvs *new_thread_dataset(network_prov_ctx_t **ctx)\n{\n    free(*ctx);\n    (*ctx) = (network_prov_ctx_t *) calloc(1, sizeof(network_prov_ctx_t));\n    return get_thread_dataset(ctx);\n}\n\nstatic esp_err_t thread_get_status_handler(network_prov_config_get_thread_data_t *resp_data, network_prov_ctx_t **ctx)\n{\n    /* Initialize to zero */\n    memset(resp_data, 0, sizeof(network_prov_config_get_thread_data_t));\n\n    if (network_prov_mgr_get_thread_state(&resp_data->thread_state) != ESP_OK) {\n        ESP_LOGW(TAG, \"Network provisioning manager not running\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    if (resp_data->thread_state == NETWORK_PROV_THREAD_ATTACHED) {\n        ESP_LOGD(TAG, \"Got state : attached\");\n        otOperationalDataset dataset;\n        if (otDatasetGetActive(esp_openthread_get_instance(), &dataset) != OT_ERROR_NONE) {\n            ESP_LOGE(TAG, \"Failed to get Thread dataset\");\n            return ESP_FAIL;\n        }\n        resp_data->conn_info.channel = dataset.mChannel;\n        memcpy(resp_data->conn_info.ext_pan_id, dataset.mExtendedPanId.m8, sizeof(dataset.mExtendedPanId.m8));\n        strncpy(resp_data->conn_info.name, dataset.mNetworkName.m8,\n                strnlen(dataset.mNetworkName.m8, sizeof(dataset.mNetworkName.m8)));\n        resp_data->conn_info.pan_id = dataset.mPanId;\n        /* Tell manager to stop provisioning service */\n        network_prov_mgr_done();\n    } else if (resp_data->thread_state == NETWORK_PROV_THREAD_DETACHED) {\n        ESP_LOGD(TAG, \"Got state : disconnected\");\n\n        /* If disconnected, convey reason */\n        network_prov_mgr_get_thread_detached_reason(&resp_data->fail_reason);\n    } else {\n        ESP_LOGD(TAG, \"Got state : attaching\");\n    }\n    return ESP_OK;\n}\n\nstatic esp_err_t thread_set_config_handler(const network_prov_config_set_thread_data_t *req_data, network_prov_ctx_t **ctx)\n{\n    otOperationalDatasetTlvs *thread_dataset = get_thread_dataset(ctx);\n    if (thread_dataset) {\n        free_network_prov_ctx(ctx);\n    }\n\n    thread_dataset = new_thread_dataset(ctx);\n    if (!thread_dataset) {\n        ESP_LOGE(TAG, \"Unable to allocate Thread dataset\");\n        return ESP_ERR_NO_MEM;\n    }\n\n    ESP_LOGD(TAG, \"Thread Dataset Received\");\n\n    thread_dataset->mLength = req_data->length;\n    memcpy(thread_dataset->mTlvs, req_data->dataset, thread_dataset->mLength);\n\n    return ESP_OK;\n}\n\nstatic esp_err_t thread_apply_config_handler(network_prov_ctx_t **ctx)\n{\n    otOperationalDatasetTlvs *thread_dataset = get_thread_dataset(ctx);\n    if (!thread_dataset) {\n        ESP_LOGE(TAG, \"Thread Dataset not set\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    esp_err_t ret = network_prov_mgr_configure_thread_dataset(thread_dataset);\n    if (ret == ESP_OK) {\n        ESP_LOGD(TAG, \"Thread Dataset Applied\");\n    } else {\n        ESP_LOGE(TAG, \"Failed to apply Thread Dataset\");\n    }\n\n    free_network_prov_ctx(ctx);\n    return ret;\n}\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n\n\nesp_err_t get_network_prov_handlers(network_prov_config_handlers_t *ptr)\n{\n    if (!ptr) {\n        return ESP_ERR_INVALID_ARG;\n    }\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    ptr->wifi_get_status_handler   = wifi_get_status_handler;\n    ptr->wifi_set_config_handler   = wifi_set_config_handler;\n    ptr->wifi_apply_config_handler = wifi_apply_config_handler;\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    ptr->thread_get_status_handler = thread_get_status_handler;\n    ptr->thread_set_config_handler = thread_set_config_handler;\n    ptr->thread_apply_config_handler = thread_apply_config_handler;\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    ptr->ctx = NULL;\n    return ESP_OK;\n}\n\n/*************************************************************************/\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\nstatic esp_err_t wifi_scan_start(bool blocking, bool passive,\n                                 uint8_t group_channels, uint32_t period_ms,\n                                 network_prov_scan_ctx_t **ctx)\n{\n    return network_prov_mgr_wifi_scan_start(blocking, passive, group_channels, period_ms);\n}\n\nstatic esp_err_t wifi_scan_status(bool *scan_finished,\n                                  uint16_t *result_count,\n                                  network_prov_scan_ctx_t **ctx)\n{\n    *scan_finished = network_prov_mgr_wifi_scan_finished();\n    *result_count  = network_prov_mgr_wifi_scan_result_count();\n    return ESP_OK;\n}\n\nstatic esp_err_t wifi_scan_result(uint16_t result_index,\n                                  network_prov_scan_wifi_result_t *result,\n                                  network_prov_scan_ctx_t **ctx)\n{\n    const wifi_ap_record_t *record = network_prov_mgr_wifi_scan_result(result_index);\n    if (!record) {\n        return ESP_FAIL;\n    }\n\n    /* Compile time check ensures memory safety in case SSID length in\n     * record / result structure definition changes in future */\n    _Static_assert(sizeof(result->ssid) == sizeof(record->ssid),\n                   \"source and destination should be of same size\");\n    memcpy(result->ssid, record->ssid, sizeof(record->ssid));\n    memcpy(result->bssid, record->bssid, sizeof(record->bssid));\n    result->channel = record->primary;\n    result->rssi = record->rssi;\n    result->auth = record->authmode;\n    return ESP_OK;\n}\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\nstatic esp_err_t thread_scan_start(bool blocking, uint32_t channel_mask, network_prov_scan_ctx_t **ctx)\n{\n    return network_prov_mgr_thread_scan_start(blocking, channel_mask);\n}\n\nstatic esp_err_t thread_scan_status(bool *scan_finished,\n                                    uint16_t *result_count,\n                                    network_prov_scan_ctx_t **ctx)\n{\n    *scan_finished = network_prov_mgr_thread_scan_finished();\n    *result_count  = network_prov_mgr_thread_scan_result_count();\n    return ESP_OK;\n}\n\nstatic esp_err_t thread_scan_result(uint16_t result_index,\n                                    network_prov_scan_thread_result_t *result,\n                                    network_prov_scan_ctx_t **ctx)\n{\n    const otActiveScanResult *record = network_prov_mgr_thread_scan_result(result_index);\n    if (!record) {\n        return ESP_FAIL;\n    }\n\n    result->channel = record->mChannel;\n    result->pan_id = record->mPanId;\n    result->rssi = record->mRssi;\n    result->lqi = record->mLqi;\n    memcpy(result->ext_addr, record->mExtAddress.m8, sizeof(record->mExtAddress.m8));\n\n    if (record->mDiscover) {\n        memcpy(result->ext_pan_id, record->mExtendedPanId.m8, sizeof(result->ext_pan_id));\n        memcpy(result->network_name, record->mNetworkName.m8, sizeof(record->mNetworkName.m8));\n    } else {\n        memset(result->ext_pan_id, 0, sizeof(result->ext_pan_id));\n        memset(result->network_name, 0, sizeof(result->network_name));\n    }\n\n    return ESP_OK;\n}\n\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n\nesp_err_t get_network_scan_handlers(network_prov_scan_handlers_t *ptr)\n{\n    if (!ptr) {\n        return ESP_ERR_INVALID_ARG;\n    }\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    ptr->wifi_scan_start  = wifi_scan_start;\n    ptr->wifi_scan_status = wifi_scan_status;\n    ptr->wifi_scan_result = wifi_scan_result;\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    ptr->thread_scan_start = thread_scan_start;\n    ptr->thread_scan_status = thread_scan_status;\n    ptr->thread_scan_result = thread_scan_result;\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    ptr->ctx = NULL;\n    return ESP_OK;\n}\n\n/*************************************************************************/\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\nstatic esp_err_t wifi_ctrl_reset(void)\n{\n    return network_prov_mgr_reset_wifi_sm_state_on_failure();\n}\n\nstatic esp_err_t wifi_ctrl_reprov(void)\n{\n    return network_prov_mgr_reset_wifi_sm_state_for_reprovision();\n}\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\nstatic esp_err_t thread_ctrl_reset(void)\n{\n    return network_prov_mgr_reset_thread_sm_state_on_failure();\n}\n\nstatic esp_err_t thread_ctrl_reprov(void)\n{\n    return network_prov_mgr_reset_thread_sm_state_for_reprovision();\n}\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n\nesp_err_t get_network_ctrl_handlers(network_ctrl_handlers_t *ptr)\n{\n    if (!ptr) {\n        return ESP_ERR_INVALID_ARG;\n    }\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    ptr->wifi_ctrl_reset  = wifi_ctrl_reset;\n    ptr->wifi_ctrl_reprov  = wifi_ctrl_reprov;\n#endif\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    ptr->thread_ctrl_reset = thread_ctrl_reset;\n    ptr->thread_ctrl_reprov = thread_ctrl_reprov;\n#endif\n    return ESP_OK;\n}\n"
  },
  {
    "path": "network_provisioning/src/manager.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <sdkconfig.h>\n\n#include <string.h>\n#include <sys/param.h>\n\n#include <freertos/FreeRTOS.h>\n#include <freertos/semphr.h>\n#include <freertos/task.h>\n\n#include <cJSON.h>\n\n#include <esp_log.h>\n#include <esp_err.h>\n#include <esp_wifi.h>\n#include <esp_timer.h>\n\n#include <protocomm.h>\n#include <protocomm_security0.h>\n#include <protocomm_security1.h>\n#include <protocomm_security2.h>\n\n#include \"network_provisioning_priv.h\"\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n#include <esp_openthread_lock.h>\n#include <esp_openthread.h>\n#include <openthread/thread.h>\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n\n#define NETWORK_PROV_MGR_VERSION      \"netprov-v1.2\"\n#define WIFI_PROV_STORAGE_BIT       BIT0\n#define WIFI_PROV_SETTING_BIT       BIT1\n#define MAX_SCAN_RESULTS           CONFIG_NETWORK_PROV_SCAN_MAX_ENTRIES\n\n#define ACQUIRE_LOCK(mux)     assert(xSemaphoreTake(mux, portMAX_DELAY) == pdTRUE)\n#define RELEASE_LOCK(mux)     assert(xSemaphoreGive(mux) == pdTRUE)\n\nstatic const char *TAG = \"network_prov_mgr\";\n\nESP_EVENT_DEFINE_BASE(NETWORK_PROV_EVENT);\nESP_EVENT_DEFINE_BASE(NETWORK_PROV_MGR_PVT_EVENT);\n\ntypedef enum {\n    NETWORK_PROV_STATE_IDLE,\n    NETWORK_PROV_STATE_STARTING,\n    NETWORK_PROV_STATE_STARTED,\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    NETWORK_PROV_STATE_CRED_RECV,\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    NETWORK_PROV_STATE_DATASET_RECV,\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    NETWORK_PROV_STATE_FAIL,\n    NETWORK_PROV_STATE_SUCCESS,\n    NETWORK_PROV_STATE_STOPPING\n} network_prov_mgr_state_t;\n\ntypedef enum {\n    NETWORK_PROV_MGR_STOP,\n} network_prov_mgr_pvt_event_t;\n\n/**\n * @brief  Structure for storing capabilities supported by\n *         the provisioning service\n */\nstruct network_prov_capabilities {\n    /* Security 0 is used */\n    bool no_sec;\n\n    /* Proof of Possession is not required for establishing session */\n    bool no_pop;\n\n    /* Provisioning doesn't stop on it's own after receiving Wi-Fi credentials or\n     * Thread dataset instead application has to explicitly call\n     * network_prov_mgr_stop_provisioning() */\n    bool no_auto_stop;\n};\n\n/**\n * @brief  Structure for storing miscellaneous information about\n *         provisioning service that will be conveyed to clients\n */\nstruct network_prov_info {\n    const char *version;\n    struct network_prov_capabilities capabilities;\n};\n\n/**\n * @brief  Context data for provisioning manager\n */\nstruct network_prov_mgr_ctx {\n    /* Provisioning manager configuration */\n    network_prov_mgr_config_t mgr_config;\n\n    /* State of the provisioning service */\n    network_prov_mgr_state_t prov_state;\n\n    /* Provisioning scheme configuration */\n    void *prov_scheme_config;\n\n    /* Protocomm handle */\n    protocomm_t *pc;\n\n    /* Type of security to use with protocomm */\n    int security;\n\n    /* Pointer to security params */\n    const void *protocomm_sec_params;\n\n    /* Handle for Provisioning Auto Stop timer */\n    esp_timer_handle_t autostop_timer;\n\n    /* Handle for delayed cleanup timer */\n    esp_timer_handle_t cleanup_delay_timer;\n\n    /* Protocomm handlers for network configuration endpoint */\n    network_prov_config_handlers_t *network_prov_handlers;\n\n    /* Protocomm handlers for network scan endpoint */\n    network_prov_scan_handlers_t *network_scan_handlers;\n\n    /* Protocomm handlers for network ctrl endpoint */\n    network_ctrl_handlers_t *network_ctrl_handlers;\n\n    /* Count of used endpoint UUIDs */\n    unsigned int endpoint_uuid_used;\n\n    /* Provisioning service information */\n    struct network_prov_info mgr_info;\n\n    /* Application related information in JSON format */\n    cJSON *app_info_json;\n\n    /* Delay after which resources will be cleaned up asynchronously\n     * upon execution of network_prov_mgr_stop_provisioning() */\n    uint32_t cleanup_delay;\n    /* Scan status */\n    bool scanning;\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    /* Handle for delayed wifi connection timer */\n    esp_timer_handle_t wifi_connect_timer;\n\n    /* State of Wi-Fi Station */\n    network_prov_wifi_sta_state_t wifi_state;\n\n    /* Code for Wi-Fi station disconnection (if disconnected) */\n    network_prov_wifi_sta_fail_reason_t wifi_disconnect_reason;\n\n    /* Wi-Fi scan parameters and state variables */\n    uint8_t channels_per_group;\n    uint16_t curr_channel;\n    uint16_t ap_list_len[14];   // 14 entries corresponding to each channel\n    wifi_ap_record_t *ap_list[14];\n    wifi_ap_record_t *ap_list_sorted[MAX_SCAN_RESULTS];\n    wifi_scan_config_t scan_cfg;\n\n    /* Total number of attempts done for connecting to Wi-Fi */\n    uint32_t connection_attempts_completed;\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    /* Handle for Thread attaching timeout timer */\n    esp_timer_handle_t thread_timeout_timer;\n\n    /* State of Thread */\n    network_prov_thread_state_t thread_state;\n\n    /* Code for Thread detached (if detached) */\n    network_prov_thread_fail_reason_t thread_detached_reason;\n\n    /* Thread scan parameters and state variables */\n    uint16_t scan_result_count;\n    otActiveScanResult *scan_result[MAX_SCAN_RESULTS];\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n};\n\n/* Mutex to lock/unlock access to provisioning singleton\n * context data. This is allocated only once on first init\n * and never deleted as network_prov_mgr is a singleton */\nstatic SemaphoreHandle_t prov_ctx_lock = NULL;\n\n/* Pointer to provisioning context data */\nstatic struct network_prov_mgr_ctx *prov_ctx;\n\n/* This executes registered app_event_callback for a particular event\n *\n * NOTE : By the time this function returns, it is possible that\n * the manager got de-initialized due to a call to network_prov_mgr_deinit()\n * either inside the event callbacks or from another thread. Therefore\n * post execution of execute_event_cb(), the validity of prov_ctx must\n * always be checked. A cleaner way, to avoid this pitfall safely, would\n * be to limit the usage of this function to only public APIs, and that\n * too at the very end, just before returning.\n *\n * NOTE: This function should be called only after ensuring that the\n * context is valid and the control mutex is locked. */\nstatic void execute_event_cb(network_prov_cb_event_t event_id, void *event_data, size_t event_data_size)\n{\n    ESP_LOGD(TAG, \"execute_event_cb : %d\", event_id);\n\n    if (prov_ctx) {\n        network_prov_cb_func_t app_cb = prov_ctx->mgr_config.app_event_handler.event_cb;\n        void *app_data = prov_ctx->mgr_config.app_event_handler.user_data;\n\n        network_prov_cb_func_t scheme_cb = prov_ctx->mgr_config.scheme_event_handler.event_cb;\n        void *scheme_data = prov_ctx->mgr_config.scheme_event_handler.user_data;\n\n        /* Release the mutex before executing the callbacks. This is done so that\n         * network_prov_mgr_event_handler() doesn't stay blocked for the duration */\n        RELEASE_LOCK(prov_ctx_lock);\n\n        if (scheme_cb) {\n            /* Call scheme specific event handler */\n            scheme_cb(scheme_data, event_id, event_data);\n        }\n\n        if (app_cb) {\n            /* Call application specific event handler */\n            app_cb(app_data, event_id, event_data);\n        }\n\n        if (esp_event_post(NETWORK_PROV_EVENT, event_id,\n                           event_data, event_data_size,\n                           portMAX_DELAY) != ESP_OK) {\n            ESP_LOGE(TAG, \"Failed to post event %d to default event loop\", event_id);\n        }\n\n        ACQUIRE_LOCK(prov_ctx_lock);\n    }\n}\n\nesp_err_t network_prov_mgr_set_app_info(const char *label, const char *version,\n                                        const char **capabilities, size_t total_capabilities)\n{\n    if (!label || !version || !capabilities) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    esp_err_t ret = ESP_FAIL;\n    ACQUIRE_LOCK(prov_ctx_lock);\n\n    if (prov_ctx && prov_ctx->prov_state == NETWORK_PROV_STATE_IDLE) {\n        if (!prov_ctx->app_info_json) {\n            prov_ctx->app_info_json = cJSON_CreateObject();\n        }\n\n        cJSON *new_entry_json = cJSON_CreateObject();\n        cJSON *capabilities_json = cJSON_CreateArray();\n        cJSON_AddItemToObject(prov_ctx->app_info_json, label, new_entry_json);\n\n        /* Version (\"ver\") */\n        cJSON_AddStringToObject(new_entry_json, \"ver\", version);\n\n        /* List of capabilities (\"cap\") */\n        cJSON_AddItemToObject(new_entry_json, \"cap\", capabilities_json);\n        for (unsigned int i = 0; i < total_capabilities; i++) {\n            if (capabilities[i]) {\n                cJSON_AddItemToArray(capabilities_json, cJSON_CreateString(capabilities[i]));\n            }\n        }\n        ret = ESP_OK;\n    } else {\n        ret = ESP_ERR_INVALID_STATE;\n    }\n\n    RELEASE_LOCK(prov_ctx_lock);\n    return ret;\n}\n\nstatic cJSON *network_prov_get_info_json(void)\n{\n    cJSON *full_info_json = prov_ctx->app_info_json ?\n                            cJSON_Duplicate(prov_ctx->app_info_json, 1) : cJSON_CreateObject();\n    cJSON *prov_info_json = cJSON_CreateObject();\n    cJSON *prov_capabilities = cJSON_CreateArray();\n\n    /* Use label \"prov\" to indicate provisioning related information */\n    cJSON_AddItemToObject(full_info_json, \"prov\", prov_info_json);\n\n    /* Version field */\n    cJSON_AddStringToObject(prov_info_json, \"ver\", prov_ctx->mgr_info.version);\n\n    /* Security field */\n    cJSON_AddNumberToObject(prov_info_json, \"sec_ver\", prov_ctx->security);\n#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_PATCH_VERSION\n    int sec_ver = 0;\n    uint8_t sec_patch_ver = 0;\n    protocomm_get_sec_version(prov_ctx->pc, &sec_ver, &sec_patch_ver);\n    assert(sec_ver == prov_ctx->security);\n    cJSON_AddNumberToObject(prov_info_json, \"sec_patch_ver\", sec_patch_ver);\n#endif\n\n    /* Capabilities field */\n    cJSON_AddItemToObject(prov_info_json, \"cap\", prov_capabilities);\n\n    /* If Security / Proof of Possession is not used, indicate in capabilities */\n    if (prov_ctx->mgr_info.capabilities.no_sec) {\n        cJSON_AddItemToArray(prov_capabilities, cJSON_CreateString(\"no_sec\"));\n    } else if (prov_ctx->mgr_info.capabilities.no_pop) {\n        cJSON_AddItemToArray(prov_capabilities, cJSON_CreateString(\"no_pop\"));\n    }\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    /* Indicate capability for performing Wi-Fi provision */\n    cJSON_AddItemToArray(prov_capabilities, cJSON_CreateString(\"wifi_prov\"));\n    /* Indicate capability for performing Wi-Fi scan */\n    cJSON_AddItemToArray(prov_capabilities, cJSON_CreateString(\"wifi_scan\"));\n#endif\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    /* Indicate capability for performing Thread provision */\n    cJSON_AddItemToArray(prov_capabilities, cJSON_CreateString(\"thread_prov\"));\n    /* Indicate capability for performing Thread scan */\n    cJSON_AddItemToArray(prov_capabilities, cJSON_CreateString(\"thread_scan\"));\n#endif\n    return full_info_json;\n}\n\n/* Declare the internal event handler */\nstatic void network_prov_mgr_event_handler_internal(void *arg, esp_event_base_t event_base,\n        int32_t event_id, void *event_data);\n\nstatic esp_err_t network_prov_mgr_start_service(const char *service_name, const char *service_key)\n{\n    const network_prov_scheme_t *scheme = &prov_ctx->mgr_config.scheme;\n    esp_err_t ret;\n\n    /* Create new protocomm instance */\n    prov_ctx->pc = protocomm_new();\n    if (prov_ctx->pc == NULL) {\n        ESP_LOGE(TAG, \"Failed to create new protocomm instance\");\n        return ESP_FAIL;\n    }\n\n    ret = scheme->set_config_service(prov_ctx->prov_scheme_config, service_name, service_key);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to configure service\");\n        protocomm_delete(prov_ctx->pc);\n        return ret;\n    }\n\n    /* Start provisioning */\n    ret = scheme->prov_start(prov_ctx->pc, prov_ctx->prov_scheme_config);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to start service\");\n        protocomm_delete(prov_ctx->pc);\n        return ret;\n    }\n\n    /* Set protocomm security type for endpoint */\n    if (prov_ctx->security == 0) {\n#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0\n        ret = protocomm_set_security(prov_ctx->pc, \"prov-session\",\n                                     &protocomm_security0, NULL);\n#else\n        // Enable SECURITY_VERSION_0 in Protocomm configuration menu\n        return ESP_ERR_NOT_SUPPORTED;\n#endif\n    } else if (prov_ctx->security == 1) {\n#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1\n        ret = protocomm_set_security(prov_ctx->pc, \"prov-session\",\n                                     &protocomm_security1, prov_ctx->protocomm_sec_params);\n#else\n        // Enable SECURITY_VERSION_1 in Protocomm configuration menu\n        return ESP_ERR_NOT_SUPPORTED;\n#endif\n    } else if (prov_ctx->security == 2) {\n#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2\n        ret = protocomm_set_security(prov_ctx->pc, \"prov-session\",\n                                     &protocomm_security2, prov_ctx->protocomm_sec_params);\n#else\n        // Enable SECURITY_VERSION_2 in Protocomm configuration menu\n        return ESP_ERR_NOT_SUPPORTED;\n#endif\n    } else {\n        ESP_LOGE(TAG, \"Unsupported protocomm security version %d\", prov_ctx->security);\n        ret = ESP_ERR_INVALID_ARG;\n    }\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to set security endpoint\");\n        scheme->prov_stop(prov_ctx->pc);\n        protocomm_delete(prov_ctx->pc);\n        return ret;\n    }\n\n    /* Set version information / capabilities of provisioning service and application */\n    cJSON *version_json = network_prov_get_info_json();\n    char *version_str = cJSON_Print(version_json);\n    ret = protocomm_set_version(prov_ctx->pc, \"proto-ver\", version_str);\n    free(version_str);\n    cJSON_Delete(version_json);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to set version endpoint\");\n        scheme->prov_stop(prov_ctx->pc);\n        protocomm_delete(prov_ctx->pc);\n        return ret;\n    }\n\n    prov_ctx->network_prov_handlers = malloc(sizeof(network_prov_config_handlers_t));\n    ret = get_network_prov_handlers(prov_ctx->network_prov_handlers);\n    if (ret != ESP_OK) {\n        ESP_LOGD(TAG, \"Failed to allocate memory for provisioning handlers\");\n        scheme->prov_stop(prov_ctx->pc);\n        protocomm_delete(prov_ctx->pc);\n        return ESP_ERR_NO_MEM;\n    }\n\n    /* Add protocomm endpoint for network configuration */\n    ret = protocomm_add_endpoint(prov_ctx->pc, \"prov-config\",\n                                 network_prov_config_data_handler,\n                                 prov_ctx->network_prov_handlers);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to set provisioning endpoint\");\n        free(prov_ctx->network_prov_handlers);\n        scheme->prov_stop(prov_ctx->pc);\n        protocomm_delete(prov_ctx->pc);\n        return ret;\n    }\n\n    prov_ctx->network_scan_handlers = malloc(sizeof(network_prov_scan_handlers_t));\n    ret = get_network_scan_handlers(prov_ctx->network_scan_handlers);\n    if (ret != ESP_OK) {\n        ESP_LOGD(TAG, \"Failed to allocate memory for network scan handlers\");\n        free(prov_ctx->network_prov_handlers);\n        scheme->prov_stop(prov_ctx->pc);\n        protocomm_delete(prov_ctx->pc);\n        return ESP_ERR_NO_MEM;\n    }\n\n    /* Add endpoint for scanning networks and sending scan list */\n    ret = protocomm_add_endpoint(prov_ctx->pc, \"prov-scan\",\n                                 network_prov_scan_handler,\n                                 prov_ctx->network_scan_handlers);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to set network scan endpoint\");\n        free(prov_ctx->network_scan_handlers);\n        free(prov_ctx->network_prov_handlers);\n        scheme->prov_stop(prov_ctx->pc);\n        protocomm_delete(prov_ctx->pc);\n        return ret;\n    }\n\n    prov_ctx->network_ctrl_handlers = malloc(sizeof(network_ctrl_handlers_t));\n    ret = get_network_ctrl_handlers(prov_ctx->network_ctrl_handlers);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to allocate memory for network ctrl handlers\");\n        free(prov_ctx->network_prov_handlers);\n        scheme->prov_stop(prov_ctx->pc);\n        protocomm_delete(prov_ctx->pc);\n        return ESP_ERR_NO_MEM;\n    }\n\n    /* Add endpoint for controlling state of network provisioning */\n    ret = protocomm_add_endpoint(prov_ctx->pc, \"prov-ctrl\",\n                                 network_ctrl_handler,\n                                 prov_ctx->network_ctrl_handlers);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to set network ctrl endpoint\");\n        free(prov_ctx->network_ctrl_handlers);\n        free(prov_ctx->network_prov_handlers);\n        scheme->prov_stop(prov_ctx->pc);\n        protocomm_delete(prov_ctx->pc);\n        return ret;\n    }\n\n    /* Register global event handler */\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    ret = esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID,\n                                     network_prov_mgr_event_handler_internal, NULL);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to register WiFi event handler\");\n        free(prov_ctx->network_scan_handlers);\n        free(prov_ctx->network_ctrl_handlers);\n        free(prov_ctx->network_prov_handlers);\n        scheme->prov_stop(prov_ctx->pc);\n        protocomm_delete(prov_ctx->pc);\n        return ret;\n    }\n\n    ret = esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP,\n                                     network_prov_mgr_event_handler_internal, NULL);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to register IP event handler\");\n        esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID,\n                                     network_prov_mgr_event_handler_internal);\n        free(prov_ctx->network_scan_handlers);\n        free(prov_ctx->network_ctrl_handlers);\n        free(prov_ctx->network_prov_handlers);\n        scheme->prov_stop(prov_ctx->pc);\n        protocomm_delete(prov_ctx->pc);\n        return ret;\n    }\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    ret = esp_event_handler_register(OPENTHREAD_EVENT, ESP_EVENT_ANY_ID,\n                                     network_prov_mgr_event_handler_internal, NULL);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to register OpenThread event handler\");\n        free(prov_ctx->network_scan_handlers);\n        free(prov_ctx->network_ctrl_handlers);\n        free(prov_ctx->network_prov_handlers);\n        scheme->prov_stop(prov_ctx->pc);\n        protocomm_delete(prov_ctx->pc);\n        return ret;\n    }\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n\n    ret = esp_event_handler_register(NETWORK_PROV_MGR_PVT_EVENT, NETWORK_PROV_MGR_STOP,\n                                     network_prov_mgr_event_handler_internal, NULL);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to register provisioning event handler\");\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID,\n                                     network_prov_mgr_event_handler_internal);\n        esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP,\n                                     network_prov_mgr_event_handler_internal);\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        esp_event_handler_unregister(OPENTHREAD_EVENT, ESP_EVENT_ANY_ID,\n                                     network_prov_mgr_event_handler_internal);\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        free(prov_ctx->network_scan_handlers);\n        free(prov_ctx->network_ctrl_handlers);\n        free(prov_ctx->network_prov_handlers);\n        scheme->prov_stop(prov_ctx->pc);\n        protocomm_delete(prov_ctx->pc);\n        return ret;\n    }\n\n\n    ESP_LOGI(TAG, \"Provisioning started with service name : %s \",\n             service_name ? service_name : \"<NULL>\");\n    return ESP_OK;\n}\n\nesp_err_t network_prov_mgr_endpoint_create(const char *ep_name)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    esp_err_t err = ESP_FAIL;\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (prov_ctx &&\n            prov_ctx->prov_state == NETWORK_PROV_STATE_IDLE) {\n        err = prov_ctx->mgr_config.scheme.set_config_endpoint(\n                  prov_ctx->prov_scheme_config, ep_name,\n                  prov_ctx->endpoint_uuid_used + 1);\n    }\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to create additional endpoint\");\n    } else {\n        prov_ctx->endpoint_uuid_used++;\n    }\n    RELEASE_LOCK(prov_ctx_lock);\n    return err;\n}\n\nesp_err_t network_prov_mgr_endpoint_register(const char *ep_name, protocomm_req_handler_t handler, void *user_ctx)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    esp_err_t err = ESP_FAIL;\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (prov_ctx &&\n            prov_ctx->prov_state > NETWORK_PROV_STATE_STARTING &&\n            prov_ctx->prov_state < NETWORK_PROV_STATE_STOPPING) {\n        err = protocomm_add_endpoint(prov_ctx->pc, ep_name, handler, user_ctx);\n    }\n    RELEASE_LOCK(prov_ctx_lock);\n\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to register handler for endpoint\");\n    }\n    return err;\n}\n\nvoid network_prov_mgr_endpoint_unregister(const char *ep_name)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (prov_ctx &&\n            prov_ctx->prov_state > NETWORK_PROV_STATE_STARTING &&\n            prov_ctx->prov_state < NETWORK_PROV_STATE_STOPPING) {\n        protocomm_remove_endpoint(prov_ctx->pc, ep_name);\n    }\n    RELEASE_LOCK(prov_ctx_lock);\n}\n\nstatic void prov_stop_and_notify(bool is_async)\n{\n    esp_event_handler_unregister(NETWORK_PROV_MGR_PVT_EVENT, NETWORK_PROV_MGR_STOP,\n                                 network_prov_mgr_event_handler_internal);\n\n    if (prov_ctx->cleanup_delay_timer) {\n        esp_timer_stop(prov_ctx->cleanup_delay_timer);\n        esp_timer_delete(prov_ctx->cleanup_delay_timer);\n        prov_ctx->cleanup_delay_timer = NULL;\n    }\n\n    network_prov_cb_func_t app_cb = prov_ctx->mgr_config.app_event_handler.event_cb;\n    void *app_data = prov_ctx->mgr_config.app_event_handler.user_data;\n\n    network_prov_cb_func_t scheme_cb = prov_ctx->mgr_config.scheme_event_handler.event_cb;\n    void *scheme_data = prov_ctx->mgr_config.scheme_event_handler.user_data;\n\n    /* This delay is so that the client side app is notified first\n     * and then the provisioning is stopped. Generally 1000ms is enough. */\n    if (!is_async) {\n        uint32_t cleanup_delay = prov_ctx->cleanup_delay > 100 ? prov_ctx->cleanup_delay : 100;\n        vTaskDelay(cleanup_delay / portTICK_PERIOD_MS);\n    }\n\n    protocomm_remove_endpoint(prov_ctx->pc, \"prov-ctrl\");\n\n    protocomm_remove_endpoint(prov_ctx->pc, \"prov-scan\");\n\n    protocomm_remove_endpoint(prov_ctx->pc, \"prov-config\");\n\n    protocomm_unset_security(prov_ctx->pc, \"prov-session\");\n\n    protocomm_unset_version(prov_ctx->pc, \"proto-ver\");\n\n    /* All the extra application added endpoints are also\n     * removed automatically when prov_stop is called */\n    prov_ctx->mgr_config.scheme.prov_stop(prov_ctx->pc);\n\n    /* Delete protocomm instance */\n    protocomm_delete(prov_ctx->pc);\n    prov_ctx->pc = NULL;\n\n    /* Free provisioning handlers */\n    free(prov_ctx->network_prov_handlers->ctx);\n    free(prov_ctx->network_prov_handlers);\n    prov_ctx->network_prov_handlers = NULL;\n\n    free(prov_ctx->network_scan_handlers->ctx);\n    free(prov_ctx->network_scan_handlers);\n    prov_ctx->network_scan_handlers = NULL;\n\n    free(prov_ctx->network_ctrl_handlers);\n    prov_ctx->network_ctrl_handlers = NULL;\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    /* Switch device to Wi-Fi STA mode irrespective of\n     * whether provisioning was completed or not */\n    esp_wifi_set_mode(WIFI_MODE_STA);\n#endif\n\n    ESP_LOGI(TAG, \"Provisioning stopped\");\n\n    if (is_async) {\n        /* NOTE: While calling this API in an async fashion,\n         * the context lock prov_ctx_lock has already been taken\n         */\n        prov_ctx->prov_state = NETWORK_PROV_STATE_IDLE;\n\n        ESP_LOGD(TAG, \"execute_event_cb : %d\", NETWORK_PROV_END);\n        if (scheme_cb) {\n            scheme_cb(scheme_data, NETWORK_PROV_END, NULL);\n        }\n        if (app_cb) {\n            app_cb(app_data, NETWORK_PROV_END, NULL);\n        }\n        if (esp_event_post(NETWORK_PROV_EVENT, NETWORK_PROV_END, NULL, 0, portMAX_DELAY) != ESP_OK) {\n            ESP_LOGE(TAG, \"Failed to post event THREAD_PROV_END\");\n        }\n    }\n}\n\n/* This will do one of these:\n * 1) if blocking is false, start a cleanup timer for stopping the provisioning service (returns true)\n * 2) if blocking is true, stop provisioning service immediately (returns true)\n * 3) if service was already in the process of termination, in blocking mode this will\n *    wait till the service is stopped (returns false)\n * 4) if service was not running, this will return immediately (returns false)\n *\n * NOTE: This function should be called only after ensuring that the context\n * is valid and the control mutex is locked\n *\n * NOTE: When blocking mode is selected, the event callbacks are not executed.\n * This help with de-initialization.\n */\nstatic bool network_prov_mgr_stop_service(bool blocking)\n{\n    if (blocking) {\n        /* Wait for any ongoing calls to network_prov_mgr_start_service() or\n         * network_prov_mgr_stop_service() from another thread to finish */\n        while (prov_ctx && (\n                    prov_ctx->prov_state == NETWORK_PROV_STATE_STARTING ||\n                    prov_ctx->prov_state == NETWORK_PROV_STATE_STOPPING)) {\n            RELEASE_LOCK(prov_ctx_lock);\n            vTaskDelay(100 / portTICK_PERIOD_MS);\n            ACQUIRE_LOCK(prov_ctx_lock);\n        }\n    } else {\n        /* Wait for any ongoing call to network_prov_mgr_start_service()\n         * from another thread to finish */\n        while (prov_ctx &&\n                prov_ctx->prov_state == NETWORK_PROV_STATE_STARTING) {\n            RELEASE_LOCK(prov_ctx_lock);\n            vTaskDelay(100 / portTICK_PERIOD_MS);\n            ACQUIRE_LOCK(prov_ctx_lock);\n        }\n\n        if (prov_ctx && prov_ctx->prov_state == NETWORK_PROV_STATE_STOPPING) {\n            ESP_LOGD(TAG, \"Provisioning is already stopping\");\n            return false;\n        }\n    }\n\n    if (!prov_ctx || prov_ctx->prov_state == NETWORK_PROV_STATE_IDLE) {\n        ESP_LOGD(TAG, \"Provisioning not running\");\n        return false;\n    }\n\n    /* Timers not needed anymore */\n    if (prov_ctx->autostop_timer) {\n        esp_timer_stop(prov_ctx->autostop_timer);\n        esp_timer_delete(prov_ctx->autostop_timer);\n        prov_ctx->autostop_timer = NULL;\n    }\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    if (prov_ctx->wifi_connect_timer) {\n        esp_timer_stop(prov_ctx->wifi_connect_timer);\n        esp_timer_delete(prov_ctx->wifi_connect_timer);\n        prov_ctx->wifi_connect_timer = NULL;\n    }\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    if (prov_ctx->thread_timeout_timer) {\n        esp_timer_stop(prov_ctx->thread_timeout_timer);\n        esp_timer_delete(prov_ctx->thread_timeout_timer);\n        prov_ctx->thread_timeout_timer = NULL;\n    }\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n\n    ESP_LOGD(TAG, \"Stopping provisioning\");\n    prov_ctx->prov_state = NETWORK_PROV_STATE_STOPPING;\n\n    /* Free proof of possession */\n    if (prov_ctx->protocomm_sec_params) {\n        if (prov_ctx->security == 1) {\n            // In case of security 1 we keep an internal copy of \"pop\".\n            // Hence free it at this point\n            uint8_t *pop = (uint8_t *)((protocomm_security1_params_t *) prov_ctx->protocomm_sec_params)->data;\n            free(pop);\n        }\n        prov_ctx->protocomm_sec_params = NULL;\n    }\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    /* Delete all scan results */\n    for (uint16_t channel = 0; channel < 14; channel++) {\n        free(prov_ctx->ap_list[channel]);\n        prov_ctx->ap_list[channel] = NULL;\n    }\n    prov_ctx->scanning = false;\n    for (uint8_t i = 0; i < MAX_SCAN_RESULTS; i++) {\n        prov_ctx->ap_list_sorted[i] = NULL;\n    }\n\n    /* Remove event handler */\n    esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID,\n                                 network_prov_mgr_event_handler_internal);\n    esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP,\n                                 network_prov_mgr_event_handler_internal);\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    /* Delete all scan results */\n    prov_ctx->scanning = false;\n    for (uint8_t i = 0; i < MAX_SCAN_RESULTS; ++i) {\n        if (prov_ctx->scan_result[i]) {\n            free(prov_ctx->scan_result[i]);\n        }\n        prov_ctx->scan_result[i] = NULL;\n    }\n    prov_ctx->scan_result_count = 0;\n\n    /* Remove event handler */\n    esp_event_handler_unregister(OPENTHREAD_EVENT, ESP_EVENT_ANY_ID,\n                                 network_prov_mgr_event_handler_internal);\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n\n    if (blocking) {\n        /* Run the cleanup without launching a separate task. Also the\n         * NETWORK_PROV_END event is not emitted in this case */\n        RELEASE_LOCK(prov_ctx_lock);\n        prov_stop_and_notify(false);\n        ACQUIRE_LOCK(prov_ctx_lock);\n        prov_ctx->prov_state = NETWORK_PROV_STATE_IDLE;\n    } else {\n        /* Launch cleanup timer to perform the cleanup asynchronously.\n         * It is important to do this asynchronously because, there are\n         * situations in which the transport level resources have to be\n         * released - some duration after - returning from a call to\n         * network_prov_mgr_stop_provisioning(), like when it is called\n         * inside a protocomm handler */\n        uint64_t cleanup_delay_ms = prov_ctx->cleanup_delay > 100 ? prov_ctx->cleanup_delay : 100;\n        esp_timer_start_once(prov_ctx->cleanup_delay_timer, cleanup_delay_ms * 1000U);\n        ESP_LOGD(TAG, \"Provisioning scheduled for stopping\");\n    }\n    return true;\n}\n\n/* Task spawned by timer callback */\nstatic void stop_prov_timer_cb(void *arg)\n{\n    network_prov_mgr_stop_provisioning();\n}\n\nstatic void cleanup_delay_timer_cb(void *arg)\n{\n    esp_err_t ret = esp_event_post(NETWORK_PROV_MGR_PVT_EVENT, NETWORK_PROV_MGR_STOP, NULL, 0, pdMS_TO_TICKS(100));\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to post NETWORK_PROV_MGR_STOP event! %d %s\", ret, esp_err_to_name(ret));\n    }\n}\n\nesp_err_t network_prov_mgr_disable_auto_stop(uint32_t cleanup_delay)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    esp_err_t ret = ESP_FAIL;\n    ACQUIRE_LOCK(prov_ctx_lock);\n\n    if (prov_ctx && prov_ctx->prov_state == NETWORK_PROV_STATE_IDLE) {\n        prov_ctx->mgr_info.capabilities.no_auto_stop = true;\n        prov_ctx->cleanup_delay = cleanup_delay;\n        ret = ESP_OK;\n    } else {\n        ret = ESP_ERR_INVALID_STATE;\n    }\n\n    RELEASE_LOCK(prov_ctx_lock);\n    return ret;\n}\n\n/* Call this if provisioning is completed before the timeout occurs */\nesp_err_t network_prov_mgr_done(void)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    bool auto_stop_enabled = false;\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (prov_ctx && !prov_ctx->mgr_info.capabilities.no_auto_stop) {\n        auto_stop_enabled = true;\n    }\n    RELEASE_LOCK(prov_ctx_lock);\n\n    /* Stop provisioning if auto stop is enabled */\n    if (auto_stop_enabled) {\n        network_prov_mgr_stop_provisioning();\n    }\n    return ESP_OK;\n}\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\nstatic esp_err_t update_wifi_scan_results(void)\n{\n    if (!prov_ctx->scanning) {\n        return ESP_ERR_INVALID_STATE;\n    }\n    ESP_LOGD(TAG, \"Scan finished\");\n\n    esp_err_t ret = ESP_FAIL;\n    uint16_t count = 0;\n    uint16_t curr_channel = prov_ctx->curr_channel;\n\n    if (prov_ctx->ap_list[curr_channel]) {\n        free(prov_ctx->ap_list[curr_channel]);\n        prov_ctx->ap_list[curr_channel] = NULL;\n        prov_ctx->ap_list_len[curr_channel] = 0;\n    }\n\n    if (esp_wifi_scan_get_ap_num(&count) != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to get count of scanned APs\");\n        goto exit;\n    }\n\n    if (!count) {\n        ESP_LOGD(TAG, \"Scan result empty\");\n        ret = ESP_OK;\n        goto exit;\n    }\n\n    uint16_t get_count = MIN(count, MAX_SCAN_RESULTS);\n    prov_ctx->ap_list[curr_channel] = (wifi_ap_record_t *) calloc(get_count, sizeof(wifi_ap_record_t));\n    if (!prov_ctx->ap_list[curr_channel]) {\n        ESP_LOGE(TAG, \"Failed to allocate memory for AP list\");\n        esp_wifi_clear_ap_list();\n        goto exit;\n    }\n    if (esp_wifi_scan_get_ap_records(&get_count, prov_ctx->ap_list[curr_channel]) != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to get scanned AP records\");\n        goto exit;\n    }\n    prov_ctx->ap_list_len[curr_channel] = get_count;\n\n    if (prov_ctx->channels_per_group) {\n        ESP_LOGD(TAG, \"Scan results for channel %d :\", curr_channel);\n    } else {\n        ESP_LOGD(TAG, \"Scan results :\");\n    }\n    ESP_LOGD(TAG, \"\\tS.N. %-32s %-12s %s %s\", \"SSID\", \"BSSID\", \"RSSI\", \"AUTH\");\n    for (uint8_t i = 0; i < prov_ctx->ap_list_len[curr_channel]; i++) {\n        ESP_LOGD(TAG, \"\\t[%2d] %-32s %02x%02x%02x%02x%02x%02x %4d %4d\", i,\n                 prov_ctx->ap_list[curr_channel][i].ssid,\n                 prov_ctx->ap_list[curr_channel][i].bssid[0],\n                 prov_ctx->ap_list[curr_channel][i].bssid[1],\n                 prov_ctx->ap_list[curr_channel][i].bssid[2],\n                 prov_ctx->ap_list[curr_channel][i].bssid[3],\n                 prov_ctx->ap_list[curr_channel][i].bssid[4],\n                 prov_ctx->ap_list[curr_channel][i].bssid[5],\n                 prov_ctx->ap_list[curr_channel][i].rssi,\n                 prov_ctx->ap_list[curr_channel][i].authmode);\n    }\n\n    /* Store results in sorted list */\n    {\n        int rc = get_count;\n        int is = MAX_SCAN_RESULTS - rc - 1;\n        while (rc > 0 && is >= 0) {\n            if (prov_ctx->ap_list_sorted[is]) {\n                if (prov_ctx->ap_list_sorted[is]->rssi > prov_ctx->ap_list[curr_channel][rc - 1].rssi) {\n                    prov_ctx->ap_list_sorted[is + rc] = &prov_ctx->ap_list[curr_channel][rc - 1];\n                    rc--;\n                    continue;\n                }\n                prov_ctx->ap_list_sorted[is + rc] = prov_ctx->ap_list_sorted[is];\n            }\n            is--;\n        }\n        while (rc > 0) {\n            prov_ctx->ap_list_sorted[rc - 1] = &prov_ctx->ap_list[curr_channel][rc - 1];\n            rc--;\n        }\n    }\n\n    ret = ESP_OK;\nexit:\n\n    if (!prov_ctx->channels_per_group) {\n        /* All channel scan was performed\n         * so nothing more to do */\n        prov_ctx->scanning = false;\n        goto final;\n    }\n\n    curr_channel = prov_ctx->curr_channel = (prov_ctx->curr_channel + 1) % 14;\n    if (ret != ESP_OK || curr_channel == 0) {\n        prov_ctx->scanning = false;\n        goto final;\n    }\n\n    if ((curr_channel % prov_ctx->channels_per_group) == 0) {\n        vTaskDelay(120 / portTICK_PERIOD_MS);\n    }\n\n    ESP_LOGD(TAG, \"Scan starting on channel %u...\", curr_channel);\n    prov_ctx->scan_cfg.channel = curr_channel;\n    ret = esp_wifi_scan_start(&prov_ctx->scan_cfg, false);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to start scan\");\n        prov_ctx->scanning = false;\n        goto final;\n    }\n    ESP_LOGD(TAG, \"Scan started\");\n\nfinal:\n\n    return ret;\n}\n\nesp_err_t network_prov_mgr_wifi_scan_start(bool blocking, bool passive,\n        uint8_t group_channels, uint32_t period_ms)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n    ACQUIRE_LOCK(prov_ctx_lock);\n\n    if (!prov_ctx) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    if (prov_ctx->scanning) {\n        ESP_LOGD(TAG, \"Scan already running\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_OK;\n    }\n\n    /* Clear sorted list for new entries */\n    for (uint8_t i = 0; i < MAX_SCAN_RESULTS; i++) {\n        prov_ctx->ap_list_sorted[i] = NULL;\n    }\n\n    if (passive) {\n        prov_ctx->scan_cfg.scan_type = WIFI_SCAN_TYPE_PASSIVE;\n        /* We do not recommend scan configuration modification in Wi-Fi and BT coexistence mode */\n#if !CONFIG_BT_ENABLED\n        prov_ctx->scan_cfg.scan_time.passive = period_ms;\n#endif\n    } else {\n        prov_ctx->scan_cfg.scan_type = WIFI_SCAN_TYPE_ACTIVE;\n        /* We do not recommend scan configuration modification in Wi-Fi and BT coexistence mode */\n#if !CONFIG_BT_ENABLED\n        prov_ctx->scan_cfg.scan_time.active.min = period_ms;\n        prov_ctx->scan_cfg.scan_time.active.max = period_ms;\n#endif\n    }\n    prov_ctx->channels_per_group = group_channels;\n\n    if (prov_ctx->channels_per_group) {\n        ESP_LOGD(TAG, \"Scan starting on channel 1...\");\n        prov_ctx->scan_cfg.channel = 1;\n    } else {\n        ESP_LOGD(TAG, \"Scan starting...\");\n        prov_ctx->scan_cfg.channel = 0;\n    }\n\n    if (esp_wifi_scan_start(&prov_ctx->scan_cfg, false) != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to start scan\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_FAIL;\n    }\n\n    ESP_LOGD(TAG, \"Scan started\");\n    prov_ctx->scanning = true;\n    prov_ctx->curr_channel = prov_ctx->scan_cfg.channel;\n    RELEASE_LOCK(prov_ctx_lock);\n\n    /* If scan is to be non-blocking, return immediately */\n    if (!blocking) {\n        return ESP_OK;\n    }\n\n    /* Loop till scan is complete */\n    bool scanning = true;\n    while (scanning) {\n        ACQUIRE_LOCK(prov_ctx_lock);\n        scanning = (prov_ctx && prov_ctx->scanning);\n        RELEASE_LOCK(prov_ctx_lock);\n\n        /* 120ms delay is  sufficient for Wi-Fi beacons to be sent */\n        vTaskDelay(120 / portTICK_PERIOD_MS);\n    }\n    return ESP_OK;\n}\n\nbool network_prov_mgr_wifi_scan_finished(void)\n{\n    bool scan_finished = true;\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return scan_finished;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (!prov_ctx) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return scan_finished;\n    }\n\n    scan_finished = !prov_ctx->scanning;\n    RELEASE_LOCK(prov_ctx_lock);\n    return scan_finished;\n}\n\nuint16_t network_prov_mgr_wifi_scan_result_count(void)\n{\n    uint16_t rval = 0;\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return rval;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (!prov_ctx) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return rval;\n    }\n\n    while (rval < MAX_SCAN_RESULTS) {\n        if (!prov_ctx->ap_list_sorted[rval]) {\n            break;\n        }\n        rval++;\n    }\n    RELEASE_LOCK(prov_ctx_lock);\n    return rval;\n}\n\nconst wifi_ap_record_t *network_prov_mgr_wifi_scan_result(uint16_t index)\n{\n    const wifi_ap_record_t *rval = NULL;\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return rval;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (!prov_ctx) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return rval;\n    }\n\n    if (index < MAX_SCAN_RESULTS) {\n        rval = prov_ctx->ap_list_sorted[index];\n    }\n    RELEASE_LOCK(prov_ctx_lock);\n    return rval;\n}\n\nesp_err_t network_prov_mgr_get_wifi_state(network_prov_wifi_sta_state_t *state)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (prov_ctx == NULL || state == NULL) {\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_FAIL;\n    }\n\n    *state = prov_ctx->wifi_state;\n    RELEASE_LOCK(prov_ctx_lock);\n    return ESP_OK;\n}\n\nesp_err_t network_prov_mgr_get_wifi_remaining_conn_attempts(uint32_t *attempts_remaining)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (prov_ctx == NULL || attempts_remaining == NULL) {\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_FAIL;\n    }\n\n    *attempts_remaining =\n        prov_ctx->mgr_config.network_prov_wifi_conn_cfg.wifi_conn_attempts - prov_ctx->connection_attempts_completed;\n    RELEASE_LOCK(prov_ctx_lock);\n    return ESP_OK;\n}\n\nesp_err_t network_prov_mgr_get_wifi_disconnect_reason(network_prov_wifi_sta_fail_reason_t *reason)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (prov_ctx == NULL || reason == NULL) {\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_FAIL;\n    }\n\n    if (prov_ctx->wifi_state != NETWORK_PROV_WIFI_STA_DISCONNECTED) {\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_FAIL;\n    }\n\n    *reason = prov_ctx->wifi_disconnect_reason;\n    RELEASE_LOCK(prov_ctx_lock);\n    return ESP_OK;\n}\n\nstatic void debug_print_wifi_credentials(wifi_sta_config_t sta, const char *pretext)\n{\n    size_t passlen = strlen((const char *) sta.password);\n    ESP_LOGD(TAG, \"%s Wi-Fi SSID     : %.*s\", pretext,\n             strnlen((const char *) sta.ssid, sizeof(sta.ssid)), (const char *) sta.ssid);\n\n    if (passlen) {\n        /* Mask password partially if longer than 3, else mask it completely */\n        memset(sta.password + (passlen > 3), '*', passlen - 2 * (passlen > 3));\n        ESP_LOGD(TAG, \"%s Wi-Fi Password : %s\", pretext, (const char *) sta.password);\n    }\n}\n\nesp_err_t network_prov_mgr_is_wifi_provisioned(bool *provisioned)\n{\n    if (!provisioned) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    *provisioned = false;\n\n    /* Get Wi-Fi Station configuration */\n    wifi_config_t wifi_cfg;\n    if (esp_wifi_get_config(WIFI_IF_STA, &wifi_cfg) != ESP_OK) {\n        return ESP_FAIL;\n    }\n\n    if (strlen((const char *) wifi_cfg.sta.ssid)) {\n        *provisioned = true;\n        debug_print_wifi_credentials(wifi_cfg.sta, \"Found\");\n    }\n    return ESP_OK;\n}\n\nbool network_prov_mgr_is_sm_idle(void)\n{\n    return (prov_ctx->prov_state == NETWORK_PROV_STATE_IDLE);\n}\n\nstatic void wifi_connect_timer_cb(void *arg)\n{\n    if (esp_wifi_connect() != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to connect Wi-Fi\");\n    }\n}\n\nesp_err_t network_prov_mgr_configure_wifi_sta(wifi_config_t *wifi_cfg)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (!prov_ctx) {\n        ESP_LOGE(TAG, \"Invalid state of Provisioning app\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_FAIL;\n    }\n\n    execute_event_cb(NETWORK_PROV_SET_WIFI_STA_CONFIG, (void *)wifi_cfg, sizeof(wifi_config_t));\n\n    if (prov_ctx->prov_state >= NETWORK_PROV_STATE_CRED_RECV) {\n        ESP_LOGE(TAG, \"Wi-Fi credentials already received by provisioning app\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_FAIL;\n    }\n    debug_print_wifi_credentials(wifi_cfg->sta, \"Received\");\n\n    /* Configure Wi-Fi as both AP and/or Station */\n    if (esp_wifi_set_mode(prov_ctx->mgr_config.scheme.wifi_mode) != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to set Wi-Fi mode\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_FAIL;\n    }\n\n    /* Don't release mutex yet as it is possible that right after\n     * esp_wifi_connect()  is called below, the related Wi-Fi event\n     * happens even before manager state is updated in the next\n     * few lines causing the internal event handler to miss */\n\n    /* Set Wi-Fi storage again to flash to keep the newly\n     * provided credentials on NVS */\n    if (esp_wifi_set_storage(WIFI_STORAGE_FLASH) != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to set storage Wi-Fi\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_FAIL;\n    }\n    /* Configure Wi-Fi station with host credentials\n     * provided during provisioning */\n    if (esp_wifi_set_config(WIFI_IF_STA, wifi_cfg) != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to set Wi-Fi configuration\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_FAIL;\n    }\n    /* Connect to AP after one second so that the response can\n     * be sent to the client successfully, before a channel change happens*/\n    if (esp_timer_start_once(prov_ctx->wifi_connect_timer, 1000 * 1000U) != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to start Wi-Fi connect timer\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_FAIL;\n    }\n\n    /* Reset Wi-Fi station state for provisioning app */\n    prov_ctx->wifi_state = NETWORK_PROV_WIFI_STA_CONNECTING;\n    /* Reset connection attempts counter for new credentials */\n    prov_ctx->connection_attempts_completed = 0;\n    prov_ctx->prov_state = NETWORK_PROV_STATE_CRED_RECV;\n    /* Execute user registered callback handler */\n    execute_event_cb(NETWORK_PROV_WIFI_CRED_RECV, (void *)&wifi_cfg->sta, sizeof(wifi_cfg->sta));\n    RELEASE_LOCK(prov_ctx_lock);\n\n    return ESP_OK;\n}\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\nstatic char hex_byte_to_char(uint8_t byte)\n{\n    byte = byte & 0x0f;\n    if (byte <= 9) {\n        return '0' + byte;\n    }\n    return 'A' + byte - 10;\n}\n\nstatic bool hex_to_string(uint8_t *hex, size_t hex_len, char *str, size_t str_len)\n{\n    if (hex_len * 2 < str_len) {\n        for (size_t i = 0; i < hex_len; ++i) {\n            str[2 * i + 1] = hex_byte_to_char(hex[i]);\n            str[2 * i] = hex_byte_to_char(hex[i] >> 4);\n        }\n        str[hex_len * 2] = 0;\n        return true;\n    }\n    return false;\n}\n\nstatic void debug_print_thread_dataset(otOperationalDataset *dataset)\n{\n    if (dataset) {\n        ESP_LOGD(TAG, \"Thread Network Name: %s\", dataset->mNetworkName.m8);\n        char str[33];\n        if (hex_to_string(dataset->mNetworkKey.m8, sizeof(dataset->mNetworkKey.m8), str, sizeof(str))) {\n            ESP_LOGD(TAG, \"Thread Network Key: %s\", str);\n        }\n        if (hex_to_string(dataset->mExtendedPanId.m8, sizeof(dataset->mExtendedPanId.m8), str, sizeof(str))) {\n            ESP_LOGD(TAG, \"Thread Extended PAN ID: %s\", str);\n        }\n        ESP_LOGD(TAG, \"Thread Channel: %d\", dataset->mChannel);\n        ESP_LOGD(TAG, \"Thread PAN ID: %d\", dataset->mPanId);\n    }\n}\n\nstatic void thread_timeout_timer_cb(void *arg)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (!prov_ctx) {\n        ESP_LOGE(TAG, \"Invalid state of Provisioning app\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return;\n    }\n\n    prov_ctx->thread_state = NETWORK_PROV_THREAD_DETACHED;\n    prov_ctx->prov_state = NETWORK_PROV_STATE_FAIL;\n    prov_ctx->thread_detached_reason = NETWORK_PROV_THREAD_NETWORK_NOT_FOUND;\n    execute_event_cb(NETWORK_PROV_THREAD_DATASET_FAIL, (void *)&prov_ctx->thread_detached_reason,\n                     sizeof(prov_ctx->thread_detached_reason));\n    RELEASE_LOCK(prov_ctx_lock);\n    return;\n}\n\n\nstatic esp_err_t set_thread_enable(bool val)\n{\n    esp_openthread_lock_acquire(portMAX_DELAY);\n    otInstance *instance = esp_openthread_get_instance();\n    bool is_enabled = (otThreadGetDeviceRole(instance) != OT_DEVICE_ROLE_DISABLED);\n    bool is_ip6_enabled =  otIp6IsEnabled(instance);\n    if (val && !is_ip6_enabled) {\n        if (otIp6SetEnabled(instance, val) != OT_ERROR_NONE) {\n            esp_openthread_lock_release();\n            return ESP_FAIL;\n        }\n    }\n    if (val != is_enabled) {\n        if (otThreadSetEnabled(instance, val) != OT_ERROR_NONE) {\n            esp_openthread_lock_release();\n            return ESP_FAIL;\n        }\n    }\n    if (!val && is_ip6_enabled) {\n        if (otIp6SetEnabled(instance, val) != OT_ERROR_NONE) {\n            esp_openthread_lock_release();\n            return ESP_FAIL;\n        }\n    }\n    esp_openthread_lock_release();\n    return ESP_OK;\n}\n\nstatic esp_err_t set_thread_dataset(otOperationalDatasetTlvs *dataset_tlvs)\n{\n    otError err = OT_ERROR_NONE;\n    esp_openthread_lock_acquire(portMAX_DELAY);\n    otInstance *instance = esp_openthread_get_instance();\n    err = otDatasetSetActiveTlvs(instance, dataset_tlvs);\n    esp_openthread_lock_release();\n    return err == OT_ERROR_NONE ? ESP_OK : ESP_FAIL;\n}\n\nstatic void update_thread_scan_result(otActiveScanResult *result, void *context)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return;\n    }\n    ACQUIRE_LOCK(prov_ctx_lock);\n\n    if (!prov_ctx) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return;\n    }\n\n    if (!prov_ctx->scanning) {\n        ESP_LOGD(TAG, \"Scan not running\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return;\n    }\n\n    if (!result) {\n        prov_ctx->scanning = false;\n        ESP_LOGD(TAG, \"Scan finished\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return;\n    }\n\n    otActiveScanResult *new_result = (otActiveScanResult *)malloc(sizeof(otActiveScanResult));\n    if (!new_result) {\n        ESP_LOGE(TAG, \"Failed to allocate memory for Thread scan result\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return;\n    }\n    memcpy(new_result, result, sizeof(otActiveScanResult));\n\n    if (prov_ctx->scan_result_count < MAX_SCAN_RESULTS) {\n        prov_ctx->scan_result[prov_ctx->scan_result_count] = new_result;\n        prov_ctx->scan_result_count++;\n    }\n    RELEASE_LOCK(prov_ctx_lock);\n}\n\nesp_err_t network_prov_mgr_thread_scan_start(bool blocking, uint32_t channel_mask)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n    ACQUIRE_LOCK(prov_ctx_lock);\n\n    if (!prov_ctx) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    if (prov_ctx->scanning) {\n        ESP_LOGD(TAG, \"Scan already running\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_OK;\n    }\n\n    /* Clear sorted list for new entries */\n    for (uint8_t i = 0; i < MAX_SCAN_RESULTS; i++) {\n        if (prov_ctx->scan_result[i]) {\n            free(prov_ctx->scan_result[i]);\n            prov_ctx->scan_result[i] = 0;\n        }\n    }\n    prov_ctx->scan_result_count = 0;\n\n    esp_openthread_lock_acquire(portMAX_DELAY);\n    otInstance *instance = esp_openthread_get_instance();\n    // Make netif enabled before start scanning\n    if (!otIp6IsEnabled(instance)) {\n        if (otIp6SetEnabled(instance, true) != OT_ERROR_NONE) {\n            ESP_LOGE(TAG, \"Failed to enable netif\");\n            RELEASE_LOCK(prov_ctx_lock);\n            esp_openthread_lock_release();\n            return ESP_FAIL;\n        }\n    }\n\n    if (otThreadDiscover(instance, channel_mask, OT_PANID_BROADCAST, false, false, update_thread_scan_result, NULL) != OT_ERROR_NONE) {\n        ESP_LOGE(TAG, \"Failed to start scan\");\n        RELEASE_LOCK(prov_ctx_lock);\n        esp_openthread_lock_release();\n        return ESP_FAIL;\n    }\n    esp_openthread_lock_release();\n\n    ESP_LOGI(TAG, \"Scan started\");\n    prov_ctx->scanning = true;\n    RELEASE_LOCK(prov_ctx_lock);\n\n    /* If scan is to be non-blocking, return immediately */\n    if (!blocking) {\n        return ESP_OK;\n    }\n\n    /* Loop till scan is complete */\n    bool scanning = true;\n    while (scanning) {\n        ACQUIRE_LOCK(prov_ctx_lock);\n        scanning = (prov_ctx && prov_ctx->scanning);\n        RELEASE_LOCK(prov_ctx_lock);\n\n        /* 500ms delay is  sufficient for Thread beacons to be sent */\n        vTaskDelay(500 / portTICK_PERIOD_MS);\n    }\n    return ESP_OK;\n}\n\nbool network_prov_mgr_thread_scan_finished(void)\n{\n    bool scan_finished = true;\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return scan_finished;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (!prov_ctx) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return scan_finished;\n    }\n\n    scan_finished = !prov_ctx->scanning;\n    RELEASE_LOCK(prov_ctx_lock);\n    return scan_finished;\n}\n\nuint16_t network_prov_mgr_thread_scan_result_count(void)\n{\n    uint16_t rval = 0;\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return rval;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (!prov_ctx) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return rval;\n    }\n\n    rval = prov_ctx->scan_result_count;\n    RELEASE_LOCK(prov_ctx_lock);\n    return rval;\n}\n\nconst otActiveScanResult *network_prov_mgr_thread_scan_result(uint16_t index)\n{\n    const otActiveScanResult *rval = NULL;\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return rval;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (!prov_ctx) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return rval;\n    }\n\n    if (index < MAX_SCAN_RESULTS) {\n        rval = prov_ctx->scan_result[index];\n    }\n    RELEASE_LOCK(prov_ctx_lock);\n    return rval;\n}\n\nesp_err_t network_prov_mgr_get_thread_state(network_prov_thread_state_t *state)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (prov_ctx == NULL || state == NULL) {\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_FAIL;\n    }\n\n    *state = prov_ctx->thread_state;\n    RELEASE_LOCK(prov_ctx_lock);\n    return ESP_OK;\n}\n\nesp_err_t network_prov_mgr_get_thread_detached_reason(network_prov_thread_fail_reason_t *reason)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (prov_ctx == NULL || reason == NULL) {\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_FAIL;\n    }\n\n    if (prov_ctx->thread_state != NETWORK_PROV_THREAD_DETACHED) {\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_FAIL;\n    }\n\n    *reason = prov_ctx->thread_detached_reason;\n    RELEASE_LOCK(prov_ctx_lock);\n    return ESP_OK;\n}\n\nesp_err_t network_prov_mgr_is_thread_provisioned(bool *provisioned)\n{\n    if (!provisioned) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    *provisioned = false;\n    otOperationalDataset dataset;\n    esp_openthread_lock_acquire(portMAX_DELAY);\n    otError ot_err = otDatasetGetActive(esp_openthread_get_instance(), &dataset);\n    esp_openthread_lock_release();\n    if (ot_err == OT_ERROR_NONE) {\n        *provisioned = true;\n        debug_print_thread_dataset(&dataset);\n    }\n\n    return ESP_OK;\n}\n\n\nesp_err_t network_prov_mgr_configure_thread_dataset(otOperationalDatasetTlvs *dataset_tlvs)\n{\n    esp_err_t err = ESP_OK;\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (!prov_ctx) {\n        ESP_LOGE(TAG, \"Invalid state of Provisioning app\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_FAIL;\n    }\n    if (prov_ctx->prov_state >= NETWORK_PROV_STATE_DATASET_RECV) {\n        ESP_LOGE(TAG, \"Dataset already received by provisioning app\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_FAIL;\n    }\n\n    otOperationalDataset dataset;\n    otError ot_err = otDatasetParseTlvs(dataset_tlvs, &dataset);\n    if (ot_err != OT_ERROR_NONE) {\n        prov_ctx->thread_state = NETWORK_PROV_THREAD_DETACHED;\n        prov_ctx->prov_state = NETWORK_PROV_STATE_FAIL;\n        prov_ctx->thread_detached_reason = NETWORK_PROV_THREAD_DATASET_INVALID;\n        execute_event_cb(NETWORK_PROV_THREAD_DATASET_FAIL, (void *)&prov_ctx->thread_detached_reason,\n                         sizeof(prov_ctx->thread_detached_reason));\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_FAIL;\n    }\n    debug_print_thread_dataset(&dataset);\n\n    err = set_thread_enable(false);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to stop Thread\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return err;\n    }\n    err = set_thread_dataset(dataset_tlvs);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to set Thread dataset\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return err;\n    }\n    err = set_thread_enable(true);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to start Thread\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return err;\n    }\n\n    /* Start the timeout timer*/\n    if (esp_timer_start_once(prov_ctx->thread_timeout_timer, 20000 * 1000U) != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to start Thread attaching timer\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_FAIL;\n    }\n\n    /* Reset Thread state for provisioning app */\n    prov_ctx->thread_state = NETWORK_PROV_THREAD_ATTACHING;\n    prov_ctx->prov_state = NETWORK_PROV_STATE_DATASET_RECV;\n    /* Execute user registered callback handler */\n    execute_event_cb(NETWORK_PROV_THREAD_DATASET_RECV, &dataset, sizeof(dataset));\n    RELEASE_LOCK(prov_ctx_lock);\n\n    return ESP_OK;\n}\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n\nstatic void network_prov_mgr_event_handler_internal(\n    void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n\n    /* If pointer to provisioning application data is NULL\n     * then provisioning manager is not running, therefore\n     * return with error to allow the global handler to act */\n    if (!prov_ctx) {\n        RELEASE_LOCK(prov_ctx_lock);\n        return;\n    }\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    /* If scan completed then update scan result */\n    if (prov_ctx->prov_state == NETWORK_PROV_STATE_STARTED &&\n            event_base == WIFI_EVENT &&\n            event_id == WIFI_EVENT_SCAN_DONE) {\n        update_wifi_scan_results();\n    }\n\n    /* Only handle events when credential is received and\n     * Wi-Fi STA is yet to complete trying the connection */\n    if (prov_ctx->prov_state < NETWORK_PROV_STATE_CRED_RECV) {\n        RELEASE_LOCK(prov_ctx_lock);\n        return;\n    }\n\n    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {\n        ESP_LOGI(TAG, \"STA Start\");\n        /* Once configuration is received through protocomm,\n         * device is started as station. Once station starts,\n         * wait for connection to establish with configured\n         * host SSID and password */\n        prov_ctx->wifi_state = NETWORK_PROV_WIFI_STA_CONNECTING;\n    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {\n        ESP_LOGI(TAG, \"STA Got IP\");\n        /* Station got IP. That means configuration is successful. */\n        prov_ctx->wifi_state = NETWORK_PROV_WIFI_STA_CONNECTED;\n        prov_ctx->prov_state = NETWORK_PROV_STATE_SUCCESS;\n\n        /* If auto stop is enabled (default), schedule timer to\n         * stop provisioning after configured timeout. */\n        if (!prov_ctx->mgr_info.capabilities.no_auto_stop) {\n            ESP_LOGD(TAG, \"Starting %d sec timer for stop_prov_timer_cb()\",\n                     CONFIG_NETWORK_PROV_AUTOSTOP_TIMEOUT);\n            esp_timer_start_once(prov_ctx->autostop_timer, CONFIG_NETWORK_PROV_AUTOSTOP_TIMEOUT * 1000000U);\n        }\n\n        /* Execute user registered callback handler */\n        execute_event_cb(NETWORK_PROV_WIFI_CRED_SUCCESS, NULL, 0);\n    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {\n        if (prov_ctx->mgr_config.network_prov_wifi_conn_cfg.wifi_conn_attempts > 0) {\n            prov_ctx->connection_attempts_completed += 1; /* Increasing attempt after every failure */\n            if (prov_ctx->connection_attempts_completed < prov_ctx->mgr_config.network_prov_wifi_conn_cfg.wifi_conn_attempts) {\n                /* Set WiFi state to NETWORK_PROV_WIFI_STA_CONN_ATTEMPT_FAILED only if the user configure wifi_conn_attempts\n                 * and connection_attempts_completed are less than wifi_conn_attempts.\n                 */\n                prov_ctx->wifi_state = NETWORK_PROV_WIFI_STA_CONN_ATTEMPT_FAILED;\n                esp_wifi_connect();\n            } else {\n                /* Station couldn't connect to configured host SSID */\n                ESP_LOGE(TAG, \"STA Disconnected\");\n                prov_ctx->wifi_state = NETWORK_PROV_WIFI_STA_DISCONNECTED;\n            }\n        } else {\n            ESP_LOGE(TAG, \"STA Disconnected\");\n            prov_ctx->wifi_state = NETWORK_PROV_WIFI_STA_DISCONNECTED;\n        }\n\n        /* In case of disconnection, update state of service and\n         * run the event handler with disconnection reason as data */\n        if (prov_ctx->wifi_state == NETWORK_PROV_WIFI_STA_DISCONNECTED) {\n            prov_ctx->prov_state = NETWORK_PROV_STATE_FAIL;\n            wifi_event_sta_disconnected_t *disconnected = (wifi_event_sta_disconnected_t *) event_data;\n            ESP_LOGE(TAG, \"Disconnect reason : %d\", disconnected->reason);\n\n            /* Set code corresponding to the reason for disconnection */\n            switch (disconnected->reason) {\n            case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT:\n            case WIFI_REASON_AUTH_FAIL:\n            case WIFI_REASON_HANDSHAKE_TIMEOUT:\n            case WIFI_REASON_MIC_FAILURE:\n                ESP_LOGE(TAG, \"STA Auth Error\");\n                prov_ctx->wifi_disconnect_reason = NETWORK_PROV_WIFI_STA_AUTH_ERROR;\n                break;\n            case WIFI_REASON_NO_AP_FOUND:\n                ESP_LOGE(TAG, \"STA AP Not found\");\n                prov_ctx->wifi_disconnect_reason = NETWORK_PROV_WIFI_STA_AP_NOT_FOUND;\n                break;\n            default:\n                if (prov_ctx->mgr_config.network_prov_wifi_conn_cfg.wifi_conn_attempts == 0) {\n                    /* If none of the expected reasons, retry connecting to host SSID */\n                    prov_ctx->wifi_state = NETWORK_PROV_WIFI_STA_CONNECTING;\n                    esp_wifi_connect();\n                }\n            }\n            if (prov_ctx->wifi_state == NETWORK_PROV_WIFI_STA_DISCONNECTED) {\n                /* Execute user registered callback handler */\n                network_prov_wifi_sta_fail_reason_t reason = prov_ctx->wifi_disconnect_reason;\n                execute_event_cb(NETWORK_PROV_WIFI_CRED_FAIL, (void *)&reason, sizeof(reason));\n            }\n        }\n    }\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    /* Only handle events when dataset is received and\n     * Thread is yet to complete trying the connection */\n    if (prov_ctx->prov_state < NETWORK_PROV_STATE_DATASET_RECV) {\n        RELEASE_LOCK(prov_ctx_lock);\n        return;\n    }\n\n    if (event_base == OPENTHREAD_EVENT && event_id == OPENTHREAD_EVENT_ATTACHED) {\n        ESP_LOGI(TAG, \"Thread attached\");\n        prov_ctx->thread_state = NETWORK_PROV_THREAD_ATTACHED;\n        prov_ctx->prov_state = NETWORK_PROV_STATE_SUCCESS;\n        /* If auto stop is enabled (default), schedule timer to\n         * stop provisioning after configured timeout. */\n        if (!prov_ctx->mgr_info.capabilities.no_auto_stop) {\n            ESP_LOGD(TAG, \"Starting %d sec timer for stop_prov_timer_cb()\",\n                     CONFIG_NETWORK_PROV_AUTOSTOP_TIMEOUT);\n            esp_timer_start_once(prov_ctx->autostop_timer, CONFIG_NETWORK_PROV_AUTOSTOP_TIMEOUT * 1000000U);\n        }\n        esp_timer_stop(prov_ctx->thread_timeout_timer);\n        /* Execute user registered callback handler */\n        execute_event_cb(NETWORK_PROV_THREAD_DATASET_SUCCESS, NULL, 0);\n    }\n\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n\n    if (event_base == NETWORK_PROV_MGR_PVT_EVENT && event_id == NETWORK_PROV_MGR_STOP) {\n        prov_stop_and_notify(true);\n    }\n\n    RELEASE_LOCK(prov_ctx_lock);\n}\n\n\nesp_err_t network_prov_mgr_init(network_prov_mgr_config_t config)\n{\n    if (!prov_ctx_lock) {\n        /* Create mutex if this is the first time init is being called.\n         * This is created only once and never deleted because if some\n         * other thread is trying to take this mutex while it is being\n         * deleted from another thread then the reference may become\n         * invalid and cause exception */\n        prov_ctx_lock = xSemaphoreCreateMutex();\n        if (!prov_ctx_lock) {\n            ESP_LOGE(TAG, \"Failed to create mutex\");\n            return ESP_ERR_NO_MEM;\n        }\n    }\n\n    void *fn_ptrs[] = {\n        config.scheme.prov_stop,\n        config.scheme.prov_start,\n        config.scheme.new_config,\n        config.scheme.delete_config,\n        config.scheme.set_config_service,\n        config.scheme.set_config_endpoint\n    };\n\n    /* All function pointers in the scheme structure must be non-null */\n    for (size_t i = 0; i < sizeof(fn_ptrs) / sizeof(fn_ptrs[0]); i++) {\n        if (!fn_ptrs[i]) {\n            return ESP_ERR_INVALID_ARG;\n        }\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (prov_ctx) {\n        ESP_LOGE(TAG, \"Provisioning manager already initialized\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    /* Allocate memory for provisioning app data */\n    prov_ctx = (struct network_prov_mgr_ctx *) calloc(1, sizeof(struct network_prov_mgr_ctx));\n    if (!prov_ctx) {\n        ESP_LOGE(TAG, \"Error allocating memory for singleton instance\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_ERR_NO_MEM;\n    }\n\n    prov_ctx->mgr_config = config;\n    prov_ctx->prov_state = NETWORK_PROV_STATE_IDLE;\n    prov_ctx->mgr_info.version = NETWORK_PROV_MGR_VERSION;\n\n    /* Allocate memory for provisioning scheme configuration */\n    const network_prov_scheme_t *scheme = &prov_ctx->mgr_config.scheme;\n    esp_err_t ret = ESP_OK;\n    prov_ctx->prov_scheme_config = scheme->new_config();\n    if (!prov_ctx->prov_scheme_config) {\n        ESP_LOGE(TAG, \"failed to allocate provisioning scheme configuration\");\n        ret = ESP_ERR_NO_MEM;\n        goto exit;\n    }\n\n    ret = scheme->set_config_endpoint(prov_ctx->prov_scheme_config, \"prov-ctrl\", 0xFF4F);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"failed to configure Network state control endpoint\");\n        goto exit;\n    }\n\n    ret = scheme->set_config_endpoint(prov_ctx->prov_scheme_config, \"prov-scan\", 0xFF50);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"failed to configure Network scanning endpoint\");\n        goto exit;\n    }\n\n    ret = scheme->set_config_endpoint(prov_ctx->prov_scheme_config, \"prov-session\", 0xFF51);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"failed to configure security endpoint\");\n        goto exit;\n    }\n\n    ret = scheme->set_config_endpoint(prov_ctx->prov_scheme_config, \"prov-config\", 0xFF52);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"failed to configure Network configuration endpoint\");\n        goto exit;\n    }\n\n    ret = scheme->set_config_endpoint(prov_ctx->prov_scheme_config, \"proto-ver\", 0xFF53);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"failed to configure version endpoint\");\n        goto exit;\n    }\n\n    /* Application specific custom endpoints will be assigned\n     * incremental UUIDs starting after this value */\n    prov_ctx->endpoint_uuid_used = 0xFF53;\n\n    /* This delay is so that the client side app is notified first\n     * and then the provisioning is stopped. Default is 1000ms. */\n    prov_ctx->cleanup_delay = 1000;\n\nexit:\n    if (ret != ESP_OK) {\n        if (prov_ctx->prov_scheme_config) {\n            config.scheme.delete_config(prov_ctx->prov_scheme_config);\n        }\n        free(prov_ctx);\n    } else {\n        execute_event_cb(NETWORK_PROV_INIT, NULL, 0);\n    }\n    RELEASE_LOCK(prov_ctx_lock);\n    return ret;\n}\n\nvoid network_prov_mgr_wait(void)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return;\n    }\n\n    while (1) {\n        ACQUIRE_LOCK(prov_ctx_lock);\n        if (prov_ctx &&\n                prov_ctx->prov_state != NETWORK_PROV_STATE_IDLE) {\n            RELEASE_LOCK(prov_ctx_lock);\n            vTaskDelay(1000 / portTICK_PERIOD_MS);\n            continue;\n        }\n        break;\n    }\n    RELEASE_LOCK(prov_ctx_lock);\n}\n\nesp_err_t network_prov_mgr_deinit(void)\n{\n    esp_err_t ret = ESP_FAIL;\n\n    if (!prov_ctx_lock) {\n        ESP_LOGW(TAG, \"Provisioning manager not initialized\");\n        return ESP_OK;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n\n    /* This will do one of these:\n     * 1) if found running, stop the provisioning service (returns true)\n     * 2) if service was already in the process of termination, this will\n     *    wait till the service is stopped (returns false)\n     * 3) if service was not running, this will return immediately (returns false)\n     */\n    bool service_was_running = network_prov_mgr_stop_service(1);\n\n    /* If service was not running, its also possible that manager\n     * was not even initialized */\n    if (!service_was_running && !prov_ctx) {\n        ESP_LOGD(TAG, \"Manager already de-initialized\");\n        RELEASE_LOCK(prov_ctx_lock);\n        vSemaphoreDelete(prov_ctx_lock);\n        prov_ctx_lock = NULL;\n        return ESP_OK;\n    }\n\n    if (prov_ctx->app_info_json) {\n        cJSON_Delete(prov_ctx->app_info_json);\n    }\n\n    if (prov_ctx->prov_scheme_config) {\n        prov_ctx->mgr_config.scheme.delete_config(prov_ctx->prov_scheme_config);\n    }\n\n    /* Extract the callbacks to be called post deinit */\n    network_prov_cb_func_t app_cb = prov_ctx->mgr_config.app_event_handler.event_cb;\n    void *app_data = prov_ctx->mgr_config.app_event_handler.user_data;\n\n    network_prov_cb_func_t scheme_cb = prov_ctx->mgr_config.scheme_event_handler.event_cb;\n    void *scheme_data = prov_ctx->mgr_config.scheme_event_handler.user_data;\n\n    /* Free manager context */\n    free(prov_ctx);\n    prov_ctx = NULL;\n    RELEASE_LOCK(prov_ctx_lock);\n\n    /* If a running service was also stopped during de-initialization\n     * then NETWORK_PROV_END event also needs to be emitted before deinit */\n    if (service_was_running) {\n        ESP_LOGD(TAG, \"execute_event_cb : %d\", NETWORK_PROV_END);\n        if (scheme_cb) {\n            scheme_cb(scheme_data, NETWORK_PROV_END, NULL);\n        }\n        if (app_cb) {\n            app_cb(app_data, NETWORK_PROV_END, NULL);\n        }\n        ret = esp_event_post(NETWORK_PROV_EVENT, NETWORK_PROV_END, NULL, 0, portMAX_DELAY);\n        if (ret != ESP_OK) {\n            ESP_LOGE(TAG, \"Failed to post event NETWORK_PROV_END\");\n            return ret;\n        }\n    }\n\n    ESP_LOGD(TAG, \"execute_event_cb : %d\", NETWORK_PROV_DEINIT);\n\n    /* Execute deinit event callbacks */\n    if (scheme_cb) {\n        scheme_cb(scheme_data, NETWORK_PROV_DEINIT, NULL);\n    }\n    if (app_cb) {\n        app_cb(app_data, NETWORK_PROV_DEINIT, NULL);\n    }\n    if (esp_event_post(NETWORK_PROV_EVENT, NETWORK_PROV_DEINIT, NULL, 0, portMAX_DELAY) != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to post event NETWORK_PROV_DEINIT\");\n    }\n\n    vSemaphoreDelete(prov_ctx_lock);\n    prov_ctx_lock = NULL;\n    return ESP_OK;\n}\n\nesp_err_t network_prov_mgr_start_provisioning(network_prov_security_t security, const void *network_prov_sec_params,\n        const char *service_name, const char *service_key)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (!prov_ctx) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    if (prov_ctx->prov_state != NETWORK_PROV_STATE_IDLE) {\n        ESP_LOGE(TAG, \"Provisioning service already started\");\n        RELEASE_LOCK(prov_ctx_lock);\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    esp_err_t ret = ESP_OK;\n    /* Update state so that parallel call to network_prov_mgr_start_provisioning()\n     * or network_prov_mgr_stop_provisioning() or network_prov_mgr_deinit() from another\n     * thread doesn't interfere with this process */\n    prov_ctx->prov_state = NETWORK_PROV_STATE_STARTING;\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    uint8_t restore_wifi_flag = 0;\n    /* Start Wi-Fi in Station Mode.\n     * This is necessary for scanning to work */\n    ret = esp_wifi_set_mode(WIFI_MODE_STA);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to set Wi-Fi mode to STA\");\n        goto err;\n    }\n    ret = esp_wifi_start();\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to start Wi-Fi\");\n        goto err;\n    }\n\n    /* Change Wi-Fi storage to RAM temporarily and erase any old\n     * credentials in RAM(i.e. without erasing the copy on NVS). Also\n     * call disconnect to make sure device doesn't remain connected\n     * to the AP whose credentials were present earlier */\n    wifi_config_t wifi_cfg_empty, wifi_cfg_old;\n    memset(&wifi_cfg_empty, 0, sizeof(wifi_config_t));\n    esp_wifi_get_config(WIFI_IF_STA, &wifi_cfg_old);\n    ret = esp_wifi_set_storage(WIFI_STORAGE_RAM);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to set Wi-Fi storage to RAM\");\n        goto err;\n    }\n\n    /* WiFi storage needs to be restored before exiting this API */\n    restore_wifi_flag |= WIFI_PROV_STORAGE_BIT;\n    /* Erase Wi-Fi credentials in RAM, when call disconnect and user code\n     * receive WIFI_EVENT_STA_DISCONNECTED and maybe call esp_wifi_connect, at\n     * this time Wi-Fi will have no configuration to connect */\n    ret = esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg_empty);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to set empty Wi-Fi credentials\");\n        goto err;\n    }\n    /* WiFi settings needs to be restored if provisioning error before exiting this API */\n    restore_wifi_flag |= WIFI_PROV_SETTING_BIT;\n\n    ret = esp_wifi_disconnect();\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to disconnect\");\n        goto err;\n    }\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n\n#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0\n    /* Initialize app data */\n    if (security == NETWORK_PROV_SECURITY_0) {\n        prov_ctx->mgr_info.capabilities.no_sec = true;\n    }\n#endif\n#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1\n    if (security == NETWORK_PROV_SECURITY_1) {\n        if (network_prov_sec_params) {\n            static protocomm_security1_params_t sec1_params;\n            // Generate internal copy of \"pop\", that shall be freed at the end\n            char *pop = strdup(network_prov_sec_params);\n            if (pop == NULL) {\n                ESP_LOGE(TAG, \"Failed to allocate memory for pop\");\n                ret = ESP_ERR_NO_MEM;\n                goto err;\n            }\n            sec1_params.data = (const uint8_t *)pop;\n            sec1_params.len = strlen(pop);\n            prov_ctx->protocomm_sec_params = (const void *) &sec1_params;\n        } else {\n            prov_ctx->mgr_info.capabilities.no_pop = true;\n        }\n    }\n#endif\n#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2\n    if (security == NETWORK_PROV_SECURITY_2) {\n        if (network_prov_sec_params) {\n            prov_ctx->protocomm_sec_params = network_prov_sec_params;\n        }\n    }\n#endif\n    prov_ctx->security = security;\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    esp_timer_create_args_t wifi_connect_timer_conf = {\n        .callback = wifi_connect_timer_cb,\n        .arg = NULL,\n        .dispatch_method = ESP_TIMER_TASK,\n        .name = \"network_prov_wifi_connect_tm\"\n    };\n    ret = esp_timer_create(&wifi_connect_timer_conf, &prov_ctx->wifi_connect_timer);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to create Wi-Fi connect timer\");\n        goto err;\n    }\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    esp_timer_create_args_t thread_timeout_timer_conf = {\n        .callback = thread_timeout_timer_cb,\n        .arg = NULL,\n        .dispatch_method = ESP_TIMER_TASK,\n        .name = \"thread_prov_timeout_tm\"\n    };\n    ret = esp_timer_create(&thread_timeout_timer_conf, &prov_ctx->thread_timeout_timer);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to create Thread attaching timeout timer\");\n        goto err;\n    }\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n\n    /* If auto stop on completion is enabled (default) create the stopping timer */\n    if (!prov_ctx->mgr_info.capabilities.no_auto_stop) {\n        /* Create timer object as a member of app data */\n        esp_timer_create_args_t autostop_timer_conf = {\n            .callback = stop_prov_timer_cb,\n            .arg = NULL,\n            .dispatch_method = ESP_TIMER_TASK,\n            .name = \"network_prov_autostop_tm\"\n        };\n        ret = esp_timer_create(&autostop_timer_conf, &prov_ctx->autostop_timer);\n        if (ret != ESP_OK) {\n            ESP_LOGE(TAG, \"Failed to create auto-stop timer\");\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n            esp_timer_delete(prov_ctx->wifi_connect_timer);\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n            esp_timer_delete(prov_ctx->thread_timeout_timer);\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n            goto err;\n        }\n    }\n\n    esp_timer_create_args_t cleanup_delay_timer = {\n        .callback = cleanup_delay_timer_cb,\n        .arg = NULL,\n        .dispatch_method = ESP_TIMER_TASK,\n        .name = \"cleanup_delay_tm\"\n    };\n    ret = esp_timer_create(&cleanup_delay_timer, &prov_ctx->cleanup_delay_timer);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to create cleanup delay timer\");\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        esp_timer_delete(prov_ctx->wifi_connect_timer);\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        esp_timer_delete(prov_ctx->thread_timeout_timer);\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        esp_timer_delete(prov_ctx->autostop_timer);\n        goto err;\n    }\n\n\n    /* System APIs for BLE / Wi-Fi / Thread will be called inside network_prov_mgr_start_service(),\n     * which may trigger system level events. Hence, releasing the context lock will\n     * ensure that network_prov_mgr_event_handler() doesn't block the global event_loop\n     * handler when system events need to be handled */\n    RELEASE_LOCK(prov_ctx_lock);\n\n    /* Start provisioning service */\n    ret = network_prov_mgr_start_service(service_name, service_key);\n    if (ret != ESP_OK) {\n        esp_timer_delete(prov_ctx->autostop_timer);\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        esp_timer_delete(prov_ctx->wifi_connect_timer);\n#endif\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        esp_timer_delete(prov_ctx->thread_timeout_timer);\n#endif\n        esp_timer_delete(prov_ctx->cleanup_delay_timer);\n    }\n    ACQUIRE_LOCK(prov_ctx_lock);\n    if (ret == ESP_OK) {\n        prov_ctx->prov_state = NETWORK_PROV_STATE_STARTED;\n        /* Execute user registered callback handler */\n        execute_event_cb(NETWORK_PROV_START, NULL, 0);\n        goto exit;\n    }\n\nerr:\n    prov_ctx->prov_state = NETWORK_PROV_STATE_IDLE;\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    if (restore_wifi_flag & WIFI_PROV_SETTING_BIT) {\n        /* Restore current WiFi settings, since provisioning start has failed */\n        esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg_old);\n    }\n#endif\nexit:\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    if (restore_wifi_flag & WIFI_PROV_STORAGE_BIT) {\n        /* Restore WiFi storage back to FLASH */\n        esp_wifi_set_storage(WIFI_STORAGE_FLASH);\n    }\n#endif\n    RELEASE_LOCK(prov_ctx_lock);\n    return ret;\n}\n\nvoid network_prov_mgr_stop_provisioning(void)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n\n    /* Launches task for stopping the provisioning service. This will do one of these:\n     * 1) start a task for stopping the provisioning service (returns true)\n     * 2) if service was already in the process of termination, this will\n     *    wait till the service is stopped (returns false)\n     * 3) if service was not running, this will return immediately (returns false)\n     */\n    network_prov_mgr_stop_service(0);\n\n    RELEASE_LOCK(prov_ctx_lock);\n}\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\nesp_err_t network_prov_mgr_reset_wifi_provisioning(void)\n{\n    esp_err_t ret = esp_wifi_restore();\n\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"esp_wifi_restore fail, ret is %d\", ret);\n        ret = ESP_FAIL;\n    }\n\n    return ret;\n}\n\nesp_err_t network_prov_mgr_reset_wifi_sm_state_on_failure(void)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n\n    esp_err_t err = ESP_OK;\n    /* If already in STARTED state, reset has already been performed (e.g., by firmware).\n     * Return success as the device is effectively already reset and in provisioning mode. */\n    if (prov_ctx->prov_state == NETWORK_PROV_STATE_STARTED) {\n        ESP_LOGD(TAG, \"Reset already performed, device already in provisioning mode\");\n        goto exit;\n    }\n\n    if (prov_ctx->prov_state != NETWORK_PROV_STATE_FAIL) {\n        ESP_LOGE(TAG, \"Trying reset when not in failure state. Current state: %d\", prov_ctx->prov_state);\n        err = ESP_ERR_INVALID_STATE;\n        goto exit;\n    }\n\n    wifi_config_t wifi_cfg = {0};\n\n    err = esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to set wifi config, 0x%x\", err);\n        goto exit;\n    }\n\n    /* Reset connection attempts counter to allow full wifi_conn_attempts retries */\n    prov_ctx->connection_attempts_completed = 0;\n    prov_ctx->prov_state = NETWORK_PROV_STATE_STARTED;\n\nexit:\n    RELEASE_LOCK(prov_ctx_lock);\n    return err;\n}\n\nesp_err_t network_prov_mgr_reset_wifi_sm_state_for_reprovision(void)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n\n    esp_err_t ret = ESP_OK;\n    wifi_config_t wifi_cfg_empty = {0};\n    uint8_t restore_wifi_flag = 0;\n\n    if (!prov_ctx->mgr_info.capabilities.no_auto_stop) {\n        ESP_LOGE(TAG, \"Execute network_prov_mgr_disable_auto_stop() before calling this API\");\n        ret = ESP_ERR_INVALID_STATE;\n        goto exit;\n    }\n\n    ret = esp_wifi_set_storage(WIFI_STORAGE_RAM);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to set Wi-Fi storage to RAM\");\n        goto exit;\n    }\n    restore_wifi_flag |= WIFI_PROV_STORAGE_BIT;\n\n    ret = esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg_empty);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to set empty Wi-Fi credentials, 0x%x\", ret);\n        goto exit;\n    }\n\n    ret = esp_wifi_disconnect();\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to disconnect wifi, 0x%x\", ret);\n        goto exit;\n    }\n\n    prov_ctx->prov_state = NETWORK_PROV_STATE_STARTED;\n    execute_event_cb(NETWORK_PROV_START, NULL, 0);\n\nexit:\n    if (restore_wifi_flag & WIFI_PROV_STORAGE_BIT) {\n        esp_wifi_set_storage(WIFI_STORAGE_FLASH);\n    }\n    RELEASE_LOCK(prov_ctx_lock);\n    return ret;\n}\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\nesp_err_t network_prov_mgr_reset_thread_provisioning(void)\n{\n    otInstance *instance = esp_openthread_get_instance();\n    esp_openthread_lock_acquire(portMAX_DELAY);\n    if (otInstanceErasePersistentInfo(instance) != OT_ERROR_NONE) {\n        ESP_LOGE(TAG, \"Failed to Erase Thread Network Info\");\n        esp_openthread_lock_release();\n        return ESP_FAIL;\n    }\n    esp_openthread_lock_release();\n    return ESP_OK;\n}\n\nesp_err_t network_prov_mgr_reset_thread_sm_state_on_failure(void)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n\n    esp_err_t err = ESP_OK;\n    otInstance *instance = esp_openthread_get_instance();\n\n    esp_openthread_lock_acquire(portMAX_DELAY);\n    /* If already in STARTED state, reset has already been performed (e.g., by firmware).\n     * Return success as the device is effectively already reset and in provisioning mode. */\n    if (prov_ctx->prov_state == NETWORK_PROV_STATE_STARTED) {\n        ESP_LOGD(TAG, \"Reset already performed, device already in provisioning mode\");\n        goto exit;\n    }\n\n    if (prov_ctx->prov_state != NETWORK_PROV_STATE_FAIL) {\n        ESP_LOGE(TAG, \"Trying reset when not in failure state. Current state: %d\", prov_ctx->prov_state);\n        err = ESP_ERR_INVALID_STATE;\n        goto exit;\n    }\n\n    if (otThreadSetEnabled(instance, false) != OT_ERROR_NONE) {\n        ESP_LOGE(TAG, \"Failed to stop Thread\");\n        err = ESP_FAIL;\n        goto exit;\n    }\n\n    if (otIp6SetEnabled(instance, false) != OT_ERROR_NONE) {\n        ESP_LOGE(TAG, \"Failed to disable Thread netif\");\n        err = ESP_FAIL;\n        goto exit;\n    }\n\n    if (otInstanceErasePersistentInfo(instance) != OT_ERROR_NONE) {\n        ESP_LOGE(TAG, \"Failed to erase Thread network info\");\n        err = ESP_FAIL;\n        goto exit;\n    }\n\n    prov_ctx->prov_state = NETWORK_PROV_STATE_STARTED;\n\nexit:\n    esp_openthread_lock_release();\n    RELEASE_LOCK(prov_ctx_lock);\n    return err;\n}\n\nesp_err_t network_prov_mgr_reset_thread_sm_state_for_reprovision(void)\n{\n    if (!prov_ctx_lock) {\n        ESP_LOGE(TAG, \"Provisioning manager not initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    ACQUIRE_LOCK(prov_ctx_lock);\n\n    esp_err_t ret = ESP_OK;\n    otInstance *instance = esp_openthread_get_instance();\n\n    esp_openthread_lock_acquire(portMAX_DELAY);\n    if (!prov_ctx->mgr_info.capabilities.no_auto_stop) {\n        ESP_LOGE(TAG, \"Execute network_prov_mgr_disable_auto_stop() before calling this API\");\n        ret = ESP_ERR_INVALID_STATE;\n        goto exit;\n    }\n\n    if (otThreadSetEnabled(instance, false) != OT_ERROR_NONE) {\n        ESP_LOGE(TAG, \"Failed to stop Thread\");\n        ret = ESP_FAIL;\n        goto exit;\n    }\n\n    if (otIp6SetEnabled(instance, false) != OT_ERROR_NONE) {\n        ESP_LOGE(TAG, \"Failed to disable Thread netif\");\n        ret = ESP_FAIL;\n        goto exit;\n    }\n\n    prov_ctx->prov_state = NETWORK_PROV_STATE_STARTED;\n    execute_event_cb(NETWORK_PROV_START, NULL, 0);\n\nexit:\n    esp_openthread_lock_release();\n    RELEASE_LOCK(prov_ctx_lock);\n    return ret;\n}\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n"
  },
  {
    "path": "network_provisioning/src/network_config.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <esp_err.h>\n#include <esp_log.h>\n\n#include \"network_constants.pb-c.h\"\n#include \"network_config.pb-c.h\"\n\n#include <network_provisioning/network_config.h>\n\nstatic const char *TAG = \"NetworkProvConfig\";\n\ntypedef struct network_prov_config_cmd {\n    int cmd_num;\n    esp_err_t (*command_handler)(NetworkConfigPayload *req,\n                                 NetworkConfigPayload *resp, void *priv_data);\n} network_prov_config_cmd_t;\n\nstatic esp_err_t cmd_get_status_handler(NetworkConfigPayload *req,\n                                        NetworkConfigPayload *resp, void *priv_data);\n\nstatic esp_err_t cmd_set_config_handler(NetworkConfigPayload *req,\n                                        NetworkConfigPayload *resp, void *priv_data);\n\nstatic esp_err_t cmd_apply_config_handler(NetworkConfigPayload *req,\n        NetworkConfigPayload *resp, void *priv_data);\n\nstatic network_prov_config_cmd_t cmd_table[] = {\n    {\n        .cmd_num = NETWORK_CONFIG_MSG_TYPE__TypeCmdGetWifiStatus,\n        .command_handler = cmd_get_status_handler\n    },\n    {\n        .cmd_num = NETWORK_CONFIG_MSG_TYPE__TypeCmdSetWifiConfig,\n        .command_handler = cmd_set_config_handler\n    },\n    {\n        .cmd_num = NETWORK_CONFIG_MSG_TYPE__TypeCmdApplyWifiConfig,\n        .command_handler = cmd_apply_config_handler\n    },\n    {\n        .cmd_num = NETWORK_CONFIG_MSG_TYPE__TypeCmdGetThreadStatus,\n        .command_handler = cmd_get_status_handler\n    },\n    {\n        .cmd_num = NETWORK_CONFIG_MSG_TYPE__TypeCmdSetThreadConfig,\n        .command_handler = cmd_set_config_handler\n    },\n    {\n        .cmd_num = NETWORK_CONFIG_MSG_TYPE__TypeCmdApplyThreadConfig,\n        .command_handler = cmd_apply_config_handler\n    }\n};\n\nstatic esp_err_t cmd_get_status_handler(NetworkConfigPayload *req,\n                                        NetworkConfigPayload *resp, void *priv_data)\n{\n    ESP_LOGD(TAG, \"Enter cmd_get_status_handler\");\n    network_prov_config_handlers_t *h = (network_prov_config_handlers_t *) priv_data;\n    if (!h) {\n        ESP_LOGE(TAG, \"Command invoked without handlers\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    if (req->msg == NETWORK_CONFIG_MSG_TYPE__TypeCmdGetWifiStatus) {\n        RespGetWifiStatus *resp_payload = (RespGetWifiStatus *) malloc(sizeof(RespGetWifiStatus));\n        if (!resp_payload) {\n            ESP_LOGE(TAG, \"Error allocating memory\");\n            return ESP_ERR_NO_MEM;\n        }\n        resp_get_wifi_status__init(resp_payload);\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        network_prov_config_get_wifi_data_t resp_data;\n        if (h->wifi_get_status_handler) {\n            if (h->wifi_get_status_handler(&resp_data, &h->ctx) == ESP_OK) {\n                if (resp_data.wifi_state == NETWORK_PROV_WIFI_STA_CONNECTING) {\n                    resp_payload->wifi_sta_state = WIFI_STATION_STATE__Connecting;\n                    resp_payload->state_case = RESP_GET_WIFI_STATUS__STATE_WIFI_CONNECTED;\n                } else if (resp_data.wifi_state == NETWORK_PROV_WIFI_STA_CONNECTED) {\n                    resp_payload->wifi_sta_state  = WIFI_STATION_STATE__Connected;\n                    resp_payload->state_case = RESP_GET_WIFI_STATUS__STATE_WIFI_CONNECTED;\n                    WifiConnectedState *connected = (WifiConnectedState *)(\n                                                        malloc(sizeof(WifiConnectedState)));\n                    if (!connected) {\n                        free(resp_payload);\n                        ESP_LOGE(TAG, \"Error allocating memory\");\n                        return ESP_ERR_NO_MEM;\n                    }\n                    resp_payload->wifi_connected  = connected;\n                    wifi_connected_state__init(connected);\n\n                    connected->ip4_addr = strdup(resp_data.conn_info.ip_addr);\n                    if (connected->ip4_addr == NULL) {\n                        free(connected);\n                        free(resp_payload);\n                        return ESP_ERR_NO_MEM;\n                    }\n\n                    connected->bssid.len  = sizeof(resp_data.conn_info.bssid);\n                    connected->bssid.data = (uint8_t *) strndup(resp_data.conn_info.bssid,\n                                            sizeof(resp_data.conn_info.bssid));\n                    if (connected->bssid.data == NULL) {\n                        free(connected->ip4_addr);\n                        free(connected);\n                        free(resp_payload);\n                        return ESP_ERR_NO_MEM;\n                    }\n\n                    connected->ssid.len   = strlen(resp_data.conn_info.ssid);\n                    connected->ssid.data  = (uint8_t *) strdup(resp_data.conn_info.ssid);\n                    if (connected->ssid.data == NULL) {\n                        free(connected->bssid.data);\n                        free(connected->ip4_addr);\n                        free(connected);\n                        free(resp_payload);\n                        return ESP_ERR_NO_MEM;\n                    }\n\n                    connected->channel    = resp_data.conn_info.channel;\n                    connected->auth_mode  = resp_data.conn_info.auth_mode;\n                } else if (resp_data.wifi_state == NETWORK_PROV_WIFI_STA_DISCONNECTED) {\n                    resp_payload->wifi_sta_state = WIFI_STATION_STATE__ConnectionFailed;\n                    resp_payload->state_case = RESP_GET_WIFI_STATUS__STATE_WIFI_FAIL_REASON;\n\n                    if (resp_data.fail_reason == NETWORK_PROV_WIFI_STA_AUTH_ERROR) {\n                        resp_payload->wifi_fail_reason = WIFI_CONNECT_FAILED_REASON__AuthError;\n                    } else if (resp_data.fail_reason == NETWORK_PROV_WIFI_STA_AP_NOT_FOUND) {\n                        resp_payload->wifi_fail_reason = WIFI_CONNECT_FAILED_REASON__WifiNetworkNotFound;\n                    }\n                } else if (resp_data.wifi_state == NETWORK_PROV_WIFI_STA_CONN_ATTEMPT_FAILED) {\n                    resp_payload->wifi_sta_state = WIFI_STATION_STATE__Connecting;\n                    resp_payload->state_case = RESP_GET_WIFI_STATUS__STATE_ATTEMPT_FAILED;\n                    WifiAttemptFailed *attempt_failed = (WifiAttemptFailed *)(\n                                                            calloc(1, sizeof(WifiAttemptFailed)));\n                    if (!attempt_failed) {\n                        free(resp_payload);\n                        ESP_LOGE(TAG, \"Error allocating memory\");\n                        return ESP_ERR_NO_MEM;\n                    }\n                    wifi_attempt_failed__init(attempt_failed);\n                    attempt_failed->attempts_remaining = resp_data.connecting_info.attempts_remaining;\n                    resp_payload->attempt_failed = attempt_failed;\n                }\n                resp_payload->status = STATUS__Success;\n            } else {\n                resp_payload->status = STATUS__InternalError;\n            }\n        } else {\n            resp_payload->status = STATUS__InternalError;\n        }\n#else // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        resp_payload->status = STATUS__InvalidArgument;\n#endif // !CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        resp->payload_case = NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_GET_WIFI_STATUS;\n        resp->resp_get_wifi_status = resp_payload;\n    } else if (req->msg == NETWORK_CONFIG_MSG_TYPE__TypeCmdGetThreadStatus) {\n        RespGetThreadStatus *resp_payload = (RespGetThreadStatus *) malloc(sizeof(RespGetThreadStatus));\n        if (!resp_payload) {\n            ESP_LOGE(TAG, \"Error allocating memory\");\n            return ESP_ERR_NO_MEM;\n        }\n        resp_get_thread_status__init(resp_payload);\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        network_prov_config_get_thread_data_t resp_data;\n        if (h->thread_get_status_handler) {\n            if (h->thread_get_status_handler(&resp_data, &h->ctx) == ESP_OK) {\n                if (resp_data.thread_state == NETWORK_PROV_THREAD_ATTACHING) {\n                    resp_payload->thread_state = THREAD_NETWORK_STATE__Attaching;\n                    resp_payload->state_case = RESP_GET_THREAD_STATUS__STATE_THREAD_ATTACHED;\n                } else if (resp_data.thread_state == NETWORK_PROV_THREAD_ATTACHED) {\n                    resp_payload->thread_state  = THREAD_NETWORK_STATE__Attached;\n                    resp_payload->state_case = RESP_GET_THREAD_STATUS__STATE_THREAD_ATTACHED;\n                    ThreadAttachState *attached = (ThreadAttachState *)malloc(sizeof(ThreadAttachState));\n                    if (!attached) {\n                        free(resp_payload);\n                        ESP_LOGE(TAG, \"Error allocating memory\");\n                        return ESP_ERR_NO_MEM;\n                    }\n                    resp_payload->thread_attached  = attached;\n                    thread_attach_state__init(attached);\n                    attached->channel = resp_data.conn_info.channel;\n                    attached->ext_pan_id.len = sizeof(resp_data.conn_info.ext_pan_id);\n                    attached->ext_pan_id.data = (uint8_t *)malloc(attached->ext_pan_id.len);\n                    if (!attached->ext_pan_id.data) {\n                        free(attached);\n                        free(resp_payload);\n                        return ESP_ERR_NO_MEM;\n                    }\n                    memcpy(attached->ext_pan_id.data, resp_data.conn_info.ext_pan_id, sizeof(resp_data.conn_info.ext_pan_id));\n                    attached->pan_id = resp_data.conn_info.pan_id;\n\n                    attached->name = (char *)malloc(sizeof(resp_data.conn_info.name));\n                    if (!attached->name) {\n                        free(attached->ext_pan_id.data);\n                        free(attached);\n                        free(resp_payload);\n                        return ESP_ERR_NO_MEM;\n                    }\n                    memcpy(attached->name, resp_data.conn_info.name, sizeof(resp_data.conn_info.name));\n                } else if (resp_data.thread_state == NETWORK_PROV_THREAD_DETACHED) {\n                    resp_payload->thread_state = THREAD_NETWORK_STATE__AttachingFailed;\n                    resp_payload->state_case = RESP_GET_THREAD_STATUS__STATE_THREAD_FAIL_REASON;\n\n                    if (resp_data.fail_reason == NETWORK_PROV_THREAD_DATASET_INVALID) {\n                        resp_payload->thread_fail_reason = THREAD_ATTACH_FAILED_REASON__DatasetInvalid;\n                    } else if (resp_data.fail_reason == NETWORK_PROV_THREAD_NETWORK_NOT_FOUND) {\n                        resp_payload->thread_fail_reason = THREAD_ATTACH_FAILED_REASON__ThreadNetworkNotFound;\n                    }\n                }\n                resp_payload->status = STATUS__Success;\n            } else {\n                resp_payload->status = STATUS__InternalError;\n            }\n        } else {\n            resp_payload->status = STATUS__InternalError;\n        }\n#else // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        resp_payload->status = STATUS__InvalidArgument;\n#endif // !CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        resp->payload_case = NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_GET_THREAD_STATUS;\n        resp->resp_get_thread_status = resp_payload;\n    }\n    return ESP_OK;\n}\n\nstatic esp_err_t cmd_set_config_handler(NetworkConfigPayload *req,\n                                        NetworkConfigPayload *resp, void  *priv_data)\n{\n    ESP_LOGD(TAG, \"Enter cmd_set_config_handler\");\n    network_prov_config_handlers_t *h = (network_prov_config_handlers_t *) priv_data;\n    if (!h) {\n        ESP_LOGE(TAG, \"Command invoked without handlers\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    if (req->msg == NETWORK_CONFIG_MSG_TYPE__TypeCmdSetWifiConfig) {\n        RespSetWifiConfig *resp_payload = (RespSetWifiConfig *) malloc(sizeof(RespSetWifiConfig));\n        if (resp_payload == NULL) {\n            ESP_LOGE(TAG, \"Error allocating memory\");\n            return ESP_ERR_NO_MEM;\n        }\n        resp_set_wifi_config__init(resp_payload);\n\n        if (req->payload_case != NETWORK_CONFIG_PAYLOAD__PAYLOAD_CMD_SET_WIFI_CONFIG || !req->cmd_set_wifi_config) {\n            ESP_LOGE(TAG, \"Invalid set WiFi config command\");\n            resp->resp_set_wifi_config = resp_payload;\n            return ESP_ERR_INVALID_ARG;\n        }\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        network_prov_config_set_wifi_data_t req_data;\n        memset(&req_data, 0, sizeof(req_data));\n\n        /* Check arguments provided in protobuf packet:\n         * - SSID / Passphrase string length must be within the standard limits\n         * - BSSID must either be NULL or have length equal to that imposed by the standard\n         * If any of these conditions are not satisfied, don't invoke the handler and\n         * send error status without closing connection */\n        resp_payload->status = STATUS__InvalidArgument;\n        if (req->cmd_set_wifi_config->bssid.len != 0 &&\n                req->cmd_set_wifi_config->bssid.len != sizeof(req_data.bssid)) {\n            ESP_LOGD(TAG, \"Received invalid BSSID\");\n        } else if (req->cmd_set_wifi_config->ssid.len >= sizeof(req_data.ssid)) {\n            ESP_LOGD(TAG, \"Received invalid SSID\");\n        } else if (req->cmd_set_wifi_config->passphrase.len >= sizeof(req_data.password)) {\n            ESP_LOGD(TAG, \"Received invalid Passphrase\");\n        } else {\n            /* The received SSID and Passphrase are not NULL terminated so\n             * we memcpy over zeroed out arrays. Above length checks ensure\n             * that there is at least 1 extra byte for null termination */\n            memcpy(req_data.ssid, req->cmd_set_wifi_config->ssid.data,\n                   req->cmd_set_wifi_config->ssid.len);\n            memcpy(req_data.password, req->cmd_set_wifi_config->passphrase.data,\n                   req->cmd_set_wifi_config->passphrase.len);\n            memcpy(req_data.bssid, req->cmd_set_wifi_config->bssid.data,\n                   req->cmd_set_wifi_config->bssid.len);\n            req_data.channel = req->cmd_set_wifi_config->channel;\n            if (h->wifi_set_config_handler(&req_data, &h->ctx) == ESP_OK) {\n                resp_payload->status = STATUS__Success;\n            } else {\n                resp_payload->status = STATUS__InternalError;\n            }\n        }\n#else // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        resp_payload->status = STATUS__InvalidArgument;\n#endif // !CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        resp->payload_case = NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_SET_WIFI_CONFIG;\n        resp->resp_set_wifi_config = resp_payload;\n    } else if (req->msg == NETWORK_CONFIG_MSG_TYPE__TypeCmdSetThreadConfig) {\n        RespSetThreadConfig *resp_payload = (RespSetThreadConfig *) malloc(sizeof(RespSetThreadConfig));\n        if (resp_payload == NULL) {\n            ESP_LOGE(TAG, \"Error allocating memory\");\n            return ESP_ERR_NO_MEM;\n        }\n        resp_set_thread_config__init(resp_payload);\n\n        if (req->payload_case != NETWORK_CONFIG_PAYLOAD__PAYLOAD_CMD_SET_THREAD_CONFIG || !req->cmd_set_thread_config) {\n            ESP_LOGE(TAG, \"Invalid set Thread config command\");\n            resp->resp_set_thread_config = resp_payload;\n            return ESP_ERR_INVALID_ARG;\n        }\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        network_prov_config_set_thread_data_t req_data;\n        memset(&req_data, 0, sizeof(req_data));\n        resp_payload->status = STATUS__InvalidArgument;\n        if (req->cmd_set_thread_config->dataset.len > sizeof(req_data.dataset)) {\n            ESP_LOGD(TAG, \"Received invalid dataset\");\n        } else {\n            memcpy(req_data.dataset, req->cmd_set_thread_config->dataset.data,\n                   req->cmd_set_thread_config->dataset.len);\n            req_data.length = req->cmd_set_thread_config->dataset.len;\n            if (h->thread_set_config_handler(&req_data, &h->ctx) == ESP_OK) {\n                resp_payload->status = STATUS__Success;\n            } else {\n                resp_payload->status = STATUS__InternalError;\n            }\n        }\n#else // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        resp_payload->status = STATUS__InvalidArgument;\n#endif // !CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        resp->payload_case = NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_SET_THREAD_CONFIG;\n        resp->resp_set_thread_config = resp_payload;\n    }\n    return ESP_OK;\n}\n\nstatic esp_err_t cmd_apply_config_handler(NetworkConfigPayload *req,\n        NetworkConfigPayload *resp, void  *priv_data)\n{\n    ESP_LOGD(TAG, \"Enter cmd_apply_config_handler\");\n    network_prov_config_handlers_t *h = (network_prov_config_handlers_t *) priv_data;\n    if (!h) {\n        ESP_LOGE(TAG, \"Command invoked without handlers\");\n        return ESP_ERR_INVALID_STATE;\n    }\n    if (req->msg == NETWORK_CONFIG_MSG_TYPE__TypeCmdApplyWifiConfig) {\n        RespApplyWifiConfig *resp_payload = (RespApplyWifiConfig *) malloc(sizeof(RespApplyWifiConfig));\n        if (!resp_payload) {\n            ESP_LOGE(TAG, \"Error allocating memory\");\n            return ESP_ERR_NO_MEM;\n        }\n        resp_apply_wifi_config__init(resp_payload);\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        if (h->wifi_apply_config_handler && h->wifi_apply_config_handler(&h->ctx) == ESP_OK) {\n            resp_payload->status = STATUS__Success;\n        } else {\n            resp_payload->status = STATUS__InternalError;\n        }\n#else // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        resp_payload->status = STATUS__InvalidArgument;\n#endif // !CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        resp->payload_case = NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_APPLY_WIFI_CONFIG;\n        resp->resp_apply_wifi_config = resp_payload;\n    } else if (req->msg == NETWORK_CONFIG_MSG_TYPE__TypeCmdApplyThreadConfig) {\n        RespApplyThreadConfig *resp_payload = (RespApplyThreadConfig *) malloc(sizeof(RespApplyThreadConfig));\n        if (!resp_payload) {\n            ESP_LOGE(TAG, \"Error allocating memory\");\n            return ESP_ERR_NO_MEM;\n        }\n        resp_apply_thread_config__init(resp_payload);\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        if (h->thread_apply_config_handler && h->thread_apply_config_handler(&h->ctx) == ESP_OK) {\n            resp_payload->status = STATUS__Success;\n        } else {\n            resp_payload->status = STATUS__InternalError;\n        }\n#else // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        resp_payload->status = STATUS__InvalidArgument;\n#endif // !CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        resp->payload_case = NETWORK_CONFIG_PAYLOAD__PAYLOAD_RESP_APPLY_THREAD_CONFIG;\n        resp->resp_apply_thread_config = resp_payload;\n    }\n    return ESP_OK;\n}\n\nstatic int lookup_cmd_handler(int cmd_id)\n{\n    for (size_t i = 0; i < sizeof(cmd_table) / sizeof(network_prov_config_cmd_t); i++) {\n        if (cmd_table[i].cmd_num == cmd_id) {\n            return i;\n        }\n    }\n\n    return -1;\n}\nstatic void network_prov_config_command_cleanup(NetworkConfigPayload *resp, void *priv_data)\n{\n    if (!resp) {\n        return;\n    }\n\n    switch (resp->msg) {\n    case NETWORK_CONFIG_MSG_TYPE__TypeRespGetWifiStatus: {\n        if (!resp->resp_get_wifi_status) {\n            break;\n        }\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        switch (resp->resp_get_wifi_status->wifi_sta_state) {\n        case WIFI_STATION_STATE__Connecting:\n            break;\n        case WIFI_STATION_STATE__Connected:\n            if (resp->resp_get_wifi_status->wifi_connected) {\n                if (resp->resp_get_wifi_status->wifi_connected->ip4_addr) {\n                    free(resp->resp_get_wifi_status->wifi_connected->ip4_addr);\n                }\n                if (resp->resp_get_wifi_status->wifi_connected->bssid.data) {\n                    free(resp->resp_get_wifi_status->wifi_connected->bssid.data);\n                }\n                if (resp->resp_get_wifi_status->wifi_connected->ssid.data) {\n                    free(resp->resp_get_wifi_status->wifi_connected->ssid.data);\n                }\n                free(resp->resp_get_wifi_status->wifi_connected);\n            }\n            break;\n        case WIFI_STATION_STATE__ConnectionFailed:\n            break;\n        default:\n            break;\n        }\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        free(resp->resp_get_wifi_status);\n    }\n    break;\n    case NETWORK_CONFIG_MSG_TYPE__TypeRespGetThreadStatus: {\n        if (!resp->resp_get_thread_status) {\n            break;\n        }\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        switch (resp->resp_get_thread_status->thread_state) {\n        case THREAD_NETWORK_STATE__Attaching:\n            break;\n        case THREAD_NETWORK_STATE__Attached:\n            if (resp->resp_get_thread_status->thread_attached) {\n                if (resp->resp_get_thread_status->thread_attached->name) {\n                    free(resp->resp_get_thread_status->thread_attached->name);\n                }\n                free(resp->resp_get_thread_status->thread_attached);\n            }\n            break;\n        case THREAD_NETWORK_STATE__AttachingFailed:\n            break;\n        default:\n            break;\n        }\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        free(resp->resp_get_thread_status);\n    }\n    break;\n    case NETWORK_CONFIG_MSG_TYPE__TypeRespSetWifiConfig: {\n        free(resp->resp_set_wifi_config);\n    }\n    break;\n    case NETWORK_CONFIG_MSG_TYPE__TypeRespSetThreadConfig: {\n        free(resp->resp_set_thread_config);\n    }\n    break;\n    case NETWORK_CONFIG_MSG_TYPE__TypeRespApplyWifiConfig: {\n        free(resp->resp_apply_wifi_config);\n    }\n    break;\n    case NETWORK_CONFIG_MSG_TYPE__TypeRespApplyThreadConfig: {\n        free(resp->resp_apply_thread_config);\n    }\n    break;\n    default:\n        ESP_LOGE(TAG, \"Unsupported response type in cleanup_handler\");\n        break;\n    }\n    return;\n}\n\nstatic esp_err_t network_prov_config_command_dispatcher(NetworkConfigPayload *req,\n        NetworkConfigPayload *resp, void *priv_data)\n{\n    esp_err_t ret;\n\n    ESP_LOGD(TAG, \"In network_prov_config_command_dispatcher Cmd=%d\", req->msg);\n\n    int cmd_index = lookup_cmd_handler(req->msg);\n    if (cmd_index < 0) {\n        ESP_LOGE(TAG, \"Invalid command handler lookup\");\n        return ESP_FAIL;\n    }\n\n    ret = cmd_table[cmd_index].command_handler(req, resp, priv_data);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Error executing command handler\");\n        return ESP_FAIL;\n    }\n\n    return ESP_OK;\n}\n\nesp_err_t network_prov_config_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,\n        uint8_t **outbuf, ssize_t *outlen, void *priv_data)\n{\n    NetworkConfigPayload *req;\n    NetworkConfigPayload resp;\n    esp_err_t ret;\n\n    req = network_config_payload__unpack(NULL, inlen, inbuf);\n    if (!req) {\n        ESP_LOGE(TAG, \"Unable to unpack config data\");\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    network_config_payload__init(&resp);\n    /* Validate req->msg before arithmetic to avoid signed overflow on attacker-controlled\n     * wire values. For unknown commands the dispatcher returns ESP_FAIL without calling\n     * any handler, so nothing is allocated and resp.msg = 0 is safe for cleanup. */\n    if (lookup_cmd_handler(req->msg) >= 0) {\n        resp.msg = req->msg + 1;\n    }\n    ret = network_prov_config_command_dispatcher(req, &resp, priv_data);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Proto command dispatcher error %d\", ret);\n        ret = ESP_FAIL;\n        goto exit;\n    }\n\n    *outlen = network_config_payload__get_packed_size(&resp);\n    if (*outlen <= 0) {\n        ESP_LOGE(TAG, \"Invalid encoding for response\");\n        ret = ESP_FAIL;\n        goto exit;\n    }\n\n    *outbuf = (uint8_t *) malloc(*outlen);\n    if (!*outbuf) {\n        ESP_LOGE(TAG, \"System out of memory\");\n        ret = ESP_ERR_NO_MEM;\n        goto exit;\n    }\n    network_config_payload__pack(&resp, *outbuf);\nexit:\n    network_config_payload__free_unpacked(req, NULL);\n    network_prov_config_command_cleanup(&resp, priv_data);\n    return ret;\n}\n"
  },
  {
    "path": "network_provisioning/src/network_ctrl.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <esp_log.h>\n#include <string.h>\n#include <esp_err.h>\n\n#include \"network_ctrl.pb-c.h\"\n\n#include \"network_ctrl.h\"\n\nstatic const char *TAG = \"proto_network_ctrl\";\n\ntypedef struct network_ctrl_cmd {\n    int cmd_id;\n    esp_err_t (*command_handler)(NetworkCtrlPayload *req,\n                                 NetworkCtrlPayload *resp, void *priv_data);\n} network_ctrl_cmd_t;\n\nstatic esp_err_t cmd_ctrl_reset_handler(NetworkCtrlPayload *req,\n                                        NetworkCtrlPayload *resp,\n                                        void *priv_data);\n\nstatic esp_err_t cmd_ctrl_reprov_handler(NetworkCtrlPayload *req,\n        NetworkCtrlPayload *resp,\n        void *priv_data);\n\nstatic network_ctrl_cmd_t cmd_table[] = {\n    {\n        .cmd_id = NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlWifiReset,\n        .command_handler = cmd_ctrl_reset_handler\n    },\n    {\n        .cmd_id = NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlThreadReset,\n        .command_handler = cmd_ctrl_reset_handler\n    },\n    {\n        .cmd_id = NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlWifiReprov,\n        .command_handler = cmd_ctrl_reprov_handler\n    },\n    {\n        .cmd_id = NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlThreadReprov,\n        .command_handler = cmd_ctrl_reprov_handler\n    },\n};\n\nstatic esp_err_t cmd_ctrl_reset_handler(NetworkCtrlPayload *req,\n                                        NetworkCtrlPayload *resp, void *priv_data)\n{\n    network_ctrl_handlers_t *h = (network_ctrl_handlers_t *) priv_data;\n    if (!h) {\n        ESP_LOGE(TAG, \"Command invoked without handlers\");\n        return ESP_ERR_INVALID_STATE;\n    }\n    if (req->msg == NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlWifiReset) {\n        RespCtrlWifiReset *resp_payload = (RespCtrlWifiReset *) malloc(sizeof(RespCtrlWifiReset));\n        if (!resp_payload) {\n            ESP_LOGE(TAG, \"Error allocating memory\");\n            return ESP_ERR_NO_MEM;\n        }\n        resp_ctrl_wifi_reset__init(resp_payload);\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        if (h->wifi_ctrl_reset) {\n            resp->status = (h->wifi_ctrl_reset() == ESP_OK ? STATUS__Success : STATUS__InternalError);\n        } else {\n            resp->status = STATUS__InternalError;\n        }\n#else\n        resp->status = STATUS__InvalidArgument;\n#endif\n        resp->payload_case = NETWORK_CTRL_PAYLOAD__PAYLOAD_RESP_CTRL_WIFI_RESET;\n        resp->resp_ctrl_wifi_reset = resp_payload;\n    } else if (req->msg == NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlThreadReset) {\n        RespCtrlThreadReset *resp_payload = (RespCtrlThreadReset *) malloc(sizeof(RespCtrlThreadReset));\n        if (!resp_payload) {\n            ESP_LOGE(TAG, \"Error allocating memory\");\n            return ESP_ERR_NO_MEM;\n        }\n        resp_ctrl_thread_reset__init(resp_payload);\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        if (h->thread_ctrl_reset) {\n            resp->status = (h->thread_ctrl_reset() == ESP_OK ? STATUS__Success : STATUS__InternalError);\n        } else {\n            resp->status = STATUS__InternalError;\n        }\n#else\n        resp->status = STATUS__InvalidArgument;\n#endif\n        resp->payload_case = NETWORK_CTRL_PAYLOAD__PAYLOAD_RESP_CTRL_THREAD_RESET;\n        resp->resp_ctrl_thread_reset = resp_payload;\n    }\n    return ESP_OK;\n}\n\nstatic esp_err_t cmd_ctrl_reprov_handler(NetworkCtrlPayload *req,\n        NetworkCtrlPayload *resp, void *priv_data)\n{\n    network_ctrl_handlers_t *h = (network_ctrl_handlers_t *) priv_data;\n    if (!h) {\n        ESP_LOGE(TAG, \"Command invoked without handlers\");\n        return ESP_ERR_INVALID_STATE;\n    }\n    if (req->msg == NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlWifiReprov) {\n        RespCtrlWifiReprov *resp_payload = (RespCtrlWifiReprov *) malloc(sizeof(RespCtrlWifiReprov));\n        if (!resp_payload) {\n            ESP_LOGE(TAG, \"Error allocating memory\");\n            return ESP_ERR_NO_MEM;\n        }\n        resp_ctrl_wifi_reprov__init(resp_payload);\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        if (h->wifi_ctrl_reprov) {\n            resp->status = (h->wifi_ctrl_reprov() == ESP_OK ? STATUS__Success : STATUS__InternalError);\n        } else {\n            resp->status = STATUS__InternalError;\n        }\n#else\n        resp->status = STATUS__InvalidArgument;\n#endif\n        resp->payload_case = NETWORK_CTRL_PAYLOAD__PAYLOAD_RESP_CTRL_WIFI_REPROV;\n        resp->resp_ctrl_wifi_reprov = resp_payload;\n    } else if (req->msg == NETWORK_CTRL_MSG_TYPE__TypeCmdCtrlThreadReprov) {\n        RespCtrlThreadReprov *resp_payload = (RespCtrlThreadReprov *) malloc(sizeof(RespCtrlThreadReprov));\n        if (!resp_payload) {\n            ESP_LOGE(TAG, \"Error allocating memory\");\n            return ESP_ERR_NO_MEM;\n        }\n        resp_ctrl_thread_reprov__init(resp_payload);\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        if (h->thread_ctrl_reprov) {\n            resp->status = (h->thread_ctrl_reprov() == ESP_OK ? STATUS__Success : STATUS__InternalError);\n        } else {\n            resp->status = STATUS__InternalError;\n        }\n#else\n        resp->status = STATUS__InvalidArgument;\n#endif\n        resp->payload_case = NETWORK_CTRL_PAYLOAD__PAYLOAD_RESP_CTRL_THREAD_REPROV;\n        resp->resp_ctrl_thread_reprov = resp_payload;\n    }\n    return ESP_OK;\n}\n\nstatic int lookup_cmd_handler(int cmd_id)\n{\n    for (size_t i = 0; i < sizeof(cmd_table) / sizeof(network_ctrl_cmd_t); i++) {\n        if (cmd_table[i].cmd_id == cmd_id) {\n            return i;\n        }\n    }\n\n    return -1;\n}\n\nstatic void network_ctrl_cmd_cleanup(NetworkCtrlPayload *resp, void *priv_data)\n{\n    switch (resp->msg) {\n    case NETWORK_CTRL_MSG_TYPE__TypeRespCtrlWifiReset: {\n        free(resp->resp_ctrl_wifi_reset);\n    }\n    break;\n    case NETWORK_CTRL_MSG_TYPE__TypeRespCtrlWifiReprov: {\n        free(resp->resp_ctrl_wifi_reprov);\n    }\n    break;\n    case NETWORK_CTRL_MSG_TYPE__TypeRespCtrlThreadReset: {\n        free(resp->resp_ctrl_thread_reset);\n    }\n    break;\n    case NETWORK_CTRL_MSG_TYPE__TypeRespCtrlThreadReprov: {\n        free(resp->resp_ctrl_thread_reprov);\n    }\n    break;\n    default:\n        ESP_LOGE(TAG, \"Unsupported response type in cleanup_handler\");\n        break;\n    }\n    return;\n}\n\nstatic esp_err_t network_ctrl_cmd_dispatcher(NetworkCtrlPayload *req,\n        NetworkCtrlPayload *resp, void *priv_data)\n{\n    esp_err_t ret;\n\n    ESP_LOGD(TAG, \"In network_ctrl_cmd_dispatcher Cmd=%d\", req->msg);\n\n    int cmd_index = lookup_cmd_handler(req->msg);\n    if (cmd_index < 0) {\n        ESP_LOGE(TAG, \"Failed to find cmd with ID = %d in the command table\", req->msg);\n        return ESP_FAIL;\n    }\n\n    ret = cmd_table[cmd_index].command_handler(req, resp, priv_data);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Error executing command handler\");\n    }\n\n    return ret;\n}\n\nesp_err_t network_ctrl_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,\n                               uint8_t **outbuf, ssize_t *outlen, void *priv_data)\n{\n    NetworkCtrlPayload *req;\n    NetworkCtrlPayload resp;\n    esp_err_t ret = ESP_OK;\n\n    req = network_ctrl_payload__unpack(NULL, inlen, inbuf);\n    if (!req) {\n        ESP_LOGE(TAG, \"Unable to unpack ctrl message\");\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    network_ctrl_payload__init(&resp);\n    ret = network_ctrl_cmd_dispatcher(req, &resp, priv_data);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Command dispatcher error %02X\", ret);\n        ret = ESP_FAIL;\n        goto exit;\n    }\n\n    resp.msg = req->msg + 1; /* Response is request + 1 */\n    *outlen = network_ctrl_payload__get_packed_size(&resp);\n    if (*outlen <= 0) {\n        ESP_LOGE(TAG, \"Invalid encoding for response\");\n        ret = ESP_FAIL;\n        goto exit;\n    }\n\n    *outbuf = (uint8_t *) malloc(*outlen);\n    if (!*outbuf) {\n        ESP_LOGE(TAG, \"Failed to allocate memory for the output buffer\");\n        ret = ESP_ERR_NO_MEM;\n        goto exit;\n    }\n    network_ctrl_payload__pack(&resp, *outbuf);\n    ESP_LOGD(TAG, \"Response packet size : %d\", *outlen);\nexit:\n\n    network_ctrl_payload__free_unpacked(req, NULL);\n    network_ctrl_cmd_cleanup(&resp, priv_data);\n    return ret;\n}\n"
  },
  {
    "path": "network_provisioning/src/network_ctrl.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#ifndef _PROV_NETWORK_CTRL_H_\n#define _PROV_NETWORK_CTRL_H_\n\n#include <esp_err.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief   Internal handlers for receiving and responding to protocomm\n *          requests from client\n *\n * This is to be passed as priv_data for protocomm request handler\n * (refer to `network_ctrl_handler()`) when calling `protocomm_add_endpoint()`.\n */\ntypedef struct network_ctrl_handlers {\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    /**\n     * Handler functions called when ctrl reset command is received\n     */\n    esp_err_t (*wifi_ctrl_reset)(void);\n\n    /**\n     * Handler functions called when ctrl reprov command is received\n     */\n    esp_err_t (*wifi_ctrl_reprov)(void);\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    esp_err_t (*thread_ctrl_reset)(void);\n    esp_err_t (*thread_ctrl_reprov)(void);\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n} network_ctrl_handlers_t;\n\n/**\n * @brief   Handler for sending on demand network ctrl results\n *\n * This is to be registered as the `prov-ctrl` endpoint handler\n * (protocomm `protocomm_req_handler_t`) using `protocomm_add_endpoint()`\n */\nesp_err_t network_ctrl_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,\n                               uint8_t **outbuf, ssize_t *outlen, void *priv_data);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "network_provisioning/src/network_provisioning_priv.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include <protocomm.h>\n#include <protocomm_security.h>\n\n#include \"network_provisioning/manager.h\"\n#include \"network_provisioning/network_config.h\"\n#include \"network_provisioning/network_scan.h\"\n#include \"network_ctrl.h\"\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n#include \"openthread/link.h\"\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n\n/**\n * @brief   Notify manager that provisioning is done\n *\n * Stops the provisioning. This is called by the get_status_handler()\n * when the status is connected. This has no effect if main application\n * has disabled auto stop on completion by calling\n * network_prov_mgr_disable_auto_stop()\n *\n * @return\n *  - ESP_OK      : Provisioning will be stopped\n *  - ESP_FAIL    : Failed to stop provisioning\n */\nesp_err_t network_prov_mgr_done(void);\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n/**\n * @brief   Start Wi-Fi AP Scan\n *\n * @param[in] blocking        Set true to return only after scanning is complete\n * @param[in] passive         Set true to perform passive scan instead of default active scan\n * @param[in] group_channels  Number of channels to scan in one go\n *                            (set to 0 for scanning all channels in one go)\n * @param[in] period_ms       Scan time (in milli-seconds) on each channel\n *\n * @return\n *  - ESP_OK    : Successfully started Wi-Fi scanning\n *  - ESP_FAIL  : Provisioning app not running\n */\nesp_err_t network_prov_mgr_wifi_scan_start(bool blocking, bool passive,\n        uint8_t group_channels,\n        uint32_t period_ms);\n\n/**\n * @brief   Use to query the state of Wi-Fi scan\n *\n * @return\n *  - true   : Scan finished\n *  - false  : Scan running\n */\nbool network_prov_mgr_wifi_scan_finished(void);\n\n/**\n * @brief   Get the count of results in the scan list\n *\n * @return\n *  - count  : Number of Wi-Fi Access Points detected while scanning\n */\nuint16_t network_prov_mgr_wifi_scan_result_count(void);\n\n/**\n * @brief   Get AP record for a particular index in the scan list result\n *\n * @param[out] index  Index of the result to fetch\n *\n * @return\n *  - result : Pointer to Access Point record\n */\nconst wifi_ap_record_t *network_prov_mgr_wifi_scan_result(uint16_t index);\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n/**\n * @brief   Start Thread network Scan\n *\n * @param[in] blocking        Set true to return only after scanning is complete\n *\n * @return\n *  - ESP_OK    : Successfully started Thread scanning\n *  - ESP_FAIL  : Provisioning app not running\n */\nesp_err_t network_prov_mgr_thread_scan_start(bool blocking, uint32_t channel_mask);\n\n/**\n * @brief   Use to query the state of Thread scan\n *\n * @return\n *  - true   : Scan finished\n *  - false  : Scan running\n */\nbool network_prov_mgr_thread_scan_finished(void);\n\n/**\n * @brief   Get the count of results in the scan list\n *\n * @return\n *  - count  : Number of Thread networks detected while scanning\n */\nuint16_t network_prov_mgr_thread_scan_result_count(void);\n\n/**\n * @brief   Get Thread network record for a particular index in the scan list result\n *\n * @param[out] index  Index of the result to fetch\n *\n * @return\n *  - result : Pointer to Thread network record\n */\nconst otActiveScanResult *network_prov_mgr_thread_scan_result(uint16_t index);\n\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n\n/**\n * @brief   Get protocomm handlers for network_config provisioning endpoint\n *\n * @param[out] ptr   pointer to structure to be set\n *\n * @return\n *  - ESP_OK   : success\n *  - ESP_ERR_INVALID_ARG : null argument\n */\nesp_err_t get_network_prov_handlers(network_prov_config_handlers_t *ptr);\n\n/**\n * @brief   Get protocomm handlers for network_scan provisioning endpoint\n *\n * @param[out] ptr   pointer to structure to be set\n *\n * @return\n *  - ESP_OK   : success\n *  - ESP_ERR_INVALID_ARG : null argument\n */\nesp_err_t get_network_scan_handlers(network_prov_scan_handlers_t *ptr);\n\n/**\n * @brief   Get protocomm handlers for network_ctrl provisioning endpoint\n *\n * @param[in] ptr   pointer to structure to be set\n *\n * @return\n *  - ESP_OK   : success\n *  - ESP_ERR_INVALID_ARG : null argument\n */\nesp_err_t get_network_ctrl_handlers(network_ctrl_handlers_t *ptr);\n\n/**\n * @brief Retrieve the remaining number of Wi-Fi connection attempts\n *\n * This function provides the number of Wi-Fi connection attempts left for\n * the network provisioning manager before reaching the maximum retry limit.\n *\n * @param[out] attempts_remaining Pointer to store the remaining connection attempts\n *\n * @return\n *      - ESP_OK: Success\n *      - ESP_ERR_INVALID_ARG: Null pointer provided for attempts_remaining\n *      - ESP_FAIL: Failed to retrieve the remaining attempts\n */\nesp_err_t network_prov_mgr_get_wifi_remaining_conn_attempts(uint32_t *attempts_remaining);\n"
  },
  {
    "path": "network_provisioning/src/network_scan.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <esp_log.h>\n#include <string.h>\n#include <esp_err.h>\n#include <esp_wifi.h>\n\n#include \"network_scan.pb-c.h\"\n\n#include <network_provisioning/network_scan.h>\n\nstatic const char *TAG = \"proto_network_scan\";\n\ntypedef struct network_prov_scan_cmd {\n    int cmd_num;\n    esp_err_t (*command_handler)(NetworkScanPayload *req,\n                                 NetworkScanPayload *resp, void *priv_data);\n} network_prov_scan_cmd_t;\n\nstatic esp_err_t cmd_scan_start_handler(NetworkScanPayload *req,\n                                        NetworkScanPayload *resp,\n                                        void *priv_data);\n\nstatic esp_err_t cmd_scan_status_handler(NetworkScanPayload *req,\n        NetworkScanPayload *resp,\n        void *priv_data);\n\nstatic esp_err_t cmd_scan_result_handler(NetworkScanPayload *req,\n        NetworkScanPayload *resp,\n        void *priv_data);\n\nstatic network_prov_scan_cmd_t cmd_table[] = {\n    {\n        .cmd_num = NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiStart,\n        .command_handler = cmd_scan_start_handler\n    },\n    {\n        .cmd_num = NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiStatus,\n        .command_handler = cmd_scan_status_handler\n    },\n    {\n        .cmd_num = NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiResult,\n        .command_handler = cmd_scan_result_handler\n    },\n    {\n        .cmd_num = NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadStart,\n        .command_handler = cmd_scan_start_handler\n    },\n    {\n        .cmd_num = NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadStatus,\n        .command_handler = cmd_scan_status_handler\n    },\n    {\n        .cmd_num = NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadResult,\n        .command_handler = cmd_scan_result_handler\n    }\n};\n\nstatic esp_err_t cmd_scan_start_handler(NetworkScanPayload *req,\n                                        NetworkScanPayload *resp, void *priv_data)\n{\n    network_prov_scan_handlers_t *h = (network_prov_scan_handlers_t *) priv_data;\n    if (!h) {\n        ESP_LOGE(TAG, \"Command invoked without handlers\");\n        return ESP_ERR_INVALID_STATE;\n    }\n    if (req->msg == NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiStart) {\n        RespScanWifiStart *resp_payload = (RespScanWifiStart *) malloc(sizeof(RespScanWifiStart));\n        if (!resp_payload) {\n            ESP_LOGE(TAG, \"Error allocating memory\");\n            return ESP_ERR_NO_MEM;\n        }\n        resp_scan_wifi_start__init(resp_payload);\n\n        if (req->payload_case != NETWORK_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_WIFI_START || !req->cmd_scan_wifi_start) {\n            ESP_LOGE(TAG, \"Invalid WiFi scan start command\");\n            resp->resp_scan_wifi_start = resp_payload;\n            return ESP_ERR_INVALID_ARG;\n        }\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        if (h->wifi_scan_start) {\n            resp->status = (h->wifi_scan_start(req->cmd_scan_wifi_start->blocking,\n                                               req->cmd_scan_wifi_start->passive,\n                                               req->cmd_scan_wifi_start->group_channels,\n                                               req->cmd_scan_wifi_start->period_ms,\n                                               &h->ctx) == ESP_OK ? STATUS__Success : STATUS__InternalError);\n        } else {\n            resp->status = STATUS__InternalError;\n        }\n#else\n        resp->status = STATUS__InvalidArgument;\n#endif\n        resp->payload_case = NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_WIFI_START;\n        resp->resp_scan_wifi_start = resp_payload;\n    } else if (req->msg == NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadStart) {\n        RespScanThreadStart *resp_payload = (RespScanThreadStart *) malloc(sizeof(RespScanThreadStart));\n        if (!resp_payload) {\n            ESP_LOGE(TAG, \"Error allocating memory\");\n            return ESP_ERR_NO_MEM;\n        }\n        resp_scan_thread_start__init(resp_payload);\n\n        if (req->payload_case != NETWORK_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_THREAD_START || !req->cmd_scan_thread_start) {\n            ESP_LOGE(TAG, \"Invalid Thread scan start command\");\n            resp->resp_scan_thread_start = resp_payload;\n            return ESP_ERR_INVALID_ARG;\n        }\n\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        if (h->thread_scan_start) {\n            resp->status = (h->thread_scan_start(req->cmd_scan_thread_start->blocking,\n                                                 req->cmd_scan_thread_start->channel_mask,\n                                                 &h->ctx) == ESP_OK ? STATUS__Success : STATUS__InternalError);\n        } else {\n            resp->status = STATUS__InternalError;\n        }\n#else\n        resp->status = STATUS__InvalidArgument;\n#endif\n        resp->payload_case = NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_THREAD_START;\n        resp->resp_scan_thread_start = resp_payload;\n    }\n    return ESP_OK;\n}\n\nstatic esp_err_t cmd_scan_status_handler(NetworkScanPayload *req,\n        NetworkScanPayload *resp, void *priv_data)\n{\n    bool scan_finished = false;\n    uint16_t result_count = 0;\n\n    network_prov_scan_handlers_t *h = (network_prov_scan_handlers_t *) priv_data;\n    if (!h) {\n        ESP_LOGE(TAG, \"Command invoked without handlers\");\n        return ESP_ERR_INVALID_STATE;\n    }\n    if (req->msg == NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiStatus) {\n        RespScanWifiStatus *resp_payload = (RespScanWifiStatus *) malloc(sizeof(RespScanWifiStatus));\n        if (!resp_payload) {\n            ESP_LOGE(TAG, \"Error allocating memory\");\n            return ESP_ERR_NO_MEM;\n        }\n        resp_scan_wifi_status__init(resp_payload);\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        if (h->wifi_scan_status) {\n            resp->status = (h->wifi_scan_status(&scan_finished, &result_count, &h->ctx) == ESP_OK ?\n                            STATUS__Success : STATUS__InternalError);\n        } else {\n            resp->status = STATUS__InternalError;\n        }\n#else\n        resp->status = STATUS__InvalidArgument;\n#endif\n        resp_payload->scan_finished = scan_finished;\n        resp_payload->result_count = result_count;\n        resp->payload_case = NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_WIFI_STATUS;\n        resp->resp_scan_wifi_status = resp_payload;\n    } else if (req->msg == NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadStatus) {\n        RespScanThreadStatus *resp_payload = (RespScanThreadStatus *) malloc(sizeof(RespScanThreadStatus));\n        if (!resp_payload) {\n            ESP_LOGE(TAG, \"Error allocating memory\");\n            return ESP_ERR_NO_MEM;\n        }\n        resp_scan_thread_status__init(resp_payload);\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        if (h->thread_scan_status) {\n            resp->status = (h->thread_scan_status(&scan_finished, &result_count, &h->ctx) == ESP_OK ?\n                            STATUS__Success : STATUS__InternalError);\n        } else {\n            resp->status = STATUS__InternalError;\n        }\n#else\n        resp->status = STATUS__InvalidArgument;\n#endif\n        resp_payload->scan_finished = scan_finished;\n        resp_payload->result_count = result_count;\n        resp->payload_case = NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_THREAD_STATUS;\n        resp->resp_scan_thread_status = resp_payload;\n    }\n    return ESP_OK;\n}\n\nstatic esp_err_t cmd_scan_result_handler(NetworkScanPayload *req,\n        NetworkScanPayload *resp, void *priv_data)\n{\n    esp_err_t err = ESP_OK;\n    network_prov_scan_handlers_t *h = (network_prov_scan_handlers_t *) priv_data;\n    if (!h) {\n        ESP_LOGE(TAG, \"Command invoked without handlers\");\n        return ESP_ERR_INVALID_STATE;\n    }\n    if (req->msg == NETWORK_SCAN_MSG_TYPE__TypeCmdScanWifiResult) {\n        RespScanWifiResult *resp_payload = (RespScanWifiResult *) malloc(sizeof(RespScanWifiResult));\n        if (!resp_payload) {\n            ESP_LOGE(TAG, \"Error allocating memory\");\n            return ESP_ERR_NO_MEM;\n        }\n        resp_scan_wifi_result__init(resp_payload);\n\n        if (req->payload_case != NETWORK_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_WIFI_RESULT || !req->cmd_scan_wifi_result) {\n            ESP_LOGE(TAG, \"Invalid WiFi scan result command\");\n            resp->resp_scan_wifi_result = resp_payload;\n            return ESP_ERR_INVALID_ARG;\n        }\n\n        if (req->cmd_scan_wifi_result->start_index >= CONFIG_NETWORK_PROV_SCAN_MAX_ENTRIES ||\n                req->cmd_scan_wifi_result->count >\n                CONFIG_NETWORK_PROV_SCAN_MAX_ENTRIES - req->cmd_scan_wifi_result->start_index) {\n            ESP_LOGE(TAG, \"WiFi scan result count/start_index out of bounds\");\n            resp->resp_scan_wifi_result = resp_payload;\n            return ESP_ERR_INVALID_ARG;\n        }\n\n        resp->status = STATUS__Success;\n        resp->payload_case = NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_WIFI_RESULT;\n        resp->resp_scan_wifi_result = resp_payload;\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        network_prov_scan_wifi_result_t scan_result = {{0}, {0}, 0, 0, 0};\n        WiFiScanResult **results = NULL;\n\n        /* Allocate memory only if there are non-zero scan results */\n        if (req->cmd_scan_wifi_result->count) {\n            results = (WiFiScanResult **) calloc(req->cmd_scan_wifi_result->count,\n                                                 sizeof(WiFiScanResult *));\n            if (!results) {\n                ESP_LOGE(TAG, \"Failed to allocate memory for results array\");\n                return ESP_ERR_NO_MEM;\n            }\n        }\n        resp_payload->entries = results;\n        resp_payload->n_entries = req->cmd_scan_wifi_result->count;\n\n        /* If req->cmd_scan_wifi_result->count is 0, the below loop will\n        * be skipped.\n        */\n        for (uint32_t i = 0; i < req->cmd_scan_wifi_result->count; i++) {\n            if (!h->wifi_scan_result) {\n                resp_payload->n_entries = i;\n                resp->status = STATUS__InternalError;\n                break;\n            }\n            /* start_index and count are validated above to sum to at most\n             * CONFIG_NETWORK_PROV_SCAN_MAX_ENTRIES (max 255), so this cast is safe. */\n            uint16_t result_index = (uint16_t)(i + req->cmd_scan_wifi_result->start_index);\n            err = h->wifi_scan_result(result_index, &scan_result, &h->ctx);\n            if (err != ESP_OK) {\n                resp_payload->n_entries = i;\n                resp->status = STATUS__InternalError;\n                break;\n            }\n\n            results[i] = (WiFiScanResult *) malloc(sizeof(WiFiScanResult));\n            if (!results[i]) {\n                ESP_LOGE(TAG, \"Failed to allocate memory for result entry\");\n                resp_payload->n_entries = i;\n                resp->status = STATUS__InternalError;\n                return ESP_ERR_NO_MEM;\n            }\n            wi_fi_scan_result__init(results[i]);\n\n            results[i]->ssid.len = strnlen(scan_result.ssid, 32);\n            results[i]->ssid.data = (uint8_t *) strndup(scan_result.ssid, 32);\n            if (!results[i]->ssid.data) {\n                ESP_LOGE(TAG, \"Failed to allocate memory for scan result entry SSID\");\n                results[i]->ssid.len = 0;\n                resp_payload->n_entries = i + 1;\n                resp->status = STATUS__InternalError;\n                return ESP_ERR_NO_MEM;\n            }\n\n            results[i]->channel = scan_result.channel;\n            results[i]->rssi = scan_result.rssi;\n            results[i]->auth = scan_result.auth;\n\n            results[i]->bssid.len = sizeof(scan_result.bssid);\n            results[i]->bssid.data = malloc(results[i]->bssid.len);\n            if (!results[i]->bssid.data) {\n                ESP_LOGE(TAG, \"Failed to allocate memory for scan result entry BSSID\");\n                results[i]->bssid.len = 0;\n                resp_payload->n_entries = i + 1;\n                resp->status = STATUS__InternalError;\n                return ESP_ERR_NO_MEM;\n            }\n            memcpy(results[i]->bssid.data, scan_result.bssid, results[i]->bssid.len);\n        }\n#else // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        resp->status = STATUS__InvalidArgument;\n#endif // !CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    } else if (req->msg == NETWORK_SCAN_MSG_TYPE__TypeCmdScanThreadResult) {\n        RespScanThreadResult *resp_payload = (RespScanThreadResult *) malloc(sizeof(RespScanThreadResult));\n        if (!resp_payload) {\n            ESP_LOGE(TAG, \"Error allocating memory\");\n            return ESP_ERR_NO_MEM;\n        }\n        resp_scan_thread_result__init(resp_payload);\n\n        if (req->payload_case != NETWORK_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_THREAD_RESULT || !req->cmd_scan_thread_result) {\n            ESP_LOGE(TAG, \"Invalid Thread scan result command\");\n            resp->resp_scan_thread_result = resp_payload;\n            return ESP_ERR_INVALID_ARG;\n        }\n\n        if (req->cmd_scan_thread_result->start_index >= CONFIG_NETWORK_PROV_SCAN_MAX_ENTRIES ||\n                req->cmd_scan_thread_result->count >\n                CONFIG_NETWORK_PROV_SCAN_MAX_ENTRIES - req->cmd_scan_thread_result->start_index) {\n            ESP_LOGE(TAG, \"Thread scan result count/start_index out of bounds\");\n            resp->resp_scan_thread_result = resp_payload;\n            return ESP_ERR_INVALID_ARG;\n        }\n\n        resp->status = STATUS__Success;\n        resp->payload_case = NETWORK_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_THREAD_RESULT;\n        resp->resp_scan_thread_result = resp_payload;\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        network_prov_scan_thread_result_t scan_result;\n        memset(&scan_result, 0, sizeof(scan_result));\n        ThreadScanResult **results = NULL;\n\n        /* Allocate memory only if there are non-zero scan results */\n        if (req->cmd_scan_thread_result->count) {\n            results = (ThreadScanResult **) calloc(req->cmd_scan_thread_result->count,\n                                                   sizeof(ThreadScanResult *));\n            if (!results) {\n                ESP_LOGE(TAG, \"Failed to allocate memory for results array\");\n                return ESP_ERR_NO_MEM;\n            }\n        }\n        resp_payload->entries = results;\n        resp_payload->n_entries = req->cmd_scan_thread_result->count;\n\n        /* If req->cmd_scan_result->count is 0, the below loop will\n        * be skipped.\n        */\n        for (uint32_t i = 0; i < req->cmd_scan_thread_result->count; i++) {\n            if (!h->thread_scan_result) {\n                resp_payload->n_entries = i;\n                resp->status = STATUS__InternalError;\n                break;\n            }\n            /* start_index and count are validated above to sum to at most\n             * CONFIG_NETWORK_PROV_SCAN_MAX_ENTRIES (max 255), so this cast is safe. */\n            uint16_t result_index = (uint16_t)(i + req->cmd_scan_thread_result->start_index);\n            err = h->thread_scan_result(result_index, &scan_result, &h->ctx);\n            if (err != ESP_OK) {\n                resp_payload->n_entries = i;\n                resp->status = STATUS__InternalError;\n                break;\n            }\n\n            results[i] = (ThreadScanResult *) malloc(sizeof(ThreadScanResult));\n            if (!results[i]) {\n                ESP_LOGE(TAG, \"Failed to allocate memory for result entry\");\n                resp_payload->n_entries = i;\n                resp->status = STATUS__InternalError;\n                return ESP_ERR_NO_MEM;\n            }\n            thread_scan_result__init(results[i]);\n            results[i]->pan_id = scan_result.pan_id;\n            results[i]->channel = scan_result.channel;\n            results[i]->rssi = scan_result.rssi;\n            results[i]->lqi = scan_result.lqi;\n\n            results[i]->ext_addr.len = sizeof(scan_result.ext_addr);\n            results[i]->ext_addr.data = (uint8_t *)malloc(results[i]->ext_addr.len);\n            if (!results[i]->ext_addr.data) {\n                ESP_LOGE(TAG, \"Failed to allocate memory for scan result entry extended address\");\n                results[i]->ext_addr.len = 0;\n                resp_payload->n_entries = i + 1;\n                resp->status = STATUS__InternalError;\n                return ESP_ERR_NO_MEM;\n            }\n            memcpy(results[i]->ext_addr.data, scan_result.ext_addr, results[i]->ext_addr.len);\n\n            results[i]->ext_pan_id.len = sizeof(scan_result.ext_pan_id);\n            results[i]->ext_pan_id.data = (uint8_t *)malloc(results[i]->ext_pan_id.len);\n            if (!results[i]->ext_pan_id.data) {\n                ESP_LOGE(TAG, \"Failed to allocate memory for scan result entry extended PAN ID\");\n                results[i]->ext_pan_id.len = 0;\n                resp_payload->n_entries = i + 1;\n                resp->status = STATUS__InternalError;\n                return ESP_ERR_NO_MEM;\n            }\n            memcpy(results[i]->ext_pan_id.data, scan_result.ext_pan_id, results[i]->ext_pan_id.len);\n\n            results[i]->network_name = (char *)malloc(sizeof(scan_result.network_name));\n            if (!results[i]->network_name) {\n                ESP_LOGE(TAG, \"Failed to allocate memory for scan result entry network name\");\n                resp_payload->n_entries = i + 1;\n                resp->status = STATUS__InternalError;\n                return ESP_ERR_NO_MEM;\n            }\n            memcpy(results[i]->network_name, scan_result.network_name, sizeof(scan_result.network_name));\n        }\n#else // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        resp->status = STATUS__InvalidArgument;\n        err = ESP_ERR_INVALID_ARG;\n#endif // !CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n    }\n    return err;\n}\n\n\nstatic int lookup_cmd_handler(int cmd_id)\n{\n    for (size_t i = 0; i < sizeof(cmd_table) / sizeof(network_prov_scan_cmd_t); i++) {\n        if (cmd_table[i].cmd_num == cmd_id) {\n            return i;\n        }\n    }\n\n    return -1;\n}\n\nstatic void network_prov_scan_cmd_cleanup(NetworkScanPayload *resp, void *priv_data)\n{\n    switch (resp->msg) {\n    case NETWORK_SCAN_MSG_TYPE__TypeRespScanWifiStart: {\n        free(resp->resp_scan_wifi_start);\n    }\n    break;\n    case NETWORK_SCAN_MSG_TYPE__TypeRespScanThreadStart: {\n        free(resp->resp_scan_thread_start);\n    }\n    break;\n    case NETWORK_SCAN_MSG_TYPE__TypeRespScanWifiStatus: {\n        free(resp->resp_scan_wifi_status);\n    }\n    break;\n    case NETWORK_SCAN_MSG_TYPE__TypeRespScanThreadStatus: {\n        free(resp->resp_scan_thread_status);\n    }\n    break;\n\n    case NETWORK_SCAN_MSG_TYPE__TypeRespScanWifiResult: {\n        if (!resp->resp_scan_wifi_result) {\n            return;\n        }\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        if (resp->resp_scan_wifi_result->entries) {\n            for (uint32_t i = 0; i < resp->resp_scan_wifi_result->n_entries; i++) {\n                if (!resp->resp_scan_wifi_result->entries[i]) {\n                    continue;\n                }\n                free(resp->resp_scan_wifi_result->entries[i]->ssid.data);\n                free(resp->resp_scan_wifi_result->entries[i]->bssid.data);\n                free(resp->resp_scan_wifi_result->entries[i]);\n            }\n            free(resp->resp_scan_wifi_result->entries);\n        }\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n        free(resp->resp_scan_wifi_result);\n    }\n    break;\n    case NETWORK_SCAN_MSG_TYPE__TypeRespScanThreadResult: {\n        if (!resp->resp_scan_thread_result) {\n            return;\n        }\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        if (resp->resp_scan_thread_result->entries) {\n            for (size_t i = 0; i < resp->resp_scan_thread_result->n_entries; i++) {\n                if (!resp->resp_scan_thread_result->entries[i]) {\n                    continue;\n                }\n                free(resp->resp_scan_thread_result->entries[i]->ext_addr.data);\n                free(resp->resp_scan_thread_result->entries[i]->ext_pan_id.data);\n                if (resp->resp_scan_thread_result->entries[i]->network_name != protobuf_c_empty_string) {\n                    free(resp->resp_scan_thread_result->entries[i]->network_name);\n                }\n                free(resp->resp_scan_thread_result->entries[i]);\n            }\n            free(resp->resp_scan_thread_result->entries);\n        }\n#endif // CONFIG_NETWORK_PROV_NETWORK_TYPE_THREAD\n        free(resp->resp_scan_thread_result);\n    }\n    break;\n    default:\n        ESP_LOGE(TAG, \"Unsupported response type in cleanup_handler\");\n        break;\n    }\n    return;\n}\n\nstatic esp_err_t network_prov_scan_cmd_dispatcher(NetworkScanPayload *req,\n        NetworkScanPayload *resp, void *priv_data)\n{\n    esp_err_t ret;\n\n    ESP_LOGD(TAG, \"In network_prov_scan_cmd_dispatcher Cmd=%d\", req->msg);\n\n    int cmd_index = lookup_cmd_handler(req->msg);\n    if (cmd_index < 0) {\n        ESP_LOGE(TAG, \"Invalid command handler lookup\");\n        return ESP_FAIL;\n    }\n\n    ret = cmd_table[cmd_index].command_handler(req, resp, priv_data);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Error executing command handler\");\n        return ESP_FAIL;\n    }\n\n    return ESP_OK;\n}\n\nesp_err_t network_prov_scan_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,\n                                    uint8_t **outbuf, ssize_t *outlen, void *priv_data)\n{\n    NetworkScanPayload *req;\n    NetworkScanPayload resp;\n    esp_err_t ret = ESP_OK;\n\n    req = network_scan_payload__unpack(NULL, inlen, inbuf);\n    if (!req) {\n        ESP_LOGE(TAG, \"Unable to unpack scan message\");\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    network_scan_payload__init(&resp);\n    /* Validate req->msg before arithmetic to avoid signed overflow on attacker-controlled\n     * wire values. For unknown commands the dispatcher returns ESP_FAIL without calling\n     * any handler, so nothing is allocated and resp.msg = 0 is safe for cleanup. */\n    if (lookup_cmd_handler(req->msg) >= 0) {\n        resp.msg = req->msg + 1;\n    }\n    ret = network_prov_scan_cmd_dispatcher(req, &resp, priv_data);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Command dispatcher error %d\", ret);\n        ret = ESP_FAIL;\n        goto exit;\n    }\n    *outlen = network_scan_payload__get_packed_size(&resp);\n    if (*outlen <= 0) {\n        ESP_LOGE(TAG, \"Invalid encoding for response\");\n        ret = ESP_FAIL;\n        goto exit;\n    }\n\n    *outbuf = (uint8_t *) malloc(*outlen);\n    if (!*outbuf) {\n        ESP_LOGE(TAG, \"System out of memory\");\n        ret = ESP_ERR_NO_MEM;\n        goto exit;\n    }\n    network_scan_payload__pack(&resp, *outbuf);\n    ESP_LOGD(TAG, \"Response packet size : %d\", *outlen);\nexit:\n\n    network_scan_payload__free_unpacked(req, NULL);\n    network_prov_scan_cmd_cleanup(&resp, priv_data);\n    return ret;\n}\n"
  },
  {
    "path": "network_provisioning/src/scheme_ble.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include <esp_log.h>\n#include <esp_err.h>\n#ifdef CONFIG_BT_CONTROLLER_ENABLED\n#include \"esp_bt.h\"\n#endif\n\n#include <protocomm.h>\n#include <protocomm_ble.h>\n\n#include \"network_provisioning/scheme_ble.h\"\n#include \"network_provisioning_priv.h\"\n\nstatic const char *TAG = \"network_prov_scheme_ble\";\n\nextern const network_prov_scheme_t network_prov_scheme_ble;\n\nstatic uint8_t *custom_service_uuid;\n#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)\nstatic uint8_t *custom_ble_addr;\nstatic uint8_t custom_keep_ble_on;\n#endif\n\nstatic uint8_t *custom_manufacturer_data;\nstatic size_t custom_manufacturer_data_len;\n\nstatic esp_err_t prov_start(protocomm_t *pc, void *config)\n{\n    if (!pc) {\n        ESP_LOGE(TAG, \"Protocomm handle cannot be null\");\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    if (!config) {\n        ESP_LOGE(TAG, \"Cannot start with null configuration\");\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    protocomm_ble_config_t *ble_config = (protocomm_ble_config_t *) config;\n\n#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)\n    ble_config->keep_ble_on = custom_keep_ble_on;\n#endif\n\n#if defined(CONFIG_NETWORK_PROV_BLE_BONDING)\n    ble_config->ble_bonding = 1;\n#endif\n\n#if defined(CONFIG_NETWORK_PROV_BLE_SEC_CONN) || defined(CONFIG_BT_BLUEDROID_ENABLED)\n    ble_config->ble_sm_sc = 1;\n#endif\n\n#if defined(CONFIG_NETWORK_PROV_BLE_FORCE_ENCRYPTION)\n    ble_config->ble_link_encryption = 1;\n#endif\n\n#if defined(CONFIG_NETWORK_PROV_BLE_NOTIFY)\n    ble_config->ble_notify = 1;\n#endif\n    /* Start protocomm as BLE service */\n    if (protocomm_ble_start(pc, ble_config) != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to start protocomm BLE service\");\n        return ESP_FAIL;\n    }\n    return ESP_OK;\n}\n\n#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)\nesp_err_t network_prov_scheme_ble_set_random_addr(const uint8_t *addr)\n{\n    if (!addr) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    custom_ble_addr = (uint8_t *) malloc(BLE_ADDR_LEN);\n    if (custom_ble_addr == NULL) {\n        ESP_LOGE(TAG, \"Error allocating memory for random address\");\n        return ESP_ERR_NO_MEM;\n    }\n\n    memcpy(custom_ble_addr, addr, BLE_ADDR_LEN);\n    return ESP_OK;\n}\n\nesp_err_t network_prov_mgr_keep_ble_on(uint8_t is_on_after_ble_stop)\n{\n    if (!is_on_after_ble_stop) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    custom_keep_ble_on = is_on_after_ble_stop;\n    return ESP_OK;\n}\n#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)\n\n\nesp_err_t network_prov_scheme_ble_set_service_uuid(uint8_t *uuid128)\n{\n    if (!uuid128) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    custom_service_uuid = uuid128;\n    return ESP_OK;\n}\n\nesp_err_t network_prov_scheme_ble_set_mfg_data(uint8_t *mfg_data, ssize_t mfg_data_len)\n{\n    if (!mfg_data || !mfg_data_len) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    custom_manufacturer_data = (uint8_t *) malloc(mfg_data_len);\n    if (custom_manufacturer_data == NULL) {\n        ESP_LOGE(TAG, \"Error allocating memory for mfg_data\");\n        return ESP_ERR_NO_MEM;\n    }\n\n    custom_manufacturer_data_len = mfg_data_len;\n    memcpy(custom_manufacturer_data, mfg_data, mfg_data_len);\n    return ESP_OK;\n}\n\nstatic void *new_config(void)\n{\n    protocomm_ble_config_t *ble_config = calloc(1, sizeof(protocomm_ble_config_t));\n    if (!ble_config) {\n        ESP_LOGE(TAG, \"Error allocating memory for new configuration\");\n        return NULL;\n    }\n\n    /* The default provisioning service UUID */\n    const uint8_t service_uuid[16] = {\n        /* LSB <---------------------------------------\n         * ---------------------------------------> MSB */\n        0x07, 0xed, 0x9b, 0x2d, 0x0f, 0x06, 0x7c, 0x87,\n        0x9b, 0x43, 0x43, 0x6b, 0x4d, 0x24, 0x75, 0x17,\n    };\n\n    memcpy(ble_config->service_uuid, service_uuid, sizeof(ble_config->service_uuid));\n    return ble_config;\n}\n\nstatic void delete_config(void *config)\n{\n    if (!config) {\n        ESP_LOGE(TAG, \"Cannot delete null configuration\");\n        return;\n    }\n\n    protocomm_ble_config_t *ble_config = (protocomm_ble_config_t *) config;\n    for (unsigned int i = 0; i < ble_config->nu_lookup_count; i++) {\n        free((void *)ble_config->nu_lookup[i].name);\n    }\n    free(ble_config->nu_lookup);\n    free(ble_config);\n}\n\nstatic esp_err_t set_config_service(void *config, const char *service_name, const char *service_key)\n{\n    if (!config) {\n        ESP_LOGE(TAG, \"Cannot set null configuration\");\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    if (!service_name) {\n        ESP_LOGE(TAG, \"Service name cannot be NULL\");\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    protocomm_ble_config_t *ble_config = (protocomm_ble_config_t *) config;\n    strlcpy(ble_config->device_name,  service_name, sizeof(ble_config->device_name));\n\n    /* If a custom service UUID has been provided, override the default one */\n    if (custom_service_uuid) {\n        memcpy(ble_config->service_uuid, custom_service_uuid, sizeof(ble_config->service_uuid));\n    }\n    /* Set manufacturer data if it is provided by app */\n    if (custom_manufacturer_data) {\n        size_t mfg_data_len = custom_manufacturer_data_len;\n        size_t dev_name_len = strnlen(ble_config->device_name, MAX_BLE_DEVNAME_LEN);\n\n        if ((dev_name_len + 2) >= MAX_BLE_MANUFACTURER_DATA_LEN) {\n            /* No space left for manufacturer data */\n            ESP_LOGE(TAG, \"No space left for Manufacturer data \");\n            ble_config->manufacturer_data = NULL;\n            ble_config->manufacturer_data_len = 0;\n        } else {\n            if ((mfg_data_len + (dev_name_len ? (dev_name_len + 2) : 0)) > MAX_BLE_MANUFACTURER_DATA_LEN) {\n                ESP_LOGE(TAG, \"Manufacturer data length is more than the max allowed size; expect truncated mfg_data \");\n                /* Truncate the mfg_data to fit in the available length */\n                mfg_data_len = MAX_BLE_MANUFACTURER_DATA_LEN - (dev_name_len ? (dev_name_len + 2) : 0);\n            }\n\n            ble_config->manufacturer_data = custom_manufacturer_data;\n            ble_config->manufacturer_data_len = mfg_data_len;\n        }\n    } else {\n        ble_config->manufacturer_data = NULL;\n        ble_config->manufacturer_data_len = 0;\n    }\n\n#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)\n    if (custom_ble_addr) {\n        ble_config->ble_addr = custom_ble_addr;\n    } else {\n        ble_config->ble_addr = NULL;\n    }\n#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)\n\n    return ESP_OK;\n}\n\nstatic esp_err_t set_config_endpoint(void *config, const char *endpoint_name, uint16_t uuid)\n{\n    if (!config) {\n        ESP_LOGE(TAG, \"Cannot set null configuration\");\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    if (!endpoint_name) {\n        ESP_LOGE(TAG, \"EP name cannot be null\");\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    protocomm_ble_config_t *ble_config = (protocomm_ble_config_t *) config;\n\n    char *copy_ep_name = strdup(endpoint_name);\n    if (!copy_ep_name) {\n        ESP_LOGE(TAG, \"Error allocating memory for EP name\");\n        return ESP_ERR_NO_MEM;\n    }\n\n    protocomm_ble_name_uuid_t *lookup_table = (\n                realloc(ble_config->nu_lookup, (ble_config->nu_lookup_count + 1) * sizeof(protocomm_ble_name_uuid_t)));\n    if (!lookup_table) {\n        ESP_LOGE(TAG, \"Error allocating memory for EP-UUID lookup table\");\n        free(copy_ep_name);\n        return ESP_ERR_NO_MEM;\n    }\n\n    lookup_table[ble_config->nu_lookup_count].name = copy_ep_name;\n    lookup_table[ble_config->nu_lookup_count].uuid = uuid;\n    ble_config->nu_lookup = lookup_table;\n    ble_config->nu_lookup_count += 1;\n    return ESP_OK;\n}\n\n/* Used when both BT and BLE are not needed by application */\nvoid network_prov_scheme_ble_event_cb_free_btdm(void *user_data, network_prov_cb_event_t event, void *event_data)\n{\n#ifdef CONFIG_BT_CONTROLLER_ENABLED\n    esp_err_t err;\n    switch (event) {\n    case NETWORK_PROV_INIT:\n        /* Release BT memory, as we need only BLE */\n        err = esp_bt_mem_release(ESP_BT_MODE_CLASSIC_BT);\n        if (err != ESP_OK) {\n            ESP_LOGE(TAG, \"bt_mem_release of classic BT failed %d\", err);\n        } else {\n            ESP_LOGI(TAG, \"BT memory released\");\n        }\n        break;\n\n    case NETWORK_PROV_DEINIT:\n#ifndef CONFIG_NETWORK_PROV_KEEP_BLE_ON_AFTER_PROV\n        /* Release memory used by BLE and Bluedroid host stack */\n        err = esp_bt_mem_release(ESP_BT_MODE_BTDM);\n        if (err != ESP_OK) {\n            ESP_LOGE(TAG, \"bt_mem_release of BTDM failed %d\", err);\n        } else {\n            ESP_LOGI(TAG, \"BTDM memory released\");\n        }\n#endif /* !CONFIG_NETWORK_PROV_KEEP_BLE_ON_AFTER_PROV */\n        break;\n\n    default:\n        break;\n    }\n#endif /* CONFIG_BT_CONTROLLER_ENABLED */\n}\n\n/* Used when BT is not needed by application */\nvoid network_prov_scheme_ble_event_cb_free_bt(void *user_data, network_prov_cb_event_t event, void *event_data)\n{\n#ifdef CONFIG_BT_CONTROLLER_ENABLED\n    esp_err_t err;\n    switch (event) {\n    case NETWORK_PROV_INIT:\n        /* Release BT memory, as we need only BLE */\n        err = esp_bt_mem_release(ESP_BT_MODE_CLASSIC_BT);\n        if (err != ESP_OK) {\n            ESP_LOGE(TAG, \"bt_mem_release of classic BT failed %d\", err);\n        } else {\n            ESP_LOGI(TAG, \"BT memory released\");\n        }\n        break;\n\n    default:\n        break;\n    }\n#endif /* CONFIG_BT_CONTROLLER_ENABLED */\n}\n\n/* Used when BLE is not needed by application */\nvoid network_prov_scheme_ble_event_cb_free_ble(void *user_data, network_prov_cb_event_t event, void *event_data)\n{\n#ifdef CONFIG_BT_CONTROLLER_ENABLED\n    esp_err_t err;\n    switch (event) {\n    case NETWORK_PROV_DEINIT:\n#ifndef CONFIG_NETWORK_PROV_KEEP_BLE_ON_AFTER_PROV\n        /* Release memory used by BLE stack */\n        err = esp_bt_mem_release(ESP_BT_MODE_BLE);\n        if (err != ESP_OK) {\n            ESP_LOGE(TAG, \"bt_mem_release of BLE failed %d\", err);\n        } else {\n            ESP_LOGI(TAG, \"BLE memory released\");\n        }\n#endif /* !CONFIG_NETWORK_PROV_KEEP_BLE_ON_AFTER_PROV */\n        break;\n\n    default:\n        break;\n    }\n#endif /* CONFIG_BT_CONTROLLER_ENABLED */\n}\n\nconst network_prov_scheme_t network_prov_scheme_ble = {\n    .prov_start          = prov_start,\n    .prov_stop           = protocomm_ble_stop,\n    .new_config          = new_config,\n    .delete_config       = delete_config,\n    .set_config_service  = set_config_service,\n    .set_config_endpoint = set_config_endpoint,\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    .wifi_mode           = WIFI_MODE_STA\n#endif\n};\n"
  },
  {
    "path": "network_provisioning/src/scheme_console.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include <esp_log.h>\n#include <esp_err.h>\n#include <esp_wifi.h>\n\n#include <protocomm.h>\n#include <protocomm_console.h>\n\n#include \"network_provisioning/scheme_console.h\"\n#include \"network_provisioning_priv.h\"\n\nstatic const char *TAG = \"network_prov_scheme_console\";\n\nextern const network_prov_scheme_t network_prov_scheme_console;\n\nstatic esp_err_t prov_start(protocomm_t *pc, void *config)\n{\n    if (!pc) {\n        ESP_LOGE(TAG, \"Protocomm handle cannot be null\");\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    if (!config) {\n        ESP_LOGE(TAG, \"Cannot start with null configuration\");\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    protocomm_console_config_t *console_config = (protocomm_console_config_t *) config;\n\n    /* Start protocomm console */\n    esp_err_t err = protocomm_console_start(pc, console_config);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to start protocomm HTTP server\");\n        return ESP_FAIL;\n    }\n    return ESP_OK;\n}\n\nstatic void *new_config(void)\n{\n    protocomm_console_config_t *console_config = malloc(sizeof(protocomm_console_config_t));\n    if (!console_config) {\n        ESP_LOGE(TAG, \"Error allocating memory for new configuration\");\n        return NULL;\n    }\n    protocomm_console_config_t default_config = PROTOCOMM_CONSOLE_DEFAULT_CONFIG();\n    memcpy(console_config, &default_config, sizeof(default_config));\n    return console_config;\n}\n\nstatic void delete_config(void *config)\n{\n    if (!config) {\n        ESP_LOGE(TAG, \"Cannot delete null configuration\");\n        return;\n    }\n    free(config);\n}\n\nstatic esp_err_t set_config_service(void *config, const char *service_name, const char *service_key)\n{\n    return ESP_OK;\n}\n\nstatic esp_err_t set_config_endpoint(void *config, const char *endpoint_name, uint16_t uuid)\n{\n    return ESP_OK;\n}\n\nconst network_prov_scheme_t network_prov_scheme_console = {\n    .prov_start          = prov_start,\n    .prov_stop           = protocomm_console_stop,\n    .new_config          = new_config,\n    .delete_config       = delete_config,\n    .set_config_service  = set_config_service,\n    .set_config_endpoint = set_config_endpoint,\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    .wifi_mode           = WIFI_MODE_STA\n#endif\n};\n"
  },
  {
    "path": "network_provisioning/src/scheme_softap.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include \"sdkconfig.h\"\n\n#include <string.h>\n#include <esp_log.h>\n#include <esp_err.h>\n#include <esp_wifi.h>\n\n#include <protocomm.h>\n#include <protocomm_httpd.h>\n\n#include \"network_provisioning/scheme_softap.h\"\n#include \"network_provisioning_priv.h\"\n\ntypedef struct softap_config {\n    protocomm_httpd_config_t httpd_config;\n    char ssid[33];\n    char password[65];\n} network_prov_softap_config_t;\n\nstatic const char *TAG = \"network_prov_scheme_softap\";\n\nextern const network_prov_scheme_t network_prov_scheme_softap;\nstatic void *scheme_softap_prov_httpd_handle;\nstatic esp_err_t start_wifi_ap(const char *ssid, const char *pass)\n{\n    /* Build Wi-Fi configuration for AP mode */\n    wifi_config_t wifi_config = {\n        .ap = {\n            .max_connection = 5,\n        },\n    };\n\n    /* SSID can be a non NULL terminated string if `ap.ssid_len` is specified\n     * Hence, memcpy is used to support 32 bytes long SSID per 802.11 standard */\n    const size_t ssid_len = strnlen(ssid, sizeof(wifi_config.ap.ssid));\n    memcpy(wifi_config.ap.ssid, ssid, ssid_len);\n    wifi_config.ap.ssid_len = ssid_len;\n\n    if (strlen(pass) == 0) {\n        memset(wifi_config.ap.password, 0, sizeof(wifi_config.ap.password));\n        wifi_config.ap.authmode = WIFI_AUTH_OPEN;\n    } else {\n        strlcpy((char *) wifi_config.ap.password, pass, sizeof(wifi_config.ap.password));\n        wifi_config.ap.authmode = WIFI_AUTH_WPA_WPA2_PSK;\n    }\n\n    /* Run Wi-Fi in AP + STA mode with configuration built above */\n    esp_err_t err = esp_wifi_set_mode(WIFI_MODE_APSTA);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to set Wi-Fi mode : %d\", err);\n        return err;\n    }\n    err = esp_wifi_set_config(WIFI_IF_AP, &wifi_config);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to set Wi-Fi config : %d\", err);\n        return err;\n    }\n\n    return ESP_OK;\n}\n\nstatic esp_err_t prov_start(protocomm_t *pc, void *config)\n{\n    if (!pc) {\n        ESP_LOGE(TAG, \"Protocomm handle cannot be null\");\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    if (!config) {\n        ESP_LOGE(TAG, \"Cannot start with null configuration\");\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    network_prov_softap_config_t *softap_config = (network_prov_softap_config_t *) config;\n\n    protocomm_httpd_config_t *httpd_config = &softap_config->httpd_config;\n\n    if (scheme_softap_prov_httpd_handle) {\n        httpd_config->ext_handle_provided = true;\n        httpd_config->data.handle = scheme_softap_prov_httpd_handle;\n    }\n\n    /* Start protocomm server on top of HTTP */\n    esp_err_t err = protocomm_httpd_start(pc, httpd_config);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to start protocomm HTTP server\");\n        return err;\n    }\n\n    /* Start Wi-Fi softAP with specified ssid and password */\n    err = start_wifi_ap(softap_config->ssid, softap_config->password);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to start Wi-Fi AP\");\n        protocomm_httpd_stop(pc);\n        return err;\n    }\n\n    return ESP_OK;\n}\n\nstatic esp_err_t prov_stop(protocomm_t *pc)\n{\n    esp_err_t err = protocomm_httpd_stop(pc);\n    if (err != ESP_OK) {\n        ESP_LOGW(TAG, \"Error occurred while stopping protocomm_httpd\");\n    }\n\n    return err;\n}\n\nstatic void *new_config(void)\n{\n    network_prov_softap_config_t *softap_config = calloc(1, sizeof(network_prov_softap_config_t));\n    if (!softap_config) {\n        ESP_LOGE(TAG, \"Error allocating memory for new configuration\");\n        return NULL;\n    }\n    protocomm_httpd_config_t default_config = {\n        .data = {\n            .config = PROTOCOMM_HTTPD_DEFAULT_CONFIG()\n        }\n    };\n    softap_config->httpd_config = default_config;\n    return softap_config;\n}\n\nstatic void delete_config(void *config)\n{\n    if (!config) {\n        ESP_LOGE(TAG, \"Cannot delete null configuration\");\n        return;\n    }\n\n    network_prov_softap_config_t *softap_config = (network_prov_softap_config_t *) config;\n    free(softap_config);\n}\n\nstatic esp_err_t set_config_service(void *config, const char *service_name, const char *service_key)\n{\n    if (!config) {\n        ESP_LOGE(TAG, \"Cannot set null configuration\");\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    if (!service_name) {\n        ESP_LOGE(TAG, \"Service name cannot be NULL\");\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    network_prov_softap_config_t *softap_config = (network_prov_softap_config_t *) config;\n    if (service_key) {\n        const int service_key_len = strlen(service_key);\n        if (service_key_len < 8 || service_key_len >= sizeof(softap_config->password)) {\n            ESP_LOGE(TAG, \"Incorrect passphrase length for softAP: %d (Expected: Min - 8, Max - 64)\", service_key_len);\n            return ESP_ERR_INVALID_ARG;\n        }\n        strlcpy(softap_config->password, service_key,  sizeof(softap_config->password));\n    }\n    strlcpy(softap_config->ssid, service_name, sizeof(softap_config->ssid));\n    return ESP_OK;\n}\n\nstatic esp_err_t set_config_endpoint(void *config, const char *endpoint_name, uint16_t uuid)\n{\n    return ESP_OK;\n}\n\nvoid network_prov_scheme_softap_set_httpd_handle(void *handle)\n{\n    scheme_softap_prov_httpd_handle = handle;\n}\n\nconst network_prov_scheme_t network_prov_scheme_softap = {\n    .prov_start          = prov_start,\n    .prov_stop           = prov_stop,\n    .new_config          = new_config,\n    .delete_config       = delete_config,\n    .set_config_service  = set_config_service,\n    .set_config_endpoint = set_config_endpoint,\n#ifdef CONFIG_NETWORK_PROV_NETWORK_TYPE_WIFI\n    .wifi_mode           = WIFI_MODE_APSTA\n#endif\n};\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/README.md",
    "content": "# ESP Provisioning Tool\n\n## Description\n\n`esp_prov` - A python-based utility for testing the provisioning examples over a host machine.\n\nUsage of `esp-prov` assumes that the provisioning app has specific protocomm endpoints active. These endpoints are active in the provisioning examples and accept specific protobuf data structure:\n\n| Endpoint Name | URI (HTTP server on ip:port) | Description                                                                              |\n|---------------|------------------------------|------------------------------------------------------------------------------------------|\n| prov-session  | http://ip:port/prov-session  | Security endpoint used for session establishment                                         |\n| prov-config   | http://ip:port/prov-config   | Endpoint used for configuring Wi-Fi credentials or Thread dataset on device              |\n| proto-ver     | http://ip:port/proto-ver     | Version endpoint for checking protocol compatibility                                     |\n| prov-scan     | http://ip:port/prov-scan     | Endpoint used for scanning Wi-Fi APs or Thread network                                   |\n| prov-ctrl     | http://ip:port/prov-ctrl     | Endpoint used for controlling Wi-Fi / Thread provisioning state                          |\n| custom-data   | http://ip:port/custom-data   | Optional endpoint for sending custom data (refer `wifi_prov` or `thread_prov` example)   |\n\n\n## Usage\n\n```\npython esp_prov.py --transport < mode of provisioning : softap \\ ble \\ console > [ Optional parameters... ]\n```\n### Parameters\n\n* `--help`\n    Print the list of options along with brief descriptions\n\n* `--verbose`, `-v`\n    Sets the verbosity level of output log\n\n* `--transport <mode>`\n    - Three options are available:\n      * `softap` - for SoftAP + HTTPD based provisioning\n        * Requires the device to be running in Wi-Fi SoftAP mode and hosting an HTTP server supporting specific endpoint URIs\n        * The client needs to be connected to the device softAP network before running the `esp_prov` tool.\n      * `ble` - for Bluetooth LE based provisioning\n        * Supports Linux, Windows and macOS; redirected to console if dependencies are not met\n        * Assumes that the provisioning endpoints are active on the device with specific Bluetooth LE service UUIDs\n      * `console` - for debugging via console-based provisioning\n        * The client->device commands are printed to STDOUT and device->client messages are accepted via STDIN.\n        * This is to be used when the device is accepting provisioning commands on UART console.\n      * `httpd` - the script works the same as for `softap`. This could be used on any other network interface than WiFi soft AP, e.g. Ethernet or USB.\n\n* `--service_name <name>` (Optional)\n    - When transport mode is `ble`, this specifies the Bluetooth LE device name to which connection is to be established for provisioned. If not provided, Bluetooth LE scanning is initiated and a list of nearby devices, as seen by the host, is displayed, of which the target device can be chosen.\n    - When transport mode is `softap` or `httpd`, this specifies the HTTP server hostname / IP which is running the provisioning service, on the SoftAP network (or any other interface for `httpd` mode) of the device which is to be provisioned. This defaults to `192.168.4.1:80` if not specified\n\n* `--ssid <AP SSID>` (Optional)\n    - For specifying the SSID of the Wi-Fi AP to which the device is to connect after provisioning.\n    - If not provided, scanning is initiated and scan results, as seen by the device, are displayed, of which an SSID can be picked and the corresponding password specified.\n\n* `--passphrase <AP Password>` (Optional)\n    - For specifying the password of the Wi-Fi AP to which the device is to connect after provisioning.\n    - Only used when corresponding SSID is provided using the `--ssid` option\n\n* `--dataset_tlvs <Thread Dataset Tlvs>` (Optional)\n    - For specifying the Dataset Tlvs of the Thread network to which the device is to connect after provisioning.\n\n* `--sec_ver <Security version number>`\n    - For specifying the version of protocomm endpoint security to use. Following 3 versions are supported:\n      * `0` for `protocomm_security0` - No security\n      * `1` for `protocomm_security1` - X25519 key exchange + Authentication using Proof of Possession (PoP) + AES-CTR encryption\n      * `2` for `protocomm_security2` - Secure Remote Password protocol (SRP6a) + AES-GCM encryption\n\n* `--pop <Proof of possession string>` (Optional)\n    - For specifying optional Proof of Possession string to use for protocomm endpoint security version 1\n    - Ignored when other security versions are used\n\n* `--sec2_username <SRP6a Username>` (Optional)\n    - For specifying optional username to use for protocomm endpoint security version 2\n    - Ignored when other security versions are used\n\n* `--sec2_pwd <SRP6a Password>` (Optional)\n    - For specifying optional password to use for protocomm endpoint security version 2\n    - Ignored when other security versions are used\n\n* `--sec2_gen_cred` (Optional)\n    - For generating the `SRP6a` credentials (salt and verifier) from the provided username and password for protocomm endpoint security version 2\n    - Ignored when other security versions are used\n\n* `--sec2_salt_len <SRP6a Salt Length>` (Optional)\n    - For specifying the optional `SRP6a` salt length to be used for generating protocomm endpoint security version 2 credentials\n    - Ignored when other security versions are used and the `--sec2_gen_cred` option is not set\n\n* `--reset` (Optional)\n    - Resets internal state machine of the device and clears provisioned credentials; to be used only in case of provisioning failures\n\n* `--reprov` (Optional)\n    - Resets internal state machine of the device and clears provisioned credentials; to be used only in case the device is to be provisioned again for new credentials after a previous successful provisioning\n\n* `--ble_adapter <HCI adapter>` (Optional)\n    - For specifying the HCI adapter to use for Bluetooth LE transport (default: `hci0`).\n    - Useful when working with `vhci_bridge` for emulated devices, e.g. `--ble_adapter hci1`.\n    - Only relevant when transport mode is `ble`\n\n* `--custom_data <some string>` (Optional)\n    An information string can be sent to the `custom-data` endpoint during provisioning using this argument.\n    (Assumes the provisioning app has an endpoint called `custom-data` - see [wifi_prov](../../examples/wifi_prov/) example for implementation details).\n\n\n### Example Usage\n\nPlease refer to the `README.md` file with the `wifi_prov` or `thread_prov` example present under `{path-to-network_provisioning-component}/examples`.\n\nThis example uses specific options of the `esp_prov` tool and gives an overview of simple as well as advanced usage scenarios.\n\n## Dependencies\n\nThis requires the following python libraries to run:\n* `bleak`\n* `protobuf`\n* `cryptography`\n\nTo install the dependency packages needed, please run the following command in `$IDF_PATH` directory:\n\nFor ESP-IDF v5.1:\n```shell\nbash install.sh --enable-ttfw\n```\n\nFor ESP-IDF v5.2 to v5.5:\n```shell\nbash install.sh --enable-pytest\n```\n\nFor ESP-IDF v6.0 or later:\n```shell\nbash install.sh --enable-ci\n```\n\n**Note:** For troubleshooting errors with Bluetooth LE transport, please refer this [link](https://bleak.readthedocs.io/en/latest/troubleshooting.html).\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/__init__.py",
    "content": "# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\n\nfrom .esp_prov import *  # noqa: export esp_prov module to users\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/esp_prov.py",
    "content": "#!/usr/bin/env python\n#\n# SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\n\nimport argparse\nimport asyncio\nimport json\nimport os\nimport sys\nimport textwrap\nimport time\nfrom getpass import getpass\n\nfrom utils import int_to_hex_str\n\ntry:\n    import prov\n    import security\n    import transport\n\nexcept ImportError:\n    idf_path = os.environ['IDF_PATH']\n    sys.path.insert(0, idf_path + '/components/protocomm/python')\n    sys.path.insert(1, idf_path + '/tools/esp_prov')\n\n    import prov\n    import security\n    import transport\n\n# Set this to true to allow exceptions to be thrown\nconfig_throw_except = False\n\n\ndef on_except(err):\n    if config_throw_except:\n        raise RuntimeError(err)\n    else:\n        print(err)\n\n\ndef get_security(secver, sec_patch_ver, username, password, pop='', verbose=False):\n    if secver == 2:\n        return security.Security2(sec_patch_ver, username, password, verbose)\n    elif secver == 1:\n        return security.Security1(pop, verbose)\n    elif secver == 0:\n        return security.Security0(verbose)\n    return None\n\n\ndef get_thread_dataset_tlvs(network_info, network_key):\n    # Get the simple dataset tlvs from the PAN ID, Channel, Extended PAN ID, and Network Key\n    pan_id = network_info['pan_id']\n    channel = network_info['channel']\n    ext_pan_id = network_info['ext_pan_id']\n    dataset_tlvs = '00030000' + int_to_hex_str(channel) + '0208' + ext_pan_id + '0510' + network_key + '0102' + int_to_hex_str(pan_id)\n    return dataset_tlvs\n\n\nasync def get_transport(sel_transport, service_name, ble_adapter=transport.DEFAULT_BLE_ADAPTER):\n    try:\n        tp = None\n        if (sel_transport in ['softap', 'httpd']):\n            if service_name is None:\n                service_name = '192.168.4.1:80'\n            tp = transport.Transport_HTTP(service_name)\n        elif (sel_transport == 'ble'):\n            # BLE client is now capable of automatically figuring out\n            # the primary service from the advertisement data and the\n            # characteristics corresponding to each endpoint.\n            # Below, the service_uuid field and 16bit UUIDs in the nu_lookup\n            # table are provided only to support devices running older firmware,\n            # in which case, the automated discovery will fail and the client\n            # will fallback to using the provided UUIDs instead\n            nu_lookup = {'prov-session': 'ff51', 'prov-config': 'ff52', 'proto-ver': 'ff53'}\n            tp = transport.Transport_BLE(service_uuid='021a9004-0382-4aea-bff4-6b3f1c5adfb4',\n                                         nu_lookup=nu_lookup, ble_adapter=ble_adapter)\n            await tp.connect(devname=service_name)\n        elif (sel_transport == 'console'):\n            tp = transport.Transport_Console()\n        return tp\n    except RuntimeError as e:\n        on_except(e)\n        return None\n\n\nasync def version_match(tp, protover, verbose=False):\n    try:\n        response = await tp.send_data('proto-ver', protover)\n\n        if verbose:\n            print('proto-ver response : ', response)\n\n        # First assume this to be a simple version string\n        if response.lower() == protover.lower():\n            return True\n\n        try:\n            # Else interpret this as JSON structure containing\n            # information with versions and capabilities of both\n            # provisioning service and application\n            info = json.loads(response)\n            if info['prov']['ver'].lower() == protover.lower():\n                return True\n\n        except ValueError:\n            # If decoding as JSON fails, it means that capabilities\n            # are not supported\n            return False\n\n    except Exception as e:\n        on_except(e)\n        return None\n\n\nasync def has_capability(tp, capability='none', verbose=False):\n    # Note : default value of `capability` argument cannot be empty string\n    # because protocomm_httpd expects non zero content lengths\n    try:\n        response = await tp.send_data('proto-ver', capability)\n\n        if verbose:\n            print('proto-ver response : ', response)\n\n        try:\n            # Interpret this as JSON structure containing\n            # information with versions and capabilities of both\n            # provisioning service and application\n            info = json.loads(response)\n            supported_capabilities = info['prov']['cap']\n            if capability.lower() == 'none':\n                # No specific capability to check, but capabilities\n                # feature is present so return True\n                return True\n            elif capability in supported_capabilities:\n                return True\n            return False\n\n        except ValueError:\n            # If decoding as JSON fails, it means that capabilities\n            # are not supported\n            return False\n\n    except RuntimeError as e:\n        on_except(e)\n\n    return False\n\n\nasync def get_version(tp):\n    response = None\n    try:\n        response = await tp.send_data('proto-ver', '---')\n    except RuntimeError as e:\n        on_except(e)\n        response = ''\n    return response\n\n\nasync def get_sec_patch_ver(tp, verbose=False):\n    response = await get_version(tp)\n\n    if verbose:\n        print('proto-ver response : ', response)\n\n    try:\n        # Interpret this as JSON structure containing\n        # information with security version information\n        info = json.loads(response)\n        try:\n            sec_patch_ver = info['prov']['sec_patch_ver']\n        except KeyError:\n            sec_patch_ver = 0\n        return sec_patch_ver\n\n    except ValueError:\n        # If decoding as JSON fails, we assume default patch level\n        return 0\n\n\nasync def establish_session(tp, sec):\n    try:\n        response = None\n        while True:\n            request = sec.security_session(response)\n            if request is None:\n                break\n            response = await tp.send_data('prov-session', request)\n            if (response is None):\n                return False\n        return True\n    except RuntimeError as e:\n        on_except(e)\n        return None\n\n\nasync def custom_config(tp, sec, custom_info, custom_ver):\n    try:\n        message = prov.custom_config_request(sec, custom_info, custom_ver)\n        response = await tp.send_data('custom-config', message)\n        return (prov.custom_config_response(sec, response) == 0)\n    except RuntimeError as e:\n        on_except(e)\n        return None\n\n\nasync def custom_data(tp, sec, custom_data):\n    try:\n        message = prov.custom_data_request(sec, custom_data)\n        response = await tp.send_data('custom-data', message)\n        return (prov.custom_data_response(sec, response) == 0)\n    except RuntimeError as e:\n        on_except(e)\n        return None\n\n\nasync def scan_wifi_APs(sel_transport, tp, sec):\n    APs = []\n    group_channels = 0\n    readlen = 100\n    if sel_transport in ['softap', 'httpd']:\n        # In case of softAP/httpd we must perform the scan on individual channels, one by one,\n        # so that the Wi-Fi controller gets ample time to send out beacons (necessary to\n        # maintain connectivity with authenticated stations. As scanning one channel at a\n        # time will be slow, we can group more than one channels to be scanned in quick\n        # succession, hence speeding up the scan process. Though if too many channels are\n        # present in a group, the controller may again miss out on sending beacons. Hence,\n        # the application must should use an optimum value. The following value usually\n        # works out in most cases\n        group_channels = 5\n    elif sel_transport == 'ble':\n        # Read at most 4 entries at a time. This is because if we are using BLE transport\n        # then the response packet size should not exceed the present limit of 256 bytes of\n        # characteristic value imposed by protocomm_ble. This limit may be removed in the\n        # future\n        readlen = 4\n    try:\n        message = prov.scan_start_request('wifi', sec, blocking=True, group_channels=group_channels)\n        start_time = time.time()\n        response = await tp.send_data('prov-scan', message)\n        stop_time = time.time()\n        print('++++ Scan process executed in ' + str(stop_time - start_time) + ' sec')\n        prov.scan_start_response(sec, response)\n\n        message = prov.scan_status_request('wifi', sec)\n        response = await tp.send_data('prov-scan', message)\n        result = prov.scan_status_response(sec, response)\n        print('++++ Scan results : ' + str(result['count']))\n        if result['count'] != 0:\n            index = 0\n            remaining = result['count']\n            while remaining:\n                count = [remaining, readlen][remaining > readlen]\n                message = prov.scan_result_request('wifi', sec, index, count)\n                response = await tp.send_data('prov-scan', message)\n                APs += prov.scan_result_response(sec, response)\n                remaining -= count\n                index += count\n\n    except RuntimeError as e:\n        on_except(e)\n        return None\n\n    return APs\n\n\nasync def send_wifi_config(tp, sec, ssid, passphrase):\n    try:\n        message = prov.config_set_config_request('wifi', sec, ssid, passphrase)\n        response = await tp.send_data('prov-config', message)\n        return (prov.config_set_config_response(sec, response) == 0)\n    except RuntimeError as e:\n        on_except(e)\n        return None\n\n\nasync def apply_wifi_config(tp, sec):\n    try:\n        message = prov.config_apply_config_request('wifi', sec)\n        response = await tp.send_data('prov-config', message)\n        return (prov.config_apply_config_response(sec, response) == 0)\n    except RuntimeError as e:\n        on_except(e)\n        return None\n\n\nasync def get_wifi_config(tp, sec):\n    try:\n        message = prov.config_get_status_request('wifi', sec)\n        response = await tp.send_data('prov-config', message)\n        return prov.config_get_status_response(sec, response)\n    except RuntimeError as e:\n        on_except(e)\n        return None\n\n\nasync def wait_wifi_connected(tp, sec):\n    \"\"\"\n    Wait for provisioning to report Wi-Fi is connected\n\n    Returns True if Wi-Fi connection succeeded, False if connection consistently failed\n    \"\"\"\n    TIME_PER_POLL = 5\n    retry = 3\n\n    while True:\n        time.sleep(TIME_PER_POLL)\n        print('\\n==== Wi-Fi connection state  ====')\n        ret = await get_wifi_config(tp, sec)\n        if ret == 'connecting':\n            continue\n        elif ret == 'connected':\n            print('==== Provisioning was successful ====')\n            return True\n        elif retry > 0:\n            retry -= 1\n            print('Waiting to poll status again (status %s, %d tries left)...' % (ret, retry))\n        else:\n            print('---- Provisioning failed! ----')\n            return False\n\n\nasync def reset_wifi(tp, sec):\n    try:\n        message = prov.ctrl_reset_request('wifi', sec)\n        response = await tp.send_data('prov-ctrl', message)\n        prov.ctrl_reset_response(sec, response)\n\n    except RuntimeError as e:\n        on_except(e)\n        return None\n\n\nasync def reprov_wifi(tp, sec):\n    try:\n        message = prov.ctrl_reprov_request('wifi', sec)\n        response = await tp.send_data('prov-ctrl', message)\n        prov.ctrl_reprov_response(sec, response)\n\n    except RuntimeError as e:\n        on_except(e)\n        return None\n\n\nasync def scan_thread_networks(sel_transport, tp, sec):\n    Networks = []\n    # Read at most 4 entries at a time. This is because if we are using BLE transport\n    # then the response packet size should not exceed the present limit of 256 bytes of\n    # characteristic value imposed by protocomm_ble. This limit may be removed in the\n    # future\n    readlen = 4\n    try:\n        message = prov.scan_start_request('thread', sec, blocking=True, group_channels=0)\n        start_time = time.time()\n        response = await tp.send_data('prov-scan', message)\n        stop_time = time.time()\n        print('++++ Scan process executed in ' + str(stop_time - start_time) + ' sec')\n        prov.scan_start_response(sec, response)\n\n        message = prov.scan_status_request('thread', sec)\n        response = await tp.send_data('prov-scan', message)\n        result = prov.scan_status_response(sec, response)\n        print('++++ Scan results : ' + str(result['count']))\n        if result['count'] != 0:\n            index = 0\n            remaining = result['count']\n            while remaining:\n                count = [remaining, readlen][remaining > readlen]\n                message = prov.scan_result_request('thread', sec, index, count)\n                response = await tp.send_data('prov-scan', message)\n                Networks += prov.scan_result_response(sec, response)\n                remaining -= count\n                index += count\n\n    except RuntimeError as e:\n        on_except(e)\n        return None\n\n    return Networks\n\n\nasync def send_thread_config(tp, sec, dataset_tlvs):\n    try:\n        message = prov.config_set_config_request('thread', sec, dataset_tlvs)\n        response = await tp.send_data('prov-config', message)\n        return (prov.config_set_config_response(sec, response) == 0)\n    except RuntimeError as e:\n        on_except(e)\n        return None\n\n\nasync def apply_thread_config(tp, sec):\n    try:\n        message = prov.config_apply_config_request('thread', sec)\n        response = await tp.send_data('prov-config', message)\n        return (prov.config_apply_config_response(sec, response) == 0)\n    except RuntimeError as e:\n        on_except(e)\n        return None\n\n\nasync def get_thread_config(tp, sec):\n    try:\n        message = prov.config_get_status_request('thread', sec)\n        response = await tp.send_data('prov-config', message)\n        return prov.config_get_status_response(sec, response)\n    except RuntimeError as e:\n        on_except(e)\n        return None\n\n\nasync def wait_thread_connected(tp, sec):\n    \"\"\"\n    Wait for provisioning to report Thread is attached\n\n    Returns True if Thread connection succeeded, False if connection consistently failed\n    \"\"\"\n    TIME_PER_POLL = 5\n    retry = 3\n\n    while True:\n        time.sleep(TIME_PER_POLL)\n        print('\\n==== Thread connection state  ====')\n        ret = await get_thread_config(tp, sec)\n        if ret == 'attaching':\n            continue\n        elif ret == 'attached':\n            print('==== Provisioning was successful ====')\n            return True\n        elif retry > 0:\n            retry -= 1\n            print('Waiting to poll status again (status %s, %d tries left)...' % (ret, retry))\n        else:\n            print('---- Provisioning failed! ----')\n            return False\n\n\nasync def reset_thread(tp, sec):\n    try:\n        message = prov.ctrl_reset_request('thread', sec)\n        response = await tp.send_data('prov-ctrl', message)\n        prov.ctrl_reset_response(sec, response)\n\n    except RuntimeError as e:\n        on_except(e)\n        return None\n\n\nasync def reprov_thread(tp, sec):\n    try:\n        message = prov.ctrl_reprov_request('thread', sec)\n        response = await tp.send_data('prov-ctrl', message)\n        prov.ctrl_reprov_response(sec, response)\n\n    except RuntimeError as e:\n        on_except(e)\n        return None\n\n\ndef desc_format(*args):\n    desc = ''\n    for arg in args:\n        desc += textwrap.fill(replace_whitespace=False, text=arg) + '\\n'\n    return desc\n\n\nasync def main():\n    parser = argparse.ArgumentParser(description=desc_format(\n                                     'ESP Provisioning tool for configuring devices '\n                                     'running protocomm based provisioning service.',\n                                     'See esp-idf/examples/provisioning for sample applications'),\n                                     formatter_class=argparse.RawTextHelpFormatter)\n\n    parser.add_argument('--transport', required=True, dest='mode', type=str,\n                        help=desc_format(\n                            'Mode of transport over which provisioning is to be performed.',\n                            'This should be one of \"softap\", \"ble\", \"console\" (or \"httpd\" which is an alias of softap)'))\n\n    parser.add_argument('--service_name', dest='name', type=str,\n                        help=desc_format(\n                            'This specifies the name of the provisioning service to connect to, '\n                            'depending upon the mode of transport :',\n                            '\\t- transport \"ble\"          : The BLE Device Name',\n                            '\\t- transport \"softap/httpd\" : HTTP Server hostname or IP',\n                            '\\t                       (default \"192.168.4.1:80\")'))\n\n    parser.add_argument('--proto_ver', dest='version', type=str, default='',\n                        help=desc_format(\n                            'This checks the protocol version of the provisioning service running '\n                            'on the device before initiating Wi-Fi configuration'))\n\n    parser.add_argument('--sec_ver', dest='secver', type=int, default=None,\n                        help=desc_format(\n                            'Protocomm security scheme used by the provisioning service for secure '\n                            'session establishment. Accepted values are :',\n                            '\\t- 0 : No security',\n                            '\\t- 1 : X25519 key exchange + AES-CTR encryption',\n                            '\\t      + Authentication using Proof of Possession (PoP)',\n                            '\\t- 2 : SRP6a + AES-GCM encryption',\n                            'In case device side application uses IDF\\'s provisioning manager, '\n                            'the compatible security version is automatically determined from '\n                            'capabilities retrieved via the version endpoint'))\n\n    parser.add_argument('--pop', dest='sec1_pop', type=str, default='',\n                        help=desc_format(\n                            'This specifies the Proof of possession (PoP) when security scheme 1 '\n                            'is used'))\n\n    parser.add_argument('--sec2_username', dest='sec2_usr', type=str, default='',\n                        help=desc_format(\n                            'Username for security scheme 2 (SRP6a)'))\n\n    parser.add_argument('--sec2_pwd', dest='sec2_pwd', type=str, default='',\n                        help=desc_format(\n                            'Password for security scheme 2 (SRP6a)'))\n\n    parser.add_argument('--sec2_gen_cred', help='Generate salt and verifier for security scheme 2 (SRP6a)', action='store_true')\n\n    parser.add_argument('--sec2_salt_len', dest='sec2_salt_len', type=int, default=16,\n                        help=desc_format(\n                            'Salt length for security scheme 2 (SRP6a)'))\n\n    parser.add_argument('--ssid', dest='ssid', type=str, default='',\n                        help=desc_format(\n                            'This configures the device to use SSID of the Wi-Fi network to which '\n                            'we would like it to connect to permanently, once provisioning is complete. '\n                            'If Wi-Fi scanning is supported by the provisioning service, this need not '\n                            'be specified'))\n\n    parser.add_argument('--passphrase', dest='passphrase', type=str,\n                        help=desc_format(\n                            'This configures the device to use Passphrase for the Wi-Fi network to which '\n                            'we would like it to connect to permanently, once provisioning is complete. '\n                            'If Wi-Fi scanning is supported by the provisioning service, this need not '\n                            'be specified'))\n\n    parser.add_argument('--dataset_tlvs', dest='dataset_tlvs', type=str,\n                        help=desc_format(\n                            'This configures the device to use Dataset Tlvs of the Thread network to '\n                            'which we would like it to attach to permanently, once provisioning is '\n                            'complete. If Thread scanning is supported by the provisioning service, this '\n                            'need not be specified'))\n\n    parser.add_argument('--custom_data', dest='custom_data', type=str, default='',\n                        help=desc_format(\n                            'This is an optional parameter, only intended for use with '\n                            '\"examples/wifi_prov\"'))\n\n    parser.add_argument('--reset', help='Reset WiFi', action='store_true')\n\n    parser.add_argument('--reprov', help='Reprovision WiFi', action='store_true')\n\n    parser.add_argument('-v','--verbose', help='Increase output verbosity', action='store_true')\n\n    parser.add_argument('--ble_adapter', dest='ble_adapter', type=str, default=transport.DEFAULT_BLE_ADAPTER,\n                        help=desc_format(\n                            f'HCI adapter to use for BLE (default: {transport.DEFAULT_BLE_ADAPTER}).',\n                            'Use with vhci_bridge for emulated devices, e.g. --ble_adapter hci1'))\n\n    args = parser.parse_args()\n\n    if args.secver == 2 and args.sec2_gen_cred:\n        if not args.sec2_usr or not args.sec2_pwd:\n            raise ValueError('Username/password cannot be empty for security scheme 2 (SRP6a)')\n\n        print('==== Salt-verifier for security scheme 2 (SRP6a) ====')\n        security.sec2_gen_salt_verifier(args.sec2_usr, args.sec2_pwd, args.sec2_salt_len)\n        sys.exit()\n\n    obj_transport = await get_transport(args.mode.lower(), args.name, args.ble_adapter)\n    if obj_transport is None:\n        raise RuntimeError('Failed to establish connection')\n\n    try:\n        sec_patch_ver = 0\n        # If security version not specified check in capabilities\n        if args.secver is None:\n            # First check if capabilities are supported or not\n            if not await has_capability(obj_transport):\n                print('Security capabilities could not be determined, please specify \"--sec_ver\" explicitly')\n                raise ValueError('Invalid Security Version')\n\n            # When no_sec is present, use security 0, else security 1\n            args.secver = int(not await has_capability(obj_transport, 'no_sec'))\n            print(f'==== Security Scheme: {args.secver} ====')\n\n        if (args.secver == 1):\n            if not await has_capability(obj_transport, 'no_pop'):\n                if len(args.sec1_pop) == 0:\n                    prompt_str = 'Proof of Possession required: '\n                    args.sec1_pop = getpass(prompt_str)\n            elif len(args.sec1_pop) != 0:\n                print('Proof of Possession will be ignored')\n                args.sec1_pop = ''\n\n        if (args.secver == 2):\n            sec_patch_ver = await get_sec_patch_ver(obj_transport, args.verbose)\n            if len(args.sec2_usr) == 0:\n                args.sec2_usr = input('Security Scheme 2 - SRP6a Username required: ')\n            if len(args.sec2_pwd) == 0:\n                prompt_str = 'Security Scheme 2 - SRP6a Password required: '\n                args.sec2_pwd = getpass(prompt_str)\n\n        obj_security = get_security(args.secver, sec_patch_ver, args.sec2_usr, args.sec2_pwd, args.sec1_pop, args.verbose)\n        if obj_security is None:\n            raise ValueError('Invalid Security Version')\n\n        if args.version != '':\n            print('\\n==== Verifying protocol version ====')\n            if not await version_match(obj_transport, args.version, args.verbose):\n                raise RuntimeError('Error in protocol version matching')\n            print('==== Verified protocol version successfully ====')\n\n        print('\\n==== Starting Session ====')\n        if not await establish_session(obj_transport, obj_security):\n            print('Failed to establish session. Ensure that security scheme and proof of possession are correct')\n            raise RuntimeError('Error in establishing session')\n        print('==== Session Established ====')\n\n        if await has_capability(obj_transport, 'thread_prov'):\n            if args.reset:\n                print('==== Resetting Thread====')\n                await reset_thread(obj_transport, obj_security)\n                sys.exit()\n\n            if args.reprov:\n                print('==== Reprovisioning Thread====')\n                await reprov_thread(obj_transport, obj_security)\n                sys.exit()\n\n            if args.dataset_tlvs is None:\n                if not await has_capability(obj_transport, 'thread_scan'):\n                    prompt_str = 'Enter Thread dataset tlvs string : '\n                    args.dataset_tlvs = input(prompt_str)\n                else:\n                    while True:\n                        print('\\n==== Scanning Thread Networks ====')\n                        start_time = time.time()\n                        Networks = await scan_thread_networks(args.mode.lower(), obj_transport, obj_security)\n                        end_time = time.time()\n                        print('\\n++++ Scan finished in ' + str(end_time - start_time) + ' sec')\n                        if Networks is None:\n                            raise RuntimeError('Error in scanning Thread Networks')\n\n                        if len(Networks) == 0:\n                            print('No Thread Networks found!')\n                            sys.exit()\n\n                        print('==== Thread Scan results ====')\n                        print('{0: >4} {1: <8} {2: <18} {3: <18} {4: <18} {5: <4} {6: <4} {7: <16}'.format(\n                            'S.N.', 'PAN ID', 'EXT PAN ID', 'NAME', 'EXT ADDR', 'CHN', 'RSSI', 'LQI'))\n                        for i in range(len(Networks)):\n                            print('[{0: >2}] {1: <8} {2: <18} {3: <18} {4: <18} {5: <4} {6: <4} {7: <16}'.format(\n                                i + 1, Networks[i]['pan_id'], Networks[i]['ext_pan_id'], Networks[i]['network_name'],\n                                Networks[i]['ext_addr'], Networks[i]['channel'], Networks[i]['rssi'], Networks[i]['lqi']))\n\n                        while True:\n                            try:\n                                select = int(input('Select Network by number (0 to rescan) : '))\n                                if select < 0 or select > len(Networks):\n                                    raise ValueError\n                                break\n                            except ValueError:\n                                print('Invalid input! Retry')\n\n                        if select != 0:\n                            network_key = getpass('Enter Thread network key string : ')\n                            args.dataset_tlvs = get_thread_dataset_tlvs(Networks[select], network_key)\n                            break\n\n            print('\\n==== Sending Thread Dataset to Target ====')\n            if not await send_thread_config(obj_transport, obj_security, args.dataset_tlvs):\n                raise RuntimeError('Error in send Thread config')\n            print('==== Thread Dataset sent successfully ====')\n\n            print('\\n==== Applying Thread Config to Target ====')\n            if not await apply_thread_config(obj_transport, obj_security):\n                raise RuntimeError('Error in apply Thread config')\n            print('==== Apply config sent successfully ====')\n\n            await wait_thread_connected(obj_transport, obj_security)\n        else:\n            if not await has_capability(obj_transport, 'wifi_prov'):\n                print('Use wifi_provisioning for device without \"wifi_prov\" capabilities')\n                print('The device might be using previous wifi_provisioning in ESP-IDF')\n\n            if args.reset:\n                print('==== Resetting WiFi====')\n                await reset_wifi(obj_transport, obj_security)\n                sys.exit()\n\n            if args.reprov:\n                print('==== Reprovisioning WiFi====')\n                await reprov_wifi(obj_transport, obj_security)\n                sys.exit()\n\n            if args.custom_data != '':\n                print('\\n==== Sending Custom data to Target ====')\n                if not await custom_data(obj_transport, obj_security, args.custom_data):\n                    raise RuntimeError('Error in custom data')\n                print('==== Custom data sent successfully ====')\n\n            if args.ssid == '':\n                if not await has_capability(obj_transport, 'wifi_scan'):\n                    raise RuntimeError('Wi-Fi Scan List is not supported by provisioning service')\n\n                while True:\n                    print('\\n==== Scanning Wi-Fi APs ====')\n                    start_time = time.time()\n                    APs = await scan_wifi_APs(args.mode.lower(), obj_transport, obj_security)\n                    end_time = time.time()\n                    print('\\n++++ Scan finished in ' + str(end_time - start_time) + ' sec')\n                    if APs is None:\n                        raise RuntimeError('Error in scanning Wi-Fi APs')\n\n                    if len(APs) == 0:\n                        print('No APs found!')\n                        sys.exit()\n\n                    print('==== Wi-Fi Scan results ====')\n                    print('{0: >4} {1: <33} {2: <12} {3: >4} {4: <4} {5: <16}'.format(\n                        'S.N.', 'SSID', 'BSSID', 'CHN', 'RSSI', 'AUTH'))\n                    for i in range(len(APs)):\n                        print('[{0: >2}] {1: <33} {2: <12} {3: >4} {4: <4} {5: <16}'.format(\n                            i + 1, APs[i]['ssid'], APs[i]['bssid'], APs[i]['channel'], APs[i]['rssi'], APs[i]['auth']))\n\n                    while True:\n                        try:\n                            select = int(input('Select AP by number (0 to rescan) : '))\n                            if select < 0 or select > len(APs):\n                                raise ValueError\n                            break\n                        except ValueError:\n                            print('Invalid input! Retry')\n\n                    if select != 0:\n                        break\n\n                args.ssid = APs[select - 1]['ssid']\n\n            if args.passphrase is None:\n                prompt_str = 'Enter passphrase for {0} : '.format(args.ssid)\n                args.passphrase = getpass(prompt_str)\n\n            print('\\n==== Sending Wi-Fi Credentials to Target ====')\n            if not await send_wifi_config(obj_transport, obj_security, args.ssid, args.passphrase):\n                raise RuntimeError('Error in send Wi-Fi config')\n            print('==== Wi-Fi Credentials sent successfully ====')\n\n            print('\\n==== Applying Wi-Fi Config to Target ====')\n            if not await apply_wifi_config(obj_transport, obj_security):\n                raise RuntimeError('Error in apply Wi-Fi config')\n            print('==== Apply config sent successfully ====')\n\n            await wait_wifi_connected(obj_transport, obj_security)\n\n    finally:\n        await obj_transport.disconnect()\n\nif __name__ == '__main__':\n    asyncio.run(main())\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/proto/__init__.py",
    "content": "# SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\n\nimport importlib.util\nimport os\nimport sys\nfrom importlib.abc import Loader\nfrom typing import Any\n\n\ndef _load_source(name: str, path: str) -> Any:\n    spec = importlib.util.spec_from_file_location(name, path)\n    if not spec:\n        return None\n\n    module = importlib.util.module_from_spec(spec)\n    sys.modules[spec.name] = module\n    assert isinstance(spec.loader, Loader)\n    spec.loader.exec_module(module)\n    return module\n\n\nidf_path = os.environ['IDF_PATH']\nesp_prov_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\n\n# protocomm component related python files generated from .proto files\nconstants_pb2 = _load_source('constants_pb2', idf_path + '/components/protocomm/python/constants_pb2.py')\nsec0_pb2      = _load_source('sec0_pb2',      idf_path + '/components/protocomm/python/sec0_pb2.py')\nsec1_pb2      = _load_source('sec1_pb2',      idf_path + '/components/protocomm/python/sec1_pb2.py')\nsec2_pb2      = _load_source('sec2_pb2',      idf_path + '/components/protocomm/python/sec2_pb2.py')\nsession_pb2   = _load_source('session_pb2',   idf_path + '/components/protocomm/python/session_pb2.py')\n\n# network_provisioning component related python files generated from .proto files\nnetwork_constants_pb2 = _load_source('network_constants_pb2', esp_prov_path + '/../../python/network_constants_pb2.py')\nnetwork_config_pb2    = _load_source('network_config_pb2',    esp_prov_path + '/../../python/network_config_pb2.py')\nnetwork_scan_pb2      = _load_source('network_scan_pb2',      esp_prov_path + '/../../python/network_scan_pb2.py')\nnetwork_ctrl_pb2    = _load_source('network_ctrl_pb2',    esp_prov_path + '/../../python/network_ctrl_pb2.py')\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/prov/__init__.py",
    "content": "# SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\n\nfrom .custom_prov import *  # noqa F403\nfrom .network_ctrl import *  # noqa F403\nfrom .network_prov import *  # noqa F403\nfrom .network_scan import *  # noqa F403\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/prov/custom_prov.py",
    "content": "# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\n\n# APIs for interpreting and creating protobuf packets for `custom-config` protocomm endpoint\n\nfrom utils import str_to_bytes\n\n\ndef print_verbose(security_ctx, data):\n    if (security_ctx.verbose):\n        print(f'\\x1b[32;20m++++ {data} ++++\\x1b[0m')\n\n\ndef custom_data_request(security_ctx, data):\n    # Encrypt the custom data\n    enc_cmd = security_ctx.encrypt_data(str_to_bytes(data))\n    print_verbose(security_ctx, f'Client -> Device (CustomData cmd): 0x{enc_cmd.hex()}')\n    return enc_cmd.decode('latin-1')\n\n\ndef custom_data_response(security_ctx, response_data):\n    # Decrypt response packet\n    decrypt = security_ctx.decrypt_data(str_to_bytes(response_data))\n    print(f'++++ CustomData response: {str(decrypt)}++++')\n    return 0\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/prov/network_ctrl.py",
    "content": "# SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\n\n# APIs for interpreting and creating protobuf packets for Wi-Fi State Controlling\n\nimport proto\nfrom utils import str_to_bytes\n\n\ndef print_verbose(security_ctx, data):\n    if (security_ctx.verbose):\n        print(f'\\x1b[32;20m++++ {data} ++++\\x1b[0m')\n\n\ndef ctrl_reset_request(network_type, security_ctx):\n    # Form protobuf request packet for CtrlReset command\n    cmd = proto.network_ctrl_pb2.NetworkCtrlPayload()\n    if network_type == 'wifi':\n        cmd.msg = proto.network_ctrl_pb2.TypeCmdCtrlWifiReset\n    elif network_type == 'thread':\n        cmd.msg = proto.network_ctrl_pb2.TypeCmdCtrlThreadReset\n    else:\n        raise RuntimeError\n    enc_cmd = security_ctx.encrypt_data(cmd.SerializeToString())\n    print_verbose(security_ctx, f'Client -> Device (Encrypted CmdCtrlReset): 0x{enc_cmd.hex()}')\n    return enc_cmd.decode('latin-1')\n\n\ndef ctrl_reset_response(security_ctx, response_data):\n    # Interpret protobuf response packet from CtrlReset command\n    dec_resp = security_ctx.decrypt_data(str_to_bytes(response_data))\n    resp = proto.network_ctrl_pb2.NetworkCtrlPayload()\n    resp.ParseFromString(dec_resp)\n    print_verbose(security_ctx, f'CtrlReset status: 0x{str(resp.status)}')\n    if resp.status != 0:\n        raise RuntimeError\n\n\ndef ctrl_reprov_request(network_type, security_ctx):\n    # Form protobuf request packet for CtrlReprov command\n    cmd = proto.network_ctrl_pb2.NetworkCtrlPayload()\n    if network_type == 'wifi':\n        cmd.msg = proto.network_ctrl_pb2.TypeCmdCtrlWifiReprov\n    elif network_type == 'thread':\n        cmd.msg = proto.network_ctrl_pb2.TypeCmdCtrlThreadReprov\n    else:\n        raise RuntimeError\n    enc_cmd = security_ctx.encrypt_data(cmd.SerializeToString())\n    print_verbose(security_ctx, f'Client -> Device (Encrypted CmdCtrlReset): 0x{enc_cmd.hex()}')\n    return enc_cmd.decode('latin-1')\n\n\ndef ctrl_reprov_response(security_ctx, response_data):\n    # Interpret protobuf response packet from CtrlReprov command\n    dec_resp = security_ctx.decrypt_data(str_to_bytes(response_data))\n    resp = proto.network_ctrl_pb2.NetworkCtrlPayload()\n    resp.ParseFromString(dec_resp)\n    print_verbose(security_ctx, f'CtrlReset status: 0x{str(resp.status)}')\n    if resp.status != 0:\n        raise RuntimeError\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/prov/network_prov.py",
    "content": "# SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\n\n# APIs for interpreting and creating protobuf packets for Wi-Fi provisioning\n\nimport proto\nfrom utils import hex_str_to_bytes, str_to_bytes\n\n\ndef print_verbose(security_ctx, data):\n    if (security_ctx.verbose):\n        print(f'++++ {data} ++++')\n\n\ndef config_get_status_request(network_type, security_ctx):\n    # Form protobuf request packet for GetStatus command\n    cfg1 = proto.network_config_pb2.NetworkConfigPayload()\n    if network_type == 'wifi':\n        cfg1.msg = proto.network_config_pb2.TypeCmdGetWifiStatus\n        cmd_get_wifi_status = proto.network_config_pb2.CmdGetWifiStatus()\n        cfg1.cmd_get_wifi_status.MergeFrom(cmd_get_wifi_status)\n    elif network_type == 'thread':\n        cfg1.msg = proto.network_config_pb2.TypeCmdGetThreadStatus\n        cmd_get_thread_status = proto.network_config_pb2.CmdGetThreadStatus()\n        cfg1.cmd_get_thread_status.MergeFrom(cmd_get_thread_status)\n    else:\n        raise RuntimeError\n    encrypted_cfg = security_ctx.encrypt_data(cfg1.SerializeToString())\n    print_verbose(security_ctx, f'Client -> Device (Encrypted CmdGetStatus): 0x{encrypted_cfg.hex()}')\n    return encrypted_cfg.decode('latin-1')\n\n\ndef config_get_status_response(security_ctx, response_data):\n    # Interpret protobuf response packet from GetStatus command\n    decrypted_message = security_ctx.decrypt_data(str_to_bytes(response_data))\n    cmd_resp1 = proto.network_config_pb2.NetworkConfigPayload()\n    cmd_resp1.ParseFromString(decrypted_message)\n    print_verbose(security_ctx, f'CmdGetStatus type: {str(cmd_resp1.msg)}')\n\n    if cmd_resp1.msg == proto.network_config_pb2.TypeRespGetWifiStatus:\n        print_verbose(security_ctx, f'CmdGetStatus status: {str(cmd_resp1.resp_get_wifi_status.status)}')\n        if cmd_resp1.resp_get_wifi_status.wifi_sta_state == 0:\n            print('==== WiFi state: Connected ====')\n            return 'connected'\n        elif cmd_resp1.resp_get_wifi_status.wifi_sta_state == 1:\n            print('++++ WiFi state: Connecting... ++++')\n            if cmd_resp1.resp_get_wifi_status.HasField('attempt_failed'):\n                if cmd_resp1.resp_get_wifi_status.attempt_failed.attempts_remaining:\n                    print(cmd_resp1.resp_get_wifi_status)\n                else:\n                    print('attempt_failed {\\n  attempts_remaining: 0\\n}')\n            return 'connecting'\n        elif cmd_resp1.resp_get_wifi_status.wifi_sta_state == 2:\n            print('---- WiFi state: Disconnected ----')\n            return 'disconnected'\n        elif cmd_resp1.resp_get_wifi_status.wifi_sta_state == 3:\n            print('---- WiFi state: Connection Failed ----')\n            if cmd_resp1.resp_get_wifi_status.wifi_fail_reason == 0:\n                print('---- Failure reason: Incorrect Password ----')\n            elif cmd_resp1.resp_get_wifi_status.wifi_fail_reason == 1:\n                print('---- Failure reason: Incorrect SSID ----')\n            return 'failed'\n    elif cmd_resp1.msg == proto.network_config_pb2.TypeRespGetThreadStatus:\n        print_verbose(security_ctx, f'CmdGetStatus status: {str(cmd_resp1.resp_get_thread_status.status)}')\n        if cmd_resp1.resp_get_thread_status.thread_state == 0:\n            print('==== Thread state: Attached ====')\n            return 'attached'\n        elif cmd_resp1.resp_get_thread_status.thread_state == 1:\n            print('==== Thread state: Attaching ====')\n            return 'attaching'\n        elif cmd_resp1.resp_get_thread_status.thread_state == 2:\n            print('==== Thread state: Detached ====')\n            return 'detached'\n        elif cmd_resp1.resp_get_thread_status.thread_state == 3:\n            print('==== Thread state: Attaching Failed ====')\n            if cmd_resp1.resp_get_thread_status.thread_fail_reason == 0:\n                print('---- Failure reason: Invalid Dataset ----')\n            elif cmd_resp1.resp_get_thread_status.thread_fail_reason == 1:\n                print('---- Failure reason: Network Not Found ----')\n            return 'failed'\n\n    return 'unknown'\n\n\ndef config_set_config_request(network_type, security_ctx, ssid_or_dataset_tlvs, passphrase=''):\n    # Form protobuf request packet for SetConfig command\n    cmd = proto.network_config_pb2.NetworkConfigPayload()\n    if network_type == 'wifi':\n        cmd.msg = proto.network_config_pb2.TypeCmdSetWifiConfig\n        cmd.cmd_set_wifi_config.ssid = str_to_bytes(ssid_or_dataset_tlvs)\n        cmd.cmd_set_wifi_config.passphrase = str_to_bytes(passphrase)\n    elif network_type == 'thread':\n        cmd.msg = proto.network_config_pb2.TypeCmdSetThreadConfig\n        cmd.cmd_set_thread_config.dataset = hex_str_to_bytes(ssid_or_dataset_tlvs)\n    else:\n        raise RuntimeError\n    enc_cmd = security_ctx.encrypt_data(cmd.SerializeToString())\n    print_verbose(security_ctx, f'Client -> Device (SetConfig cmd): 0x{enc_cmd.hex()}')\n    return enc_cmd.decode('latin-1')\n\n\ndef config_set_config_response(security_ctx, response_data):\n    # Interpret protobuf response packet from SetConfig command\n    decrypt = security_ctx.decrypt_data(str_to_bytes(response_data))\n    cmd_resp4 = proto.network_config_pb2.NetworkConfigPayload()\n    cmd_resp4.ParseFromString(decrypt)\n    if cmd_resp4.msg == proto.network_config_pb2.TypeRespSetWifiConfig:\n        print_verbose(security_ctx, f'SetConfig status: 0x{str(cmd_resp4.resp_set_wifi_config.status)}')\n        return cmd_resp4.resp_set_wifi_config.status\n    elif cmd_resp4.msg == proto.network_config_pb2.TypeRespSetThreadConfig:\n        print_verbose(security_ctx, f'SetConfig status: 0x{str(cmd_resp4.resp_set_thread_config.status)}')\n        return cmd_resp4.resp_set_thread_config.status\n\n\ndef config_apply_config_request(network_type, security_ctx):\n    # Form protobuf request packet for ApplyConfig command\n    cmd = proto.network_config_pb2.NetworkConfigPayload()\n    if network_type == 'wifi':\n        cmd.msg = proto.network_config_pb2.TypeCmdApplyWifiConfig\n    elif network_type == 'thread':\n        cmd.msg = proto.network_config_pb2.TypeCmdApplyThreadConfig\n    else:\n        raise RuntimeError\n    enc_cmd = security_ctx.encrypt_data(cmd.SerializeToString())\n    print_verbose(security_ctx, f'Client -> Device (ApplyConfig cmd): 0x{enc_cmd.hex()}')\n    return enc_cmd.decode('latin-1')\n\n\ndef config_apply_config_response(security_ctx, response_data):\n    # Interpret protobuf response packet from ApplyConfig command\n    decrypt = security_ctx.decrypt_data(str_to_bytes(response_data))\n    cmd_resp5 = proto.network_config_pb2.NetworkConfigPayload()\n    cmd_resp5.ParseFromString(decrypt)\n    if cmd_resp5.msg == proto.network_config_pb2.TypeRespApplyWifiConfig:\n        print_verbose(security_ctx, f'ApplyConfig status: 0x{str(cmd_resp5.resp_apply_wifi_config.status)}')\n        return cmd_resp5.resp_apply_wifi_config.status\n    elif cmd_resp5.msg == proto.network_config_pb2.TypeRespApplyThreadConfig:\n        print_verbose(security_ctx, f'ApplyConfig status: 0x{str(cmd_resp5.resp_apply_thread_config.status)}')\n        return cmd_resp5.resp_apply_thread_config.status\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/prov/network_scan.py",
    "content": "# SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\n\n# APIs for interpreting and creating protobuf packets for Wi-Fi Scanning\nimport proto\nfrom utils import str_to_bytes\n\n\ndef print_verbose(security_ctx, data):\n    if (security_ctx.verbose):\n        print(f'\\x1b[32;20m++++ {data} ++++\\x1b[0m')\n\n\ndef scan_start_request(network_type, security_ctx, blocking=True, passive=False, group_channels=5, period_ms=120):\n    # Form protobuf request packet for ScanStart command\n    cmd = proto.network_scan_pb2.NetworkScanPayload()\n    if network_type == 'wifi':\n        cmd.msg = proto.network_scan_pb2.TypeCmdScanWifiStart\n        cmd.cmd_scan_wifi_start.blocking = blocking\n        cmd.cmd_scan_wifi_start.passive = passive\n        cmd.cmd_scan_wifi_start.group_channels = group_channels\n        cmd.cmd_scan_wifi_start.period_ms = period_ms\n    elif network_type == 'thread':\n        cmd.msg = proto.network_scan_pb2.TypeCmdScanThreadStart\n        cmd.cmd_scan_thread_start.blocking = blocking\n        cmd.cmd_scan_thread_start.channel_mask = 0\n    else:\n        raise RuntimeError\n\n    enc_cmd = security_ctx.encrypt_data(cmd.SerializeToString())\n    print_verbose(security_ctx, f'Client -> Device (Encrypted CmdScanStart): 0x{enc_cmd.hex()}')\n    return enc_cmd.decode('latin-1')\n\n\ndef scan_start_response(security_ctx, response_data):\n    # Interpret protobuf response packet from ScanStart command\n    dec_resp = security_ctx.decrypt_data(str_to_bytes(response_data))\n    resp = proto.network_scan_pb2.NetworkScanPayload()\n    resp.ParseFromString(dec_resp)\n    print_verbose(security_ctx, f'ScanStart status: 0x{str(resp.status)}')\n    if resp.status != 0:\n        raise RuntimeError\n\n\ndef scan_status_request(network_type, security_ctx):\n    # Form protobuf request packet for ScanStatus command\n    cmd = proto.network_scan_pb2.NetworkScanPayload()\n    if network_type == 'wifi':\n        cmd.msg = proto.network_scan_pb2.TypeCmdScanWifiStatus\n    elif network_type == 'thread':\n        cmd.msg = proto.network_scan_pb2.TypeCmdScanThreadStatus\n    else:\n        raise RuntimeError\n    enc_cmd = security_ctx.encrypt_data(cmd.SerializeToString())\n    print_verbose(security_ctx, f'Client -> Device (Encrypted CmdScanStatus): 0x{enc_cmd.hex()}')\n    return enc_cmd.decode('latin-1')\n\n\ndef scan_status_response(security_ctx, response_data):\n    # Interpret protobuf response packet from ScanStatus command\n    dec_resp = security_ctx.decrypt_data(str_to_bytes(response_data))\n    resp = proto.network_scan_pb2.NetworkScanPayload()\n    resp.ParseFromString(dec_resp)\n    print_verbose(security_ctx, f'ScanStatus status: 0x{str(resp.status)}')\n    if resp.status != 0:\n        raise RuntimeError\n    if resp.msg == proto.network_scan_pb2.TypeRespScanWifiStatus:\n        return {'finished': resp.resp_scan_wifi_status.scan_finished, 'count': resp.resp_scan_wifi_status.result_count}\n    elif resp.msg == proto.network_scan_pb2.TypeRespScanThreadStatus:\n        return {'finished': resp.resp_scan_thread_status.scan_finished, 'count': resp.resp_scan_thread_status.result_count}\n    else:\n        raise RuntimeError\n\n\ndef scan_result_request(network_type, security_ctx, index, count):\n    # Form protobuf request packet for ScanResult command\n    cmd = proto.network_scan_pb2.NetworkScanPayload()\n    if network_type == 'wifi':\n        cmd.msg = proto.network_scan_pb2.TypeCmdScanWifiResult\n        cmd.cmd_scan_wifi_result.start_index = index\n        cmd.cmd_scan_wifi_result.count = count\n    elif network_type == 'thread':\n        cmd.msg = proto.network_scan_pb2.TypeCmdScanThreadResult\n        cmd.cmd_scan_thread_result.start_index = index\n        cmd.cmd_scan_thread_result.count = count\n    else:\n        raise RuntimeError\n    enc_cmd = security_ctx.encrypt_data(cmd.SerializeToString())\n    print_verbose(security_ctx, f'Client -> Device (Encrypted CmdScanResult): 0x{enc_cmd.hex()}')\n    return enc_cmd.decode('latin-1')\n\n\ndef scan_result_response(security_ctx, response_data):\n    # Interpret protobuf response packet from ScanResult command\n    dec_resp = security_ctx.decrypt_data(str_to_bytes(response_data))\n    resp = proto.network_scan_pb2.NetworkScanPayload()\n    resp.ParseFromString(dec_resp)\n    print_verbose(security_ctx, f'ScanResult status: 0x{str(resp.status)}')\n    if resp.status != 0:\n        raise RuntimeError\n    results = []\n    if resp.msg == proto.network_scan_pb2.TypeRespScanWifiResult:\n        authmode_str = ['Open', 'WEP', 'WPA_PSK', 'WPA2_PSK', 'WPA_WPA2_PSK',\n                        'WPA2_ENTERPRISE', 'WPA3_PSK', 'WPA2_WPA3_PSK']\n        for entry in resp.resp_scan_wifi_result.entries:\n            results += [{'ssid': entry.ssid.decode('latin-1').rstrip('\\x00'),\n                         'bssid': entry.bssid.hex(),\n                         'channel': entry.channel,\n                         'rssi': entry.rssi,\n                         'auth': authmode_str[entry.auth]}]\n            print_verbose(security_ctx, f\"ScanResult SSID    : {str(results[-1]['ssid'])}\")\n            print_verbose(security_ctx, f\"ScanResult BSSID   : {str(results[-1]['bssid'])}\")\n            print_verbose(security_ctx, f\"ScanResult Channel : {str(results[-1]['channel'])}\")\n            print_verbose(security_ctx, f\"ScanResult RSSI    : {str(results[-1]['rssi'])}\")\n            print_verbose(security_ctx, f\"ScanResult AUTH    : {str(results[-1]['auth'])}\")\n    elif resp.msg == proto.network_scan_pb2.TypeRespScanThreadResult:\n        for entry in resp.resp_scan_thread_result.entries:\n            results += [{'pan_id': entry.pan_id,\n                         'ext_pan_id': entry.ext_pan_id.hex(),\n                         'network_name': entry.network_name,\n                         'channel': entry.channel,\n                         'rssi': entry.rssi,\n                         'lqi': entry.lqi,\n                         'ext_addr': entry.ext_addr.hex()}]\n    else:\n        raise RuntimeError\n\n    return results\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/security/__init__.py",
    "content": "# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\n\nfrom .security0 import *  # noqa: F403, F401\nfrom .security1 import *  # noqa: F403, F401\nfrom .security2 import *  # noqa: F403, F401\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/security/security.py",
    "content": "# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\n\n# Base class for protocomm security\n\n\nclass Security:\n    def __init__(self, security_session):\n        self.security_session = security_session\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/security/security0.py",
    "content": "# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\n\n# APIs for interpreting and creating protobuf packets for\n# protocomm endpoint with security type protocomm_security0\n\nimport proto\nfrom utils import str_to_bytes\n\nfrom .security import Security\n\n\nclass Security0(Security):\n    def __init__(self, verbose):\n        # Initialize state of the security1 FSM\n        self.session_state = 0\n        self.verbose = verbose\n        Security.__init__(self, self.security0_session)\n\n    def security0_session(self, response_data):\n        # protocomm security0 FSM which interprets/forms\n        # protobuf packets according to present state of session\n        if (self.session_state == 0):\n            self.session_state = 1\n            return self.setup0_request()\n        if (self.session_state == 1):\n            self.setup0_response(response_data)\n            return None\n\n    def setup0_request(self):\n        # Form protocomm security0 request packet\n        setup_req = proto.session_pb2.SessionData()\n        setup_req.sec_ver = 0\n        session_cmd = proto.sec0_pb2.S0SessionCmd()\n        setup_req.sec0.sc.MergeFrom(session_cmd)\n        return setup_req.SerializeToString().decode('latin-1')\n\n    def setup0_response(self, response_data):\n        # Interpret protocomm security0 response packet\n        setup_resp = proto.session_pb2.SessionData()\n        setup_resp.ParseFromString(str_to_bytes(response_data))\n        # Check if security scheme matches\n        if setup_resp.sec_ver != proto.session_pb2.SecScheme0:\n            raise RuntimeError('Incorrect security scheme')\n\n    def encrypt_data(self, data):\n        # Passive. No encryption when security0 used\n        return data\n\n    def decrypt_data(self, data):\n        # Passive. No encryption when security0 used\n        return data\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/security/security1.py",
    "content": "# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\n\n# APIs for interpreting and creating protobuf packets for\n# protocomm endpoint with security type protocomm_security1\n\nimport proto\nfrom cryptography.hazmat.backends import default_backend\nfrom cryptography.hazmat.primitives import hashes, serialization\nfrom cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey, X25519PublicKey\nfrom cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes\nfrom utils import long_to_bytes, str_to_bytes\n\nfrom .security import Security\n\n\ndef a_xor_b(a: bytes, b: bytes) -> bytes:\n    return b''.join(long_to_bytes(a[i] ^ b[i]) for i in range(0, len(b)))\n\n\n# Enum for state of protocomm_security1 FSM\nclass security_state:\n    REQUEST1 = 0\n    RESPONSE1_REQUEST2 = 1\n    RESPONSE2 = 2\n    FINISHED = 3\n\n\nclass Security1(Security):\n    def __init__(self, pop, verbose):\n        # Initialize state of the security1 FSM\n        self.session_state = security_state.REQUEST1\n        self.pop = str_to_bytes(pop)\n        self.verbose = verbose\n        Security.__init__(self, self.security1_session)\n\n    def security1_session(self, response_data):\n        # protocomm security1 FSM which interprets/forms\n        # protobuf packets according to present state of session\n        if (self.session_state == security_state.REQUEST1):\n            self.session_state = security_state.RESPONSE1_REQUEST2\n            return self.setup0_request()\n        elif (self.session_state == security_state.RESPONSE1_REQUEST2):\n            self.session_state = security_state.RESPONSE2\n            self.setup0_response(response_data)\n            return self.setup1_request()\n        elif (self.session_state == security_state.RESPONSE2):\n            self.session_state = security_state.FINISHED\n            self.setup1_response(response_data)\n            return None\n\n        print('Unexpected state')\n        return None\n\n    def __generate_key(self):\n        # Generate private and public key pair for client\n        self.client_private_key = X25519PrivateKey.generate()\n        self.client_public_key = self.client_private_key.public_key().public_bytes(\n            encoding=serialization.Encoding.Raw,\n            format=serialization.PublicFormat.Raw)\n\n    def _print_verbose(self, data):\n        if (self.verbose):\n            print(f'\\x1b[32;20m++++ {data} ++++\\x1b[0m')\n\n    def setup0_request(self):\n        # Form SessionCmd0 request packet using client public key\n        setup_req = proto.session_pb2.SessionData()\n        setup_req.sec_ver = proto.session_pb2.SecScheme1\n        self.__generate_key()\n        setup_req.sec1.sc0.client_pubkey = self.client_public_key\n        self._print_verbose(f'Client Public Key:\\t0x{self.client_public_key.hex()}')\n        return setup_req.SerializeToString().decode('latin-1')\n\n    def setup0_response(self, response_data):\n        # Interpret SessionResp0 response packet\n        setup_resp = proto.session_pb2.SessionData()\n        setup_resp.ParseFromString(str_to_bytes(response_data))\n        self._print_verbose('Security version:\\t' + str(setup_resp.sec_ver))\n        if setup_resp.sec_ver != proto.session_pb2.SecScheme1:\n            raise RuntimeError('Incorrect security scheme')\n\n        self.device_public_key = setup_resp.sec1.sr0.device_pubkey\n        # Device random is the initialization vector\n        device_random = setup_resp.sec1.sr0.device_random\n        self._print_verbose(f'Device Public Key:\\t0x{self.device_public_key.hex()}')\n        self._print_verbose(f'Device Random:\\t0x{device_random.hex()}')\n\n        # Calculate Curve25519 shared key using Client private key and Device public key\n        sharedK = self.client_private_key.exchange(X25519PublicKey.from_public_bytes(self.device_public_key))\n        self._print_verbose(f'Shared Key:\\t0x{sharedK.hex()}')\n\n        # If PoP is provided, XOR SHA256 of PoP with the previously\n        # calculated Shared Key to form the actual Shared Key\n        if len(self.pop) > 0:\n            # Calculate SHA256 of PoP\n            h = hashes.Hash(hashes.SHA256(), backend=default_backend())\n            h.update(self.pop)\n            digest = h.finalize()\n            # XOR with and update Shared Key\n            sharedK = a_xor_b(sharedK, digest)\n            self._print_verbose(f'Updated Shared Key (Shared key XORed with PoP):\\t0x{sharedK.hex()}')\n        # Initialize the encryption engine with Shared Key and initialization vector\n        cipher = Cipher(algorithms.AES(sharedK), modes.CTR(device_random), backend=default_backend())\n        self.cipher = cipher.encryptor()\n\n    def setup1_request(self):\n        # Form SessionCmd1 request packet using encrypted device public key\n        setup_req = proto.session_pb2.SessionData()\n        setup_req.sec_ver = proto.session_pb2.SecScheme1\n        setup_req.sec1.msg = proto.sec1_pb2.Session_Command1\n        # Encrypt device public key and attach to the request packet\n        client_verify = self.cipher.update(self.device_public_key)\n        self._print_verbose(f'Client Proof:\\t0x{client_verify.hex()}')\n        setup_req.sec1.sc1.client_verify_data = client_verify\n        return setup_req.SerializeToString().decode('latin-1')\n\n    def setup1_response(self, response_data):\n        # Interpret SessionResp1 response packet\n        setup_resp = proto.session_pb2.SessionData()\n        setup_resp.ParseFromString(str_to_bytes(response_data))\n        # Ensure security scheme matches\n        if setup_resp.sec_ver == proto.session_pb2.SecScheme1:\n            # Read encrypyed device verify string\n            device_verify = setup_resp.sec1.sr1.device_verify_data\n            self._print_verbose(f'Device Proof:\\t0x{device_verify.hex()}')\n            # Decrypt the device verify string\n            enc_client_pubkey = self.cipher.update(setup_resp.sec1.sr1.device_verify_data)\n            # Match decrypted string with client public key\n            if enc_client_pubkey != self.client_public_key:\n                raise RuntimeError('Failed to verify device!')\n        else:\n            raise RuntimeError('Unsupported security protocol')\n\n    def encrypt_data(self, data):\n        return self.cipher.update(data)\n\n    def decrypt_data(self, data):\n        return self.cipher.update(data)\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/security/security2.py",
    "content": "# SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n# APIs for interpreting and creating protobuf packets for\n# protocomm endpoint with security type protocomm_security2\nimport struct\nfrom typing import Any\nfrom typing import Type\n\nimport proto\nfrom cryptography.hazmat.primitives.ciphers.aead import AESGCM\nfrom utils import long_to_bytes\nfrom utils import str_to_bytes\n\nfrom .security import Security\nfrom .srp6a import generate_salt_and_verifier\nfrom .srp6a import Srp6a\n\nAES_KEY_LEN = 256 // 8\n\n\n# Enum for state of protocomm_security1 FSM\nclass security_state:\n    REQUEST1 = 0\n    RESPONSE1_REQUEST2 = 1\n    RESPONSE2 = 2\n    FINISHED = 3\n\n\ndef sec2_gen_salt_verifier(username: str, password: str, salt_len: int) -> Any:\n    salt, verifier = generate_salt_and_verifier(username, password, len_s=salt_len)\n\n    salt_str = ', '.join([format(b, '#04x') for b in salt])\n    salt_c_arr = '\\n    '.join(salt_str[i: i + 96] for i in range(0, len(salt_str), 96))\n    print(f'static const char sec2_salt[] = {{\\n    {salt_c_arr}\\n}};\\n')  # noqa E702\n\n    verifier_str = ', '.join([format(b, '#04x') for b in verifier])\n    verifier_c_arr = '\\n    '.join(verifier_str[i: i + 96] for i in range(0, len(verifier_str), 96))\n    print(f'static const char sec2_verifier[] = {{\\n    {verifier_c_arr}\\n}};\\n')  # noqa E702\n\n\nclass Security2(Security):\n    def __init__(self, sec_patch_ver:int, username: str, password: str, verbose: bool) -> None:\n        # Initialize state of the security2 FSM\n        self.session_state = security_state.REQUEST1\n        self.sec_patch_ver = sec_patch_ver\n        self.username = username\n        self.password = password\n        self.verbose = verbose\n\n        self.srp6a_ctx: Type[Srp6a]\n        self.cipher: Type[AESGCM]\n\n        self.client_pop_key = None\n        self.nonce = bytearray()\n\n        Security.__init__(self, self.security2_session)\n\n    def security2_session(self, response_data: bytes) -> Any:\n        # protocomm security2 FSM which interprets/forms\n        # protobuf packets according to present state of session\n        if (self.session_state == security_state.REQUEST1):\n            self.session_state = security_state.RESPONSE1_REQUEST2\n            return self.setup0_request()\n\n        if (self.session_state == security_state.RESPONSE1_REQUEST2):\n            self.session_state = security_state.RESPONSE2\n            self.setup0_response(response_data)\n            return self.setup1_request()\n\n        if (self.session_state == security_state.RESPONSE2):\n            self.session_state = security_state.FINISHED\n            self.setup1_response(response_data)\n            return None\n\n        print('---- Unexpected state! ----')\n        return None\n\n    def _print_verbose(self, data: str) -> None:\n        if (self.verbose):\n            print(f'\\x1b[32;20m++++ {data} ++++\\x1b[0m')  # noqa E702\n\n    def setup0_request(self) -> Any:\n        # Form SessionCmd0 request packet using client public key\n        setup_req = proto.session_pb2.SessionData()\n        setup_req.sec_ver = proto.session_pb2.SecScheme2\n        setup_req.sec2.msg = proto.sec2_pb2.S2Session_Command0\n\n        setup_req.sec2.sc0.client_username = str_to_bytes(self.username)\n        self.srp6a_ctx = Srp6a(self.username, self.password)\n        if self.srp6a_ctx is None:\n            raise RuntimeError('Failed to initialize SRP6a instance!')\n\n        client_pubkey = long_to_bytes(self.srp6a_ctx.A)\n        setup_req.sec2.sc0.client_pubkey = client_pubkey\n\n        self._print_verbose(f'Client Public Key:\\t0x{client_pubkey.hex()}')\n        return setup_req.SerializeToString().decode('latin-1')\n\n    def setup0_response(self, response_data: bytes) -> None:\n        # Interpret SessionResp0 response packet\n        setup_resp = proto.session_pb2.SessionData()\n        setup_resp.ParseFromString(str_to_bytes(response_data))\n        self._print_verbose(f'Security version:\\t{str(setup_resp.sec_ver)}')\n        if setup_resp.sec_ver != proto.session_pb2.SecScheme2:\n            raise RuntimeError('Incorrect security scheme')\n\n        # Device public key, random salt and password verifier\n        device_pubkey = setup_resp.sec2.sr0.device_pubkey\n        device_salt = setup_resp.sec2.sr0.device_salt\n\n        self._print_verbose(f'Device Public Key:\\t0x{device_pubkey.hex()}')\n        self.client_pop_key = self.srp6a_ctx.process_challenge(device_salt, device_pubkey)\n\n    def setup1_request(self) -> Any:\n        # Form SessionCmd1 request packet using encrypted device public key\n        setup_req = proto.session_pb2.SessionData()\n        setup_req.sec_ver = proto.session_pb2.SecScheme2\n        setup_req.sec2.msg = proto.sec2_pb2.S2Session_Command1\n\n        # Encrypt device public key and attach to the request packet\n        if self.client_pop_key is None:\n            raise RuntimeError('Failed to generate client proof!')\n\n        self._print_verbose(f'Client Proof:\\t0x{self.client_pop_key.hex()}')\n        setup_req.sec2.sc1.client_proof = self.client_pop_key\n\n        return setup_req.SerializeToString().decode('latin-1')\n\n    def setup1_response(self, response_data: bytes) -> Any:\n        # Interpret SessionResp1 response packet\n        setup_resp = proto.session_pb2.SessionData()\n        setup_resp.ParseFromString(str_to_bytes(response_data))\n        # Ensure security scheme matches\n        if setup_resp.sec_ver == proto.session_pb2.SecScheme2:\n            # Read encrypyed device proof string\n            device_proof = setup_resp.sec2.sr1.device_proof\n            self._print_verbose(f'Device Proof:\\t0x{device_proof.hex()}')\n            self.srp6a_ctx.verify_session(device_proof)\n            if not self.srp6a_ctx.authenticated():\n                raise RuntimeError('Failed to verify device proof')\n        else:\n            raise RuntimeError('Unsupported security protocol')\n\n        # Getting the shared secret\n        shared_secret = self.srp6a_ctx.get_session_key()\n        self._print_verbose(f'Shared Secret:\\t0x{shared_secret.hex()}')\n\n        # Using the first 256 bits of a 512 bit key\n        session_key = shared_secret[:AES_KEY_LEN]\n        self._print_verbose(f'Session Key:\\t0x{session_key.hex()}')\n\n        # 96-bit nonce\n        self.nonce = bytearray(setup_resp.sec2.sr1.device_nonce)\n        if self.nonce is None:\n            raise RuntimeError('Received invalid nonce from device!')\n        self._print_verbose(f'Nonce:\\t0x{self.nonce.hex()}')\n\n        # Initialize the encryption engine with Shared Key and initialization vector\n        self.cipher = AESGCM(session_key)\n        if self.cipher is None:\n            raise RuntimeError('Failed to initialize AES-GCM cryptographic engine!')\n\n    def _increment_nonce(self) -> None:\n        \"\"\"Increment the last 4 bytes of nonce (big-endian counter).\"\"\"\n        if self.sec_patch_ver == 1:\n            counter = struct.unpack('>I', self.nonce[8:])[0]  # Read last 4 bytes as big-endian integer\n            counter += 1  # Increment counter\n            if counter > 0xFFFFFFFF:  # Check for overflow\n                raise RuntimeError('Nonce counter overflow')\n            self.nonce[8:] = struct.pack('>I', counter)  # Store back as big-endian\n\n    def encrypt_data(self, data: bytes) -> Any:\n        self._print_verbose(f'Nonce:\\t0x{self.nonce.hex()}')\n        ciphertext = self.cipher.encrypt(self.nonce, data, None)\n        self._increment_nonce()\n        return ciphertext\n\n    def decrypt_data(self, data: bytes) -> Any:\n        self._print_verbose(f'Nonce:\\t0x{self.nonce.hex()}')\n        plaintext = self.cipher.decrypt(self.nonce, data, None)\n        self._increment_nonce()\n        return plaintext\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/security/srp6a.py",
    "content": "# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\n\n# N     A large safe prime (N = 2q+1, where q is prime) [All arithmetic is done modulo N]\n# g     A generator modulo N\n# k     Multiplier parameter (k = H(N, g) in SRP-6a, k = 3 for legacy SRP-6)\n# s     User's salt\n# Iu    Username\n# p     Cleartext Password\n# H()   One-way hash function\n# ^     (Modular) Exponentiation\n# u     Random scrambling parameter\n# a, b  Secret ephemeral values\n# A, B  Public ephemeral values\n# x     Private key (derived from p and s)\n# v     Password verifier\n\nimport hashlib\nimport os\nfrom typing import Any, Callable, Optional, Tuple\n\nfrom utils import bytes_to_long, long_to_bytes\n\nSHA1 = 0\nSHA224 = 1\nSHA256 = 2\nSHA384 = 3\nSHA512 = 4\n\nNG_1024 = 0\nNG_2048 = 1\nNG_3072 = 2\nNG_4096 = 3\nNG_8192 = 4\n\n_hash_map = {SHA1: hashlib.sha1,\n             SHA224: hashlib.sha224,\n             SHA256: hashlib.sha256,\n             SHA384: hashlib.sha384,\n             SHA512: hashlib.sha512}\n\n\n_ng_const = (\n    # 1024-bit\n    ('''\\\nEEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496\\\nEA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8E\\\nF4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA\\\n9AFD5138FE8376435B9FC61D2FC0EB06E3''',\n     '2'),\n    # 2048\n    ('''\\\nAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4\\\nA099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF60\\\n95179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF\\\n747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B907\\\n8717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB37861\\\n60279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DB\\\nFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73''',\n     '2'),\n    # 3072\n    ('''\\\nFFFFFFFFFFFFFFFFC90FDAA22168C2\\\n34C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E\\\n3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B5\\\n76625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE\\\n9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D3\\\n9A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED5290770\\\n96966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E77\\\n2C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF69558171839\\\n95497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A\\\n33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6\\\nE1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA\\\n06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C77\\\n0988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2\\\nCAFFFFFFFFFFFFFFFF''',\n     '5'),\n    # 4096\n    ('''\\\nFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08\\\n8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B\\\n302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9\\\nA637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6\\\n49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8\\\nFD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D\\\n670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C\\\n180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718\\\n3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D\\\n04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D\\\nB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226\\\n1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C\\\nBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC\\\nE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26\\\n99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB\\\n04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2\\\n233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127\\\nD5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199\\\nFFFFFFFFFFFFFFFF''',\n     '5'),\n    # 8192\n    ('''\\\nFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08\\\n8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B\\\n302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9\\\nA637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6\\\n49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8\\\nFD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D\\\n670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C\\\n180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718\\\n3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D\\\n04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D\\\nB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226\\\n1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C\\\nBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC\\\nE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26\\\n99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB\\\n04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2\\\n233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127\\\nD5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492\\\n36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406\\\nAD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918\\\nDA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151\\\n2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03\\\nF482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F\\\nBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA\\\nCC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B\\\nB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632\\\n387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E\\\n6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA\\\n3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C\\\n5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9\\\n22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC886\\\n2F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6\\\n6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC5\\\n0846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268\\\n359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6\\\nFC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E71\\\n60C980DD98EDD3DFFFFFFFFFFFFFFFFF''',\n     '0x13')\n)\n\n\ndef get_ng(ng_type: int) -> Tuple[int, int]:\n    n_hex, g_hex = _ng_const[ng_type]\n    return int(n_hex, 16), int(g_hex, 16)\n\n\ndef get_random(nbytes: int) -> Any:\n    return bytes_to_long(os.urandom(nbytes))\n\n\ndef get_random_of_length(nbytes: int) -> Any:\n    offset = (nbytes * 8) - 1\n    return get_random(nbytes) | (1 << offset)\n\n\ndef H(hash_class: Callable, *args: Any, **kwargs: Any) -> int:\n    width = kwargs.get('width', None)\n\n    h = hash_class()\n\n    for s in args:\n        if s is not None:\n            data = long_to_bytes(s) if isinstance(s, int) else s\n            if width is not None:\n                h.update(bytes(width - len(data)))\n            h.update(data)\n\n    return int(h.hexdigest(), 16)\n\n\ndef H_N_xor_g(hash_class: Callable, N: int, g: int) -> bytes:\n    bin_N = long_to_bytes(N)\n    bin_g = long_to_bytes(g)\n\n    padding = len(bin_N) - len(bin_g)\n\n    hN = hash_class(bin_N).digest()\n    hg = hash_class(b''.join([b'\\0' * padding, bin_g])).digest()\n\n    return b''.join(long_to_bytes(hN[i] ^ hg[i]) for i in range(0, len(hN)))\n\n\ndef calculate_x(hash_class: Callable, s: Any, Iu: str, p: str) -> int:\n    _Iu = Iu.encode()\n    _p = p.encode()\n\n    return H(hash_class, s, H(hash_class, _Iu + b':' + _p))\n\n\ndef generate_salt_and_verifier(Iu: str, p: str, len_s: int, hash_alg: int = SHA512, ng_type: int = NG_3072) -> Tuple[bytes, bytes]:\n    hash_class = _hash_map[hash_alg]\n    N, g = get_ng(ng_type)\n\n    _s = long_to_bytes(get_random(len_s))\n    _v = long_to_bytes(pow(g, calculate_x(hash_class, _s, Iu, p), N))\n\n    return _s, _v\n\n\ndef calculate_M(hash_class: Callable, N: int, g: int, Iu: str, s: int, A: int, B: int, K: bytes) -> Any:\n    _Iu = Iu.encode()\n    h = hash_class()\n    h.update(H_N_xor_g(hash_class, N, g))\n    h.update(hash_class(_Iu).digest())\n    h.update(long_to_bytes(s))\n    h.update(long_to_bytes(A))\n    h.update(long_to_bytes(B))\n    h.update(K)\n    return h.digest()\n\n\ndef calculate_H_AMK(hash_class: Callable, A: int, M: bytes, K: bytes) -> Any:\n    h = hash_class()\n    h.update(long_to_bytes(A))\n    h.update(M)\n    h.update(K)\n    return h.digest()\n\n\nclass Srp6a (object):\n    def __init__(self, username: str, password: str, hash_alg: int = SHA512, ng_type: int = NG_3072):\n        hash_class = _hash_map[hash_alg]\n\n        N, g = get_ng(ng_type)\n        k = H(hash_class, N, g, width=len(long_to_bytes(N)))\n\n        self.Iu = username\n        self.p = password\n\n        self.a = get_random_of_length(32)\n        self.A = pow(g, self.a, N)\n\n        self.v: Optional[int] = None\n        self.K: Optional[bytes] = None\n        self.H_AMK = None\n        self._authenticated = False\n\n        self.hash_class = hash_class\n        self.N = N\n        self.g = g\n        self.k = k\n\n    def authenticated(self) -> bool:\n        return self._authenticated\n\n    def get_username(self) -> str:\n        return self.Iu\n\n    def get_ephemeral_secret(self) -> Any:\n        return long_to_bytes(self.a)\n\n    def get_session_key(self) -> Any:\n        return self.K if self._authenticated else None\n\n    def start_authentication(self) -> Tuple[str, bytes]:\n        return (self.Iu, long_to_bytes(self.A))\n\n    # Returns M or None if SRP-6a safety check is violated\n    def process_challenge(self, bytes_s: bytes, bytes_B: bytes) -> Any:\n        s = bytes_to_long(bytes_s)\n        B = bytes_to_long(bytes_B)\n\n        N = self.N\n        g = self.g\n        k = self.k\n\n        hash_class = self.hash_class\n\n        # SRP-6a safety check\n        if (B % N) == 0:\n            return None\n\n        u = H(hash_class, self.A, B, width=len(long_to_bytes(N)))\n        if u == 0:  # SRP-6a safety check\n            return None\n\n        x = calculate_x(hash_class, s, self.Iu, self.p)\n\n        v = pow(g, x, N)\n\n        S = pow((B - k * v), (self.a + u * x), N)\n\n        self.K = hash_class(long_to_bytes(S)).digest()\n\n        M = calculate_M(hash_class, N, g, self.Iu, s, self.A, B, self.K)\n        if not M:\n            return None\n\n        self.H_AMK = calculate_H_AMK(hash_class, self.A, M, self.K)\n\n        return M\n\n    def verify_session(self, host_HAMK: bytes) -> None:\n        if self.H_AMK == host_HAMK:\n            self._authenticated = True\n\n\nclass AuthenticationFailed (Exception):\n    pass\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/transport/__init__.py",
    "content": "# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\n\nfrom .transport_ble import *  # noqa: F403, F401\nfrom .transport_console import *  # noqa: F403, F401\nfrom .transport_http import *  # noqa: F403, F401\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/transport/ble_cli.py",
    "content": "# SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\n\nimport platform\n\nfrom utils import hex_str_to_bytes, str_to_bytes\n\nfallback = True\n\n\n# Check if required packages are installed\n# else fallback to console mode\ntry:\n    import bleak\n    fallback = False\nexcept ImportError:\n    pass\n\n\n# --------------------------------------------------------------------\n\ndef device_sort(device):\n    return device[0].address\n\n\nclass BLE_Bleak_Client:\n    def __init__(self):\n        self.adapter = None\n        self.adapter_props = None\n        self.characteristics = dict()\n        self.chrc_names = None\n        self.device = None\n        self.devname = None\n        self.iface = None\n        self.nu_lookup = None\n        self.services = None\n        self.srv_uuid_adv = None\n        self.srv_uuid_fallback = None\n\n    async def connect(self, devname, iface, chrc_names, fallback_srv_uuid):\n        self.devname = devname\n        self.srv_uuid_fallback = fallback_srv_uuid\n        self.chrc_names = [name.lower() for name in chrc_names]\n        self.iface = iface\n\n        print('Discovering...')\n        try:\n            discovery = await bleak.BleakScanner.discover(return_adv=True, adapter=self.iface)\n            devices = list(discovery.values())\n        except bleak.exc.BleakDBusError as e:\n            if str(e) == '[org.bluez.Error.NotReady] Resource Not Ready':\n                raise RuntimeError('Bluetooth is not ready. Maybe try `bluetoothctl power on`?')\n            raise\n\n        found_device = None\n\n        if self.devname is None:\n            if len(devices) == 0:\n                print('No devices found!')\n                exit(1)\n\n            while True:\n                devices.sort(key=device_sort)\n                print('==== BLE Discovery results ====')\n                print('{0: >4} {1: <33} {2: <12}'.format(\n                    'S.N.', 'Name', 'Address'))\n                for i, _ in enumerate(devices):\n                    print('[{0: >2}] {1: <33} {2: <12}'.format(i + 1, devices[i][0].name or 'Unknown', devices[i][0].address))\n\n                while True:\n                    try:\n                        select = int(input('Select device by number (0 to rescan) : '))\n                        if select < 0 or select > len(devices):\n                            raise ValueError\n                        break\n                    except ValueError:\n                        print('Invalid input! Retry')\n\n                if select != 0:\n                    break\n\n                discovery = await bleak.BleakScanner.discover(return_adv=True, adapter=self.iface)\n                devices = list(discovery.values())\n\n            self.devname = devices[select - 1][0].name\n            found_device = devices[select - 1]\n        else:\n            for d in devices:\n                if d[0].name == self.devname:\n                    found_device = d\n\n        if not found_device:\n            raise RuntimeError('Device not found')\n\n        uuids = found_device[1].service_uuids\n        # There should be 1 service UUID in advertising data\n        # If bluez had cached an old version of the advertisement data\n        # the list of uuids may be incorrect, in which case connection\n        # or service discovery may fail the first time. If that happens\n        # the cache will be refreshed before next retry\n        if len(uuids) == 1:\n            self.srv_uuid_adv = uuids[0]\n\n        print('Connecting...')\n        self.device = bleak.BleakClient(found_device[0].address, adapter=self.iface)\n        await self.device.connect()\n        # must be paired on Windows to access characteristics;\n        # cannot be paired on Mac\n        if platform.system() == 'Windows':\n            await self.device.pair()\n\n        print('Getting Services...')\n        services = self.device.services\n\n        service = services[self.srv_uuid_adv] or services[self.srv_uuid_fallback]\n        if not service:\n            await self.device.disconnect()\n            self.device = None\n            raise RuntimeError('Provisioning service not found')\n\n        nu_lookup = dict()\n        for characteristic in service.characteristics:\n            for descriptor in characteristic.descriptors:\n                if descriptor.uuid[4:8] != '2901':\n                    continue\n                readval = await self.device.read_gatt_descriptor(descriptor.handle)\n                found_name = ''.join(chr(b) for b in readval).lower()\n                nu_lookup[found_name] = characteristic.uuid\n                self.characteristics[characteristic.uuid] = characteristic\n\n        match_found = True\n        for name in self.chrc_names:\n            if name not in nu_lookup:\n                # Endpoint name not present\n                match_found = False\n                break\n\n        # Create lookup table only if all endpoint names found\n        self.nu_lookup = [None, nu_lookup][match_found]\n\n        return True\n\n    def get_nu_lookup(self):\n        return self.nu_lookup\n\n    def has_characteristic(self, uuid):\n        print('checking for characteristic ' + uuid)\n        if uuid in self.characteristics:\n            return True\n        return False\n\n    async def disconnect(self):\n        if self.device:\n            print('Disconnecting...')\n            if platform.system() == 'Windows':\n                await self.device.unpair()\n            await self.device.disconnect()\n            self.device = None\n            self.nu_lookup = None\n            self.characteristics = dict()\n\n    async def send_data(self, characteristic_uuid, data):\n        await self.device.write_gatt_char(characteristic_uuid, bytearray(data.encode('latin-1')), True)\n        readval = await self.device.read_gatt_char(characteristic_uuid)\n        return ''.join(chr(b) for b in readval)\n# --------------------------------------------------------------------\n\n\n# Console based BLE client for Cross Platform support\nclass BLE_Console_Client:\n    async def connect(self, devname, iface, chrc_names, fallback_srv_uuid):\n        print('BLE client is running in console mode')\n        print('\\tThis could be due to your platform not being supported or dependencies not being met')\n        print('\\tPlease ensure all pre-requisites are met to run the full fledged client')\n        print('BLECLI >> Please connect to BLE device `' + devname + '` manually using your tool of choice')\n        resp = input('BLECLI >> Was the device connected successfully? [y/n] ')\n        if resp != 'Y' and resp != 'y':\n            return False\n        print('BLECLI >> List available attributes of the connected device')\n        resp = input(\"BLECLI >> Is the service UUID '\" + fallback_srv_uuid + \"' listed among available attributes? [y/n] \")\n        if resp != 'Y' and resp != 'y':\n            return False\n        return True\n\n    def get_nu_lookup(self):\n        return None\n\n    def has_characteristic(self, uuid):\n        resp = input(\"BLECLI >> Is the characteristic UUID '\" + uuid + \"' listed among available attributes? [y/n] \")\n        if resp != 'Y' and resp != 'y':\n            return False\n        return True\n\n    async def disconnect(self):\n        pass\n\n    async def send_data(self, characteristic_uuid, data):\n        print(\"BLECLI >> Write following data to characteristic with UUID '\" + characteristic_uuid + \"' :\")\n        print('\\t>> ' + str_to_bytes(data).hex())\n        print('BLECLI >> Enter data read from characteristic (in hex) :')\n        resp = input('\\t<< ')\n        return hex_str_to_bytes(resp)\n\n\n# --------------------------------------------------------------------\n\n\n# Function to get client instance depending upon platform\ndef get_client():\n    if fallback:\n        return BLE_Console_Client()\n    return BLE_Bleak_Client()\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/transport/transport.py",
    "content": "# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\n\n# Base class for protocomm transport\n\nimport abc\n\n\nclass Transport():\n\n    @abc.abstractmethod\n    def send_session_data(self, data):\n        pass\n\n    @abc.abstractmethod\n    def send_config_data(self, data):\n        pass\n\n    async def disconnect(self):\n        pass\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/transport/transport_ble.py",
    "content": "# SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\n\nfrom . import ble_cli\nfrom .transport import Transport\n\nDEFAULT_BLE_ADAPTER = 'hci0'\n\n\nclass Transport_BLE(Transport):\n    def __init__(self, service_uuid, nu_lookup, ble_adapter=DEFAULT_BLE_ADAPTER):\n        self.nu_lookup = nu_lookup\n        self.service_uuid = service_uuid\n        self.name_uuid_lookup = None\n        self.ble_adapter = ble_adapter\n        # Expect service UUID like '0000ffff-0000-1000-8000-00805f9b34fb'\n        for name in nu_lookup.keys():\n            # Calculate characteristic UUID for each endpoint\n            nu_lookup[name] = service_uuid[:4] + '{:02x}'.format(\n                int(nu_lookup[name], 16) & int(service_uuid[4:8], 16)) + service_uuid[8:]\n\n        # Get BLE client module\n        self.cli = ble_cli.get_client()\n\n    async def connect(self, devname):\n        # Use client to connect to BLE device and bind to service\n        if not await self.cli.connect(devname=devname, iface=self.ble_adapter,\n                                      chrc_names=self.nu_lookup.keys(),\n                                      fallback_srv_uuid=self.service_uuid):\n            raise RuntimeError('Failed to initialize transport')\n\n        # Irrespective of provided parameters, let the client\n        # generate a lookup table by reading advertisement data\n        # and characteristic user descriptors\n        self.name_uuid_lookup = self.cli.get_nu_lookup()\n\n        # If that doesn't work, use the lookup table provided as parameter\n        if self.name_uuid_lookup is None:\n            self.name_uuid_lookup = self.nu_lookup\n            # Check if expected characteristics are provided by the service\n            for name in self.name_uuid_lookup.keys():\n                if not self.cli.has_characteristic(self.name_uuid_lookup[name]):\n                    raise RuntimeError(f\"'{name}' endpoint not found\")\n\n    async def disconnect(self):\n        await self.cli.disconnect()\n\n    async def send_data(self, ep_name, data):\n        # Write (and read) data to characteristic corresponding to the endpoint\n        if ep_name not in self.name_uuid_lookup.keys():\n            raise RuntimeError(f'Invalid endpoint: {ep_name}')\n        return await self.cli.send_data(self.name_uuid_lookup[ep_name], data)\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/transport/transport_console.py",
    "content": "# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\n\nfrom utils import hex_str_to_bytes, str_to_bytes\n\nfrom .transport import Transport\n\n\nclass Transport_Console(Transport):\n\n    async def send_data(self, path, data, session_id=0):\n        print('Client->Device msg :', path, session_id, str_to_bytes(data).hex())\n        try:\n            resp = input('Enter device->client msg : ')\n        except Exception as err:\n            print('error:', err)\n            return None\n        return hex_str_to_bytes(resp)\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/transport/transport_http.py",
    "content": "# SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\nimport socket\nfrom http.client import HTTPConnection, HTTPSConnection\n\nfrom utils import str_to_bytes\n\nfrom .transport import Transport\n\n\nclass Transport_HTTP(Transport):\n    def __init__(self, hostname, ssl_context=None):\n        try:\n            socket.gethostbyname(hostname.split(':')[0])\n        except socket.gaierror:\n            raise RuntimeError(f'Unable to resolve hostname: {hostname}')\n\n        if ssl_context is None:\n            self.conn = HTTPConnection(hostname, timeout=60)\n        else:\n            self.conn = HTTPSConnection(hostname, context=ssl_context, timeout=60)\n        try:\n            print(f'++++ Connecting to {hostname}++++')\n            self.conn.connect()\n        except Exception as err:\n            raise RuntimeError('Connection Failure : ' + str(err))\n        self.headers = {'Content-type': 'application/x-www-form-urlencoded','Accept': 'text/plain'}\n\n    def _send_post_request(self, path, data):\n        data = str_to_bytes(data) if isinstance(data, str) else data\n        try:\n            self.conn.request('POST', path, data, self.headers)\n            response = self.conn.getresponse()\n            # While establishing a session, the device sends the Set-Cookie header\n            # with value 'session=cookie_session_id' in its first response of the session to the tool.\n            # To maintain the same session, successive requests from the tool should include\n            # an additional 'Cookie' header with the above received value.\n            for hdr_key, hdr_val in response.getheaders():\n                if hdr_key == 'Set-Cookie':\n                    self.headers['Cookie'] = hdr_val\n            if response.status == 200:\n                return response.read().decode('latin-1')\n        except Exception as err:\n            raise RuntimeError('Connection Failure : ' + str(err))\n        raise RuntimeError('Server responded with error code ' + str(response.status))\n\n    async def send_data(self, ep_name, data):\n        return self._send_post_request('/' + ep_name, data)\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/utils/__init__.py",
    "content": "# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\n\nfrom .convenience import *  # noqa: F403, F401\n"
  },
  {
    "path": "network_provisioning/tool/esp_prov/utils/convenience.py",
    "content": "# SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n#\n\n# Convenience functions for commonly used data type conversions\n\ndef bytes_to_long(s: bytes) -> int:\n    return int.from_bytes(s, 'big')\n\n\ndef long_to_bytes(n: int) -> bytes:\n    if n == 0:\n        return b'\\x00'\n    return n.to_bytes((n.bit_length() + 7) // 8, 'big')\n\n\n# 'deadbeef' -> b'deadbeef'\ndef str_to_bytes(s: str) -> bytes:\n    return bytes(s, encoding='latin-1')\n\n\n# 'deadbeef' -> b'\\xde\\xad\\xbe\\xef'\ndef hex_str_to_bytes(s: str) -> bytes:\n    return bytes.fromhex(s)\n\n\ndef int_to_hex_str(n: int) -> str:\n    hex_string = format(n, 'x')\n    if len(hex_string) % 2 != 0:\n        hex_string = '0' + hex_string\n    return hex_string\n"
  },
  {
    "path": "nghttp/CMakeLists.txt",
    "content": "set(srcs\n    \"nghttp2/lib/nghttp2_buf.c\"\n    \"nghttp2/lib/nghttp2_callbacks.c\"\n    \"nghttp2/lib/nghttp2_debug.c\"\n    \"nghttp2/lib/nghttp2_extpri.c\"\n    \"nghttp2/lib/nghttp2_frame.c\"\n    \"nghttp2/lib/nghttp2_hd.c\"\n    \"nghttp2/lib/nghttp2_hd_huffman.c\"\n    \"nghttp2/lib/nghttp2_hd_huffman_data.c\"\n    \"nghttp2/lib/nghttp2_helper.c\"\n    \"nghttp2/lib/nghttp2_http.c\"\n    \"nghttp2/lib/nghttp2_map.c\"\n    \"nghttp2/lib/nghttp2_mem.c\"\n    \"nghttp2/lib/nghttp2_alpn.c\"\n    \"nghttp2/lib/nghttp2_option.c\"\n    \"nghttp2/lib/nghttp2_outbound_item.c\"\n    \"nghttp2/lib/nghttp2_pq.c\"\n    \"nghttp2/lib/nghttp2_priority_spec.c\"\n    \"nghttp2/lib/nghttp2_queue.c\"\n    \"nghttp2/lib/nghttp2_ratelim.c\"\n    \"nghttp2/lib/nghttp2_rcbuf.c\"\n    \"nghttp2/lib/nghttp2_session.c\"\n    \"nghttp2/lib/nghttp2_stream.c\"\n    \"nghttp2/lib/nghttp2_submit.c\"\n    \"nghttp2/lib/nghttp2_time.c\"\n    \"nghttp2/lib/nghttp2_version.c\"\n    \"nghttp2/lib/sfparse.c\")\n\nidf_component_register(SRCS \"${srcs}\"\n                    INCLUDE_DIRS port/include nghttp2/lib/includes\n                    PRIV_INCLUDE_DIRS nghttp2/lib port/private_include)\n\ntarget_compile_options(${COMPONENT_LIB} PRIVATE \"-Wno-format\")\ntarget_compile_definitions(${COMPONENT_LIB} PUBLIC \"-DHAVE_CONFIG_H\")\n\n# Override nghttp2_session.h with our own version to override inbound buffer length\ntarget_compile_options(${COMPONENT_LIB} PRIVATE\n    \"SHELL:-include \\\"${CMAKE_CURRENT_SOURCE_DIR}/port/private_include/esp_nghttp2_session.h\\\"\")\n"
  },
  {
    "path": "nghttp/Kconfig",
    "content": "menu \"NGHTTP configuration\"\n\n    config ESP_NGHTTP2_INBOUND_BUFFER_LENGTH\n        int \"Nghttp2 inbound buffer length\"\n        default 4096\n        help\n            Set the size of the inbound buffer for nghttp2. This buffer is used to store incoming HTTP/2 frames.\n            The default value is 16KB as per nghttp2 library configuration but here we have set it to 4KB. The\n            receive buffer gets placed on the stack and hence adjust this value based on your application needs\n            and available stack size.\n\nendmenu\n"
  },
  {
    "path": "nghttp/idf_component.yml",
    "content": "version: \"1.68.1\"\ndescription: \"nghttp2 - HTTP/2 C Library\"\nurl: https://github.com/espressif/idf-extra-components/tree/master/nghttp\ndependencies:\n  idf: \">=5.0\"\nsbom:\n  manifests:\n    - path: sbom_nghttp2.yml\n      dest: nghttp2\n"
  },
  {
    "path": "nghttp/port/include/nghttp2/nghttp2ver.h",
    "content": "/*\n * nghttp2 - HTTP/2 C Library\n *\n * Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n#ifndef NGHTTP2VER_H\n#define NGHTTP2VER_H\n\n/**\n * @macro\n * Version number of the nghttp2 library release\n */\n#define NGHTTP2_VERSION \"1.68.1\"\n\n/**\n * @macro\n * Numerical representation of the version number of the nghttp2 library\n * release. This is a 24 bit number with 8 bits for major number, 8 bits\n * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.\n */\n#define NGHTTP2_VERSION_NUM 0x014400\n\n#endif /* NGHTTP2VER_H */\n"
  },
  {
    "path": "nghttp/port/private_include/config.h",
    "content": "#ifndef __HAVE_CONFIG_H_\r\n#define __HAVE_CONFIG_H_\r\n\r\n#define _U_\r\n\r\n#define SIZEOF_INT_P 2\r\n\r\n#include \"stdio.h\"\r\n#include \"stdlib.h\"\r\n#include \"string.h\"\r\n\r\n/* Define to 1 if you have the `clock_gettime' function. */\r\n#define HAVE_CLOCK_GETTIME 1\r\n\r\n/* Define to 1 if you have the <time.h> header file. */\r\n#define HAVE_TIME_H 1\r\n\r\n#if (!defined(nghttp_unlikely))\r\n#define nghttp_unlikely(Expression) !!(Expression)\r\n#endif\r\n\r\n#define nghttp_ASSERT(Expression) do{if (!(Expression)) printf(\"%d\\n\", __LINE__);}while(0)\r\n\r\n#define CU_ASSERT(a) nghttp_ASSERT(a)\r\n#define CU_ASSERT_FATAL(a) nghttp_ASSERT(a)\r\n\r\n#define NGHTTP_PLATFORM_HTONS(_n)  ((uint16_t)((((_n) & 0xff) << 8) | (((_n) >> 8) & 0xff)))\r\n#define NGHTTP_PLATFORM_HTONL(_n)  ((uint32_t)( (((_n) & 0xff) << 24) | (((_n) & 0xff00) << 8) | (((_n) >> 8)  & 0xff00) | (((_n) >> 24) & 0xff) ))\r\n\r\n#define htons(x) NGHTTP_PLATFORM_HTONS(x)\r\n#define ntohs(x) NGHTTP_PLATFORM_HTONS(x)\r\n#define htonl(x) NGHTTP_PLATFORM_HTONL(x)\r\n#define ntohl(x) NGHTTP_PLATFORM_HTONL(x)\r\n\r\n#endif // __HAVE_CONFIG_H_\r\n"
  },
  {
    "path": "nghttp/port/private_include/esp_nghttp2_session.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include \"nghttp2_session.h\"\n#include \"sdkconfig.h\"\n\n// Redefine NGHTTP2_INBOUND_BUFFER_LENGTH to the value from sdkconfig\n#undef NGHTTP2_INBOUND_BUFFER_LENGTH\n#define NGHTTP2_INBOUND_BUFFER_LENGTH CONFIG_ESP_NGHTTP2_INBOUND_BUFFER_LENGTH\n"
  },
  {
    "path": "nghttp/sbom_nghttp2.yml",
    "content": "name: nghttp2\nversion: 1.68.1\ncpe: cpe:2.3:a:nghttp2:nghttp2:{}:*:*:*:*:*:*:*\nsupplier: 'Organization: nghttp2 <https://nghttp2.org/'\ndescription: nghttp2 - HTTP/2 C Library and tools\nurl: https://github.com/nghttp2/nghttp2\nhash: f769990597670f3ea8d2440d1e18a3f9a0df9bc0\ncve-exclude-list:\n  - cve: CVE-2026-27135\n    reason: Fixed in v1.68.1. See https://github.com/nghttp2/nghttp2/commit/310c239817118dc0b6be0c2184a7b6c39f751a45\n"
  },
  {
    "path": "onewire_bus/.build-test-rules.yml",
    "content": "onewire_bus/test_apps:\n  disable:\n    - if: CONFIG_NAME == \"rmt\" and SOC_RMT_SUPPORTED != 1\n      reason: RMT backend variant requires SOC RMT support\n    - if: CONFIG_NAME == \"uart\" and SOC_UART_SUPPORTED != 1\n      reason: UART backend variant requires SOC UART support\n"
  },
  {
    "path": "onewire_bus/CHANGELOG.md",
    "content": "## 1.1.0\n\n- Add UART backend support for 1-Wire bus (`onewire_new_bus_uart`) alongside the existing RMT backend.\n\n## 1.0.4\n\n- Support `en_pull_up` config option in `onewire_bus_config_t`, which can enable the internal pull-up resistor on the GPIO pin used for the one-wire bus. This is useful when using a GPIO pin that does not have a pull-up resistor connected externally.\n\n## 1.0.3\n\n- Improve the driver to support esp-idf v6.0\n\n## 1.0.2\n\n- raise recovery time to support more sensor on longer wire (d0b2b52)\n\n## 1.0.0\n\n- Initial driver version, with the RMT driver as backend controller\n"
  },
  {
    "path": "onewire_bus/CMakeLists.txt",
    "content": "set(srcs \"src/onewire_bus_api.c\"\n         \"src/onewire_crc.c\"\n         \"src/onewire_device.c\")\n\nif(CONFIG_SOC_RMT_SUPPORTED)\n     list(APPEND srcs \"src/onewire_bus_impl_rmt.c\")\nendif()\n\nif(CONFIG_SOC_UART_SUPPORTED)\n     list(APPEND srcs \"src/onewire_bus_impl_uart.c\")\nendif()\n\nset(priv_requires)\n# Starting from esp-idf v5.3, the peripheral drivers are in separate components\nif(\"${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}\" VERSION_GREATER_EQUAL \"5.3\")\n    list(APPEND priv_requires \"esp_driver_rmt\" \"esp_driver_uart\" \"esp_driver_gpio\")\nelse()\n    list(APPEND priv_requires \"driver\")\nendif()\n\nidf_component_register(SRCS ${srcs}\n                       INCLUDE_DIRS \"include\" \"interface\"\n                       PRIV_REQUIRES ${priv_requires})\n"
  },
  {
    "path": "onewire_bus/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "onewire_bus/README.md",
    "content": "# Dallas 1-Wire Bus Driver\n\n[![Component Registry](https://components.espressif.com/components/espressif/onewire_bus/badge.svg)](https://components.espressif.com/components/espressif/onewire_bus)\n\nThis directory contains an implementation for Dallas 1-Wire bus by different peripherals.\nThe following low-level backends are currently supported:\n\n- RMT backend (`onewire_new_bus_rmt`)\n- UART backend (`onewire_new_bus_uart`)\n\n## Features\n\n- Automatic 1-Wire bus initialization with RMT or UART backend\n- Device discovery and enumeration on the bus\n- Read/write operations at bit and byte level\n- Built-in CRC8 calculation for data integrity\n- Support for multiple devices on a single bus\n\n## Add to Your Project\n\nAdd the `onewire_bus` component to your project via the ESP Component Registry:\n\n```bash\nidf.py add-dependency \"espressif/onewire_bus\"\n```\n\n## Documentation\n\n- [API Reference](https://espressif.github.io/idf-extra-components/latest/onewire_bus/index.html) - Detailed API documentation\n\n## Appendix\n\n* [DS18B20 device driver based on the 1-Wire Bus driver](https://components.espressif.com/components/espressif/ds18b20) and the [DS18B20 Example](https://github.com/espressif/esp-bsp/tree/master/components/ds18b20/examples/ds18b20_read)\n"
  },
  {
    "path": "onewire_bus/docs/Doxyfile",
    "content": "# Set this to the header file you want\nINPUT = \\\n    ../include/ \\\n    ../interface/\n\n# The output directory for the generated XML documentation\nOUTPUT_DIRECTORY = doxygen_output\n\n# Warning-related settings, it's recommended to keep them enabled\nWARN_IF_UNDOC_ENUM_VAL = YES\nWARN_AS_ERROR = YES\n\n# Other common settings\nFULL_PATH_NAMES = YES\nSTRIP_FROM_PATH = ../\nSTRIP_FROM_INC_PATH = ../\nENABLE_PREPROCESSING   = YES\nMACRO_EXPANSION        = YES\nOPTIMIZE_OUTPUT_FOR_C  = YES\nEXPAND_ONLY_PREDEF     = YES\nEXTRACT_ALL            = YES\nPREDEFINED             = $(ENV_DOXYGEN_DEFINES)\nHAVE_DOT = NO\nGENERATE_XML    = YES\nXML_OUTPUT      = xml\nGENERATE_HTML   = NO\nHAVE_DOT        = NO\nGENERATE_LATEX  = NO\nQUIET = YES\nMARKDOWN_SUPPORT = YES\n"
  },
  {
    "path": "onewire_bus/docs/book.toml",
    "content": "[book]\ntitle = \"1-Wire Bus Documentation\"\nlanguage = \"en\"\n\n[output.html]\ndefault-theme = \"light\"\ngit-repository-url = \"https://github.com/espressif/idf-extra-components/tree/master/onewire_bus\"\nedit-url-template = \"https://github.com/espressif/idf-extra-components/edit/master/onewire_bus/docs/{path}\"\n"
  },
  {
    "path": "onewire_bus/docs/src/SUMMARY.md",
    "content": "# Summary\n\n---\n\n# Programming Guide\n\n- [1-Wire Bus](index.md)\n\n---\n\n# API Reference\n\n- [API Reference](api.md)\n"
  },
  {
    "path": "onewire_bus/docs/src/api.md",
    "content": "# API Reference\n\n<div class=\"warning\">\n\nThis file is automatically generated by esp-doxybook.\n\nDO NOT edit it manually.\n\n</div>\n"
  },
  {
    "path": "onewire_bus/docs/src/index.md",
    "content": "# 1-Wire Bus Programming Guide\n\nThe 1-Wire bus driver provides a generic interface for communicating with Dallas/Maxim 1-Wire devices. It supports multiple hardware backends (RMT and UART) and handles the low-level timing requirements of the 1-Wire protocol automatically.\n\n## Overview\n\n1-Wire is a device communications bus system that uses a single data line plus ground for communication. Common 1-Wire devices include temperature sensors (DS18B20), EEPROMs (DS2431), and real-time clocks (DS3234).\n\nThis driver provides:\n- Automatic 1-Wire bus initialization with RMT or UART backend\n- Device discovery and enumeration on the bus\n- Read/write operations at bit and byte level\n- Built-in CRC8 calculation for data integrity\n\n## Add the Component to Your Project\n\nAdd the `onewire_bus` component to your project via the ESP Component Registry:\n\n```bash\nidf.py add-dependency \"espressif/onewire_bus\"\n```\n\n## Allocate 1-Wire Bus with RMT Backend\n\nThe RMT backend is the recommended approach for most ESP32 chips that support the RMT peripheral. It provides precise timing control for 1-Wire communication.\n\n```c\n#include \"onewire_bus.h\"\n\n// 1-Wire bus configuration\nonewire_bus_config_t bus_config = {\n    .bus_gpio_num = 4,              // GPIO pin connected to the 1-Wire bus data line\n    .flags = {\n        .en_pull_up = false,        // Set true to enable internal pull-up (external pull-up recommended)\n    }\n};\n\n// RMT backend specific configuration\nonewire_bus_rmt_config_t rmt_config = {\n    .max_rx_bytes = 10,             // Maximum bytes expected in a single receive operation\n};\n\n// Create the 1-Wire bus handle\nonewire_bus_handle_t bus = NULL;\nESP_ERROR_CHECK(onewire_new_bus_rmt(&bus_config, &rmt_config, &bus));\n```\n\n### Notes on RMT Backend\n\n- The RMT backend uses a pair of RMT TX and RX channels internally\n- The `max_rx_bytes` value determines the size of the internal receive buffer. Set this based on the maximum response size you expect from your devices\n- An external 4.7kΩ pull-up resistor is recommended for reliable communication, especially when multiple devices are on the bus or cable lengths are long\n\n## Allocate 1-Wire Bus with UART Backend\n\nThe UART backend is an alternative that uses the UART peripheral with open-drain configuration. This is useful when RMT channels are not available.\n\n```c\n#include \"onewire_bus.h\"\n\n// 1-Wire bus configuration\nonewire_bus_config_t bus_config = {\n    .bus_gpio_num = 4,              // GPIO pin connected to the 1-Wire bus data line\n    .flags = {\n        .en_pull_up = false,        // Set true to enable internal pull-up (external pull-up recommended)\n    }\n};\n\n// UART backend specific configuration\nonewire_bus_uart_config_t uart_config = {\n    .uart_port_num = 1,             // UART port number to use\n};\n\n// Create the 1-Wire bus handle\nonewire_bus_handle_t bus = NULL;\nESP_ERROR_CHECK(onewire_new_bus_uart(&bus_config, &uart_config, &bus));\n```\n\n### Notes on UART Backend\n\n- Both the UART TX and RX paths are configured to the same GPIO pin (`bus_gpio_num`)\n- The GPIO is automatically configured as open-drain mode\n\n## Enumerate Devices on the Bus\n\nAfter initializing the bus, you can discover all 1-Wire devices connected to it. Each 1-Wire device has a unique 64-bit ROM address.\n\n```c\n// Create a device iterator\nonewire_device_iter_handle_t iter = NULL;\nESP_ERROR_CHECK(onewire_new_device_iter(bus, &iter));\n\n// Enumerate all devices on the bus\nonewire_device_t dev;\nwhile (onewire_device_iter_get_next(iter, &dev) == ESP_OK) {\n    ESP_LOGI(\"example\", \"Found device with address: %016llX\", dev.address);\n}\n\n// Delete the iterator when done\nESP_ERROR_CHECK(onewire_del_device_iter(iter));\n```\n\n### Notes on Device Enumeration\n\n- The iterator performs a 1-Wire search algorithm to find all devices on the bus\n- Each call to `onewire_device_iter_get_next()` returns the next device found\n- The device address contains the family code (first byte), serial number (middle 6 bytes), and CRC (last byte)\n- Call the iterator functions again if you need to re-scan the bus for newly connected devices\n\n## Communicate with Devices\n\n### Reset the Bus\n\nBefore each communication sequence, send a reset pulse to check for device presence:\n\n```c\nesp_err_t ret = onewire_bus_reset(bus);\nif (ret == ESP_OK) {\n    ESP_LOGI(\"example\", \"Device(s) present on the bus\");\n} else if (ret == ESP_ERR_NOT_FOUND) {\n    ESP_LOGW(\"example\", \"No devices found on the bus\");\n}\n```\n\n### Send Commands and Data\n\nYou can communicate with devices using the byte-level or bit-level functions:\n\n```c\n// Send a command byte (e.g., SKIP ROM command to address all devices)\nuint8_t cmd = ONEWIRE_CMD_SKIP_ROM;\nESP_ERROR_CHECK(onewire_bus_write_bytes(bus, &cmd, 1));\n\n// Write a read temperature command to a DS18B20\nuint8_t convert_cmd = 0x44;\nESP_ERROR_CHECK(onewire_bus_write_bytes(bus, &convert_cmd, 1));\n\n// Read response data\nuint8_t scratchpad[9];\nESP_ERROR_CHECK(onewire_bus_read_bytes(bus, scratchpad, 9));\n```\n\n### Working with a Specific Device\n\nWhen multiple devices are on the bus, use the MATCH ROM command to address a specific device:\n\n```c\n// First, find the device address using the iterator (shown above)\nonewire_device_iter_handle_t iter = NULL;\nESP_ERROR_CHECK(onewire_new_device_iter(bus, &iter));\n\nonewire_device_t dev;\nif (onewire_device_iter_get_next(iter, &dev) == ESP_OK) {\n    // Reset and send MATCH ROM command followed by the device address\n    ESP_ERROR_CHECK(onewire_bus_reset(bus));\n\n    uint8_t match_cmd = ONEWIRE_CMD_MATCH_ROM;\n    ESP_ERROR_CHECK(onewire_bus_write_bytes(bus, &match_cmd, 1));\n    ESP_ERROR_CHECK(onewire_bus_write_bytes(bus, (uint8_t *)&dev.address, 8));\n\n    // Now you can communicate with this specific device\n    uint8_t read_cmd = 0xBE;  // Read scratchpad command for DS18B20\n    ESP_ERROR_CHECK(onewire_bus_write_bytes(bus, &read_cmd, 1));\n\n    uint8_t data[9];\n    ESP_ERROR_CHECK(onewire_bus_read_bytes(bus, data, 9));\n}\n\nESP_ERROR_CHECK(onewire_del_device_iter(iter));\n```\n\n## Verify Data with CRC\n\nThe 1-Wire protocol uses CRC8 for data integrity. The driver provides a CRC8 utility function:\n\n```c\n#include \"onewire_crc.h\"\n\n// Calculate CRC8 for received data\nuint8_t data[9];  // Received scratchpad data\nESP_ERROR_CHECK(onewire_bus_read_bytes(bus, data, 9));\n\n// Verify CRC - the result should be 0 if data is correct\nuint8_t crc = onewire_crc8(0, data, 9);\nif (crc == 0) {\n    ESP_LOGI(\"example\", \"Data CRC verified OK\");\n} else {\n    ESP_LOGE(\"example\", \"Data CRC mismatch\");\n}\n```\n\n## Free Resources\n\nWhen you are done using the 1-Wire bus, free the allocated resources:\n\n```c\nESP_ERROR_CHECK(onewire_bus_del(bus));\n```\n\n## Common 1-Wire Commands\n\nThe driver provides commonly used 1-Wire command definitions:\n\n| Command | Value | Description |\n|---------|-------|-------------|\n| `ONEWIRE_CMD_SEARCH_NORMAL` | 0xF0 | Search for all devices on the bus |\n| `ONEWIRE_CMD_MATCH_ROM` | 0x55 | Address a specific device by its ROM address |\n| `ONEWIRE_CMD_SKIP_ROM` | 0xCC | Address all devices on the bus simultaneously |\n| `ONEWIRE_CMD_SEARCH_ALARM` | 0xEC | Search for devices in alarm condition |\n| `ONEWIRE_CMD_READ_POWER_SUPPLY` | 0xB4 | Check if devices are parasitically powered |\n\n## FAQ\n\n- **Do I need an external pull-up resistor?**\n  - Yes, a 4.7kΩ pull-up resistor is recommended for reliable communication. The internal pull-up may not provide enough current for some devices, especially with longer cables or multiple devices.\n\n- **Which backend should I use, RMT or UART?**\n  - Use RMT backend if your chip supports it and you have free RMT channels. It provides more precise timing. Use UART backend when RMT is unavailable or all channels are in use.\n\n- **How many devices can I connect to a single 1-Wire bus?**\n  - The 1-Wire protocol supports many devices on a single bus (limited by the 64-bit address space). In practice, the limit is determined by bus capacitance and power supply capabilities.\n\n- **How do I communicate with a specific device when multiple devices are on the bus?**\n  - First enumerate devices using the device iterator to get their addresses. Then use the `ONEWIRE_CMD_MATCH_ROM` command followed by the 8-byte device address to select a specific device before sending commands.\n\n- **Where can I find a complete example?**\n  - See the [DS18B20 device driver](https://components.espressif.com/components/espressif/ds18b20) and the [DS18B20 Example](https://github.com/espressif/esp-bsp/tree/master/components/ds18b20/examples/ds18b20_read) for a complete working implementation based on this 1-Wire bus driver.\n"
  },
  {
    "path": "onewire_bus/idf_component.yml",
    "content": "version: \"1.1.0\"\ndescription: Driver for Dallas 1-Wire bus\nurl: https://github.com/espressif/idf-extra-components/tree/master/onewire_bus\nrepository: https://github.com/espressif/idf-extra-components.git\ndocumentation: https://espressif.github.io/idf-extra-components/latest/onewire_bus/index.html\nissues: https://github.com/espressif/idf-extra-components/issues\ndependencies:\n  idf: \">=5.0\"\n"
  },
  {
    "path": "onewire_bus/include/onewire_bus.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdint.h>\n#include \"esp_err.h\"\n#include \"soc/soc_caps.h\"\n#include \"onewire_types.h\"\n#if SOC_RMT_SUPPORTED\n#include \"onewire_bus_impl_rmt.h\"\n#endif\n#if SOC_UART_SUPPORTED\n#include \"onewire_bus_impl_uart.h\"\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief Write bytes to 1-wire bus\n *\n * @param[in] bus 1-Wire bus handle\n * @param[in] tx_data pointer to data to be sent\n * @param[in] tx_data_size size of data to be sent, in bytes\n * @return\n *      - ESP_OK: Write bytes to 1-Wire bus successfully\n *      - ESP_ERR_INVALID_ARG: Write bytes to 1-Wire bus failed because of invalid argument\n *      - ESP_FAIL: Write bytes to 1-Wire bus failed because of other errors\n */\nesp_err_t onewire_bus_write_bytes(onewire_bus_handle_t bus, const uint8_t *tx_data, uint8_t tx_data_size);\n\n/**\n * @brief Read bytes from 1-wire bus\n *\n * @param[in] bus 1-wire bus handle\n * @param[out] rx_buf pointer to buffer to store received data\n * @param[in] rx_buf_size size of buffer to store received data, in bytes\n * @return\n *      - ESP_OK: Read bytes from 1-Wire bus successfully\n *      - ESP_ERR_INVALID_ARG: Read bytes from 1-Wire bus failed because of invalid argument\n *      - ESP_FAIL: Read bytes from 1-Wire bus failed because of other errors\n */\nesp_err_t onewire_bus_read_bytes(onewire_bus_handle_t bus, uint8_t *rx_buf, size_t rx_buf_size);\n\n/**\n * @brief Write a bit to 1-wire bus, this is a blocking function\n *\n * @param[in] bus 1-wire bus handle\n * @param[in] tx_bit bit to transmit, 0 for zero bit, other for one bit\n * @return\n *         - ESP_OK                Write bit to 1-wire bus successfully.\n *         - ESP_ERR_INVALID_ARG   Invalid argument.\n */\nesp_err_t onewire_bus_write_bit(onewire_bus_handle_t bus, uint8_t tx_bit);\n\n/**\n * @brief Read a bit from 1-wire bus\n *\n * @param[in] bus 1-wire bus handle\n * @param[out] rx_bit received bit, 0 for zero bit, 1 for one bit\n * @return\n *         - ESP_OK                Read bit from 1-wire bus successfully.\n *         - ESP_ERR_INVALID_ARG   Invalid argument.\n */\nesp_err_t onewire_bus_read_bit(onewire_bus_handle_t bus, uint8_t *rx_bit);\n\n/**\n * @brief Send reset pulse to the bus, and check if there are devices attached to the bus\n *\n * @param[in] bus 1-Wire bus handle\n *\n * @return\n *      - ESP_OK: Reset 1-Wire bus successfully and find device on the bus\n *      - ESP_ERR_NOT_FOUND: Reset 1-Wire bus successfully but no device found on the bus\n *      - ESP_FAIL: Reset 1-Wire bus failed because of other errors\n */\nesp_err_t onewire_bus_reset(onewire_bus_handle_t bus);\n\n/**\n * @brief Free 1-Wire bus resources\n *\n * @param[in] bus 1-Wire bus handle\n *\n * @return\n *      - ESP_OK: Free resources successfully\n *      - ESP_FAIL: Free resources failed because error occurred\n */\nesp_err_t onewire_bus_del(onewire_bus_handle_t bus);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "onewire_bus/include/onewire_bus_impl_rmt.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdint.h>\n#include \"esp_err.h\"\n#include \"onewire_types.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief 1-Wire bus RMT specific configuration\n */\ntypedef struct {\n    uint32_t max_rx_bytes; /*!< Set the largest possible single receive size,\n                                which determines the size of the internal buffer that used to save the receiving RMT symbols */\n} onewire_bus_rmt_config_t;\n\n/**\n * @brief Create 1-Wire bus with RMT backend\n *\n * @note One 1-Wire bus utilizes a pair of RMT TX and RX channels\n *\n * @param[in] bus_config 1-Wire bus configuration\n * @param[in] rmt_config RMT specific configuration\n * @param[out] ret_bus Returned 1-Wire bus handle\n * @return\n *      - ESP_OK: create 1-Wire bus handle successfully\n *      - ESP_ERR_INVALID_ARG: create 1-Wire bus handle failed because of invalid argument\n *      - ESP_ERR_NO_MEM: create 1-Wire bus handle failed because of out of memory\n *      - ESP_FAIL: create 1-Wire bus handle failed because some other error\n */\nesp_err_t onewire_new_bus_rmt(const onewire_bus_config_t *bus_config, const onewire_bus_rmt_config_t *rmt_config, onewire_bus_handle_t *ret_bus);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "onewire_bus/include/onewire_bus_impl_uart.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdint.h>\n#include \"esp_err.h\"\n#include \"onewire_types.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief 1-Wire bus UART specific configuration\n */\ntypedef struct {\n    int uart_port_num; /*!< UART port number, e.g. UART_NUM_1 */\n} onewire_bus_uart_config_t;\n\n/**\n * @brief Create 1-Wire bus with UART backend\n *\n * @note TX and RX will both be configured to bus_config->bus_gpio_num.\n *       And this GPIO will be configured as open-drain mode.\n *\n * @param[in] bus_config 1-Wire bus configuration\n * @param[in] uart_config UART specific configuration\n * @param[out] ret_bus Returned 1-Wire bus handle\n * @return\n *      - ESP_OK: create 1-Wire bus handle successfully\n *      - ESP_ERR_INVALID_ARG: create 1-Wire bus handle failed because of invalid argument\n *      - ESP_ERR_NO_MEM: create 1-Wire bus handle failed because of out of memory\n *      - ESP_FAIL: create 1-Wire bus handle failed because some other error\n */\nesp_err_t onewire_new_bus_uart(const onewire_bus_config_t *bus_config, const onewire_bus_uart_config_t *uart_config, onewire_bus_handle_t *ret_bus);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "onewire_bus/include/onewire_cmd.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#define ONEWIRE_CMD_SEARCH_NORMAL      0xF0\n#define ONEWIRE_CMD_MATCH_ROM          0x55\n#define ONEWIRE_CMD_SKIP_ROM           0xCC\n#define ONEWIRE_CMD_SEARCH_ALARM       0xEC\n#define ONEWIRE_CMD_READ_POWER_SUPPLY  0xB4\n"
  },
  {
    "path": "onewire_bus/include/onewire_crc.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdint.h>\n#include <stddef.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief Calculate Dallas CRC8 value of a given buffer\n *\n * @param[in] init_crc Initial CRC value\n * @param[in] input Input buffer to calculate CRC value\n * @param[in] input_size Size of input buffer, in bytes\n * @return CRC8 result of the input buffer\n */\nuint8_t onewire_crc8(uint8_t init_crc, uint8_t *input, size_t input_size);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "onewire_bus/include/onewire_device.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdint.h>\n#include \"esp_err.h\"\n#include \"onewire_types.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief 1-Wire device generic type\n */\ntypedef struct onewire_device_t {\n    onewire_bus_handle_t bus;         /*!< Which bus the 1-Wire device is attached to */\n    onewire_device_address_t address; /*!< Device address (represented by its internal ROM ID) */\n} onewire_device_t;\n\n/**\n * @brief Create an iterator to enumerate the 1-Wire devices on the bus\n *\n * @param[in] bus 1-Wire bus handle\n * @param[out] ret_iter Returned created device iterator\n * @return\n *      - ESP_OK: Create device iterator successfully\n *      - ESP_ERR_INVALID_ARG: Invalid argument\n *      - ESP_ERR_NO_MEM: No memory to create device iterator\n *      - ESP_FAIL: Other errors\n */\nesp_err_t onewire_new_device_iter(onewire_bus_handle_t bus, onewire_device_iter_handle_t *ret_iter);\n\n/**\n * @brief Delete the device iterator\n *\n * @param[in] iter Device iterator handle\n * @return\n *      - ESP_OK: Delete device iterator successfully\n *      - ESP_ERR_INVALID_ARG: Invalid argument\n *      - ESP_FAIL: Other errors\n */\nesp_err_t onewire_del_device_iter(onewire_device_iter_handle_t iter);\n\n/**\n * @brief Get the next 1-Wire device from the iterator\n *\n * @param[in] iter Device iterator handle\n * @param[out] dev Returned 1-Wire device handle\n * @return\n *      - ESP_OK: Get next device successfully\n *      - ESP_ERR_INVALID_ARG: Invalid argument\n *      - ESP_ERR_NOT_FOUND: No more device to get\n *      - ESP_FAIL: Other errors\n */\nesp_err_t onewire_device_iter_get_next(onewire_device_iter_handle_t iter, onewire_device_t *dev);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "onewire_bus/include/onewire_types.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdint.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief Type of 1-Wire bus handle\n */\ntypedef struct onewire_bus_t *onewire_bus_handle_t;\n\n/**\n * @brief Type of the address for a 1-Wire compatible device\n */\ntypedef uint64_t onewire_device_address_t;\n\n/**\n * @brief Type of 1-Wire device iterator handle\n */\ntypedef struct onewire_device_iter_t *onewire_device_iter_handle_t;\n\n/**\n * @brief 1-Wire bus configuration\n */\ntypedef struct {\n    int bus_gpio_num; /*!< GPIO number that used by the 1-Wire bus */\n    struct onewire_bus_config_flags {\n        uint32_t en_pull_up: 1; /*!< Set true to enable internal pull-up resistor.\n                                     Please note the internal pull-up resistor cannot provide enough current for some devices,\n                                     so external pull-up resistor is still recommended. */\n    } flags; /*!< Configuration flags for the bus */\n} onewire_bus_config_t;\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "onewire_bus/interface/onewire_bus_interface.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdint.h>\n#include \"esp_err.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct onewire_bus_t onewire_bus_t; /*!< Type of 1-Wire bus */\n\n/**\n * @brief 1-Wire bus interface definition\n */\nstruct onewire_bus_t {\n    /**\n     * @brief Write bytes to 1-wire bus\n     *\n     * @note This is a blocking function\n     *\n     * @param[in] bus 1-Wire bus handle\n     * @param[in] tx_data pointer to data to be sent\n     * @param[in] tx_data_size size of data to be sent, in bytes\n     * @return\n     *      - ESP_OK: Write bytes to 1-Wire bus successfully\n     *      - ESP_ERR_INVALID_ARG: Write bytes to 1-Wire bus failed because of invalid argument\n     *      - ESP_FAIL: Write bytes to 1-Wire bus failed because of other errors\n     */\n    esp_err_t (*write_bytes)(onewire_bus_t *bus, const uint8_t *tx_data, uint8_t tx_data_size);\n\n    /**\n     * @brief Read bytes from 1-wire bus\n     *\n     * @param[in] bus 1-wire bus handle\n     * @param[out] rx_buf pointer to buffer to store received data\n     * @param[in] rx_buf_size size of buffer to store received data, in bytes\n     * @return\n     *      - ESP_OK: Read bytes from 1-Wire bus successfully\n     *      - ESP_ERR_INVALID_ARG: Read bytes from 1-Wire bus failed because of invalid argument\n     *      - ESP_FAIL: Read bytes from 1-Wire bus failed because of other errors\n     */\n    esp_err_t (*read_bytes)(onewire_bus_t *bus, uint8_t *rx_buf, size_t rx_buf_size);\n\n    /**\n     * @brief Write a bit to 1-wire bus, this is a blocking function\n     *\n     * @param[in] handle 1-wire bus handle\n     * @param[in] tx_bit bit to transmit, 0 for zero bit, other for one bit\n     * @return\n     *         - ESP_OK                Write bit to 1-wire bus successfully.\n     *         - ESP_ERR_INVALID_ARG   Invalid argument.\n     */\n    esp_err_t (*write_bit)(onewire_bus_handle_t handle, uint8_t tx_bit);\n\n    /**\n     * @brief Read a bit from 1-wire bus\n     *\n     * @param[in] handle 1-wire bus handle\n     * @param[out] rx_bit received bit, 0 for zero bit, 1 for one bit\n     * @return\n     *         - ESP_OK                Read bit from 1-wire bus successfully.\n     *         - ESP_ERR_INVALID_ARG   Invalid argument.\n     */\n    esp_err_t (*read_bit)(onewire_bus_handle_t handle, uint8_t *rx_bit);\n\n    /**\n     * @brief Send reset pulse to the bus, and check if there are devices attached to the bus\n     *\n     * @param[in] bus 1-Wire bus handle\n     *\n     * @return\n     *      - ESP_OK: Reset 1-Wire bus successfully and find device on the bus\n     *      - ESP_ERR_NOT_FOUND: Reset 1-Wire bus successfully but no device found on the bus\n     *      - ESP_FAIL: Reset 1-Wire bus failed because of other errors\n     */\n    esp_err_t (*reset)(onewire_bus_t *bus);\n\n    /**\n     * @brief Free 1-Wire bus resources\n     *\n     * @param[in] bus 1-Wire bus handle\n     *\n     * @return\n     *      - ESP_OK: Free resources successfully\n     *      - ESP_FAIL: Free resources failed because error occurred\n     */\n    esp_err_t (*del)(onewire_bus_t *bus);\n};\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "onewire_bus/src/onewire_bus_api.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include \"esp_log.h\"\n#include \"esp_check.h\"\n#include \"onewire_types.h\"\n#include \"onewire_bus_interface.h\"\n\nstatic const char *TAG = \"1-wire\";\n\nesp_err_t onewire_bus_reset(onewire_bus_handle_t bus)\n{\n    ESP_RETURN_ON_FALSE(bus, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    return bus->reset(bus);\n}\n\nesp_err_t onewire_bus_write_bytes(onewire_bus_handle_t bus, const uint8_t *tx_data, uint8_t tx_data_size)\n{\n    ESP_RETURN_ON_FALSE(bus && tx_data && tx_data_size, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    return bus->write_bytes(bus, tx_data, tx_data_size);\n}\n\nesp_err_t onewire_bus_read_bytes(onewire_bus_handle_t bus, uint8_t *rx_buf, size_t rx_buf_size)\n{\n    ESP_RETURN_ON_FALSE(bus && rx_buf && rx_buf_size, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    return bus->read_bytes(bus, rx_buf, rx_buf_size);\n}\n\nesp_err_t onewire_bus_write_bit(onewire_bus_handle_t bus, uint8_t tx_bit)\n{\n    ESP_RETURN_ON_FALSE(bus, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    return bus->write_bit(bus, tx_bit);\n}\n\nesp_err_t onewire_bus_read_bit(onewire_bus_handle_t bus, uint8_t *rx_bit)\n{\n    ESP_RETURN_ON_FALSE(bus && rx_bit, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    return bus->read_bit(bus, rx_bit);\n}\n\nesp_err_t onewire_bus_del(onewire_bus_handle_t bus)\n{\n    ESP_RETURN_ON_FALSE(bus, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    return bus->del(bus);\n}\n"
  },
  {
    "path": "onewire_bus/src/onewire_bus_impl_rmt.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include <string.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"freertos/queue.h\"\n#include \"freertos/semphr.h\"\n#include \"esp_check.h\"\n#include \"esp_attr.h\"\n#include \"driver/rmt_tx.h\"\n#include \"driver/rmt_rx.h\"\n#include \"driver/gpio.h\"\n#include \"esp_private/gpio.h\"\n#include \"onewire_bus_impl_rmt.h\"\n#include \"onewire_bus_interface.h\"\n#include \"esp_idf_version.h\"\n\nstatic const char *TAG = \"1-wire.rmt\";\n\n#define ONEWIRE_RMT_RESOLUTION_HZ               1000000 // RMT channel default resolution for 1-wire bus, 1MHz, 1tick = 1us\n#define ONEWIRE_RMT_DEFAULT_TRANS_QUEUE_SIZE    4\n\n// the memory size of each RMT channel, in words (4 bytes)\n#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2\n#define ONEWIRE_RMT_DEFAULT_MEM_BLOCK_SYMBOLS   64\n#else\n#define ONEWIRE_RMT_DEFAULT_MEM_BLOCK_SYMBOLS   48\n#endif\n\n// for chips whose RMT RX channel doesn't support ping-pong, we need the user to tell the maximum number of bytes will be received\n#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2\n// one RMT symbol represents one bit, so x8\n#define ONEWIRE_RMT_RX_MEM_BLOCK_SIZE           (rmt_config->max_rx_bytes * 8)\n#else // otherwise, we just use one memory block, to save resources\n#define ONEWIRE_RMT_RX_MEM_BLOCK_SIZE           ONEWIRE_RMT_DEFAULT_MEM_BLOCK_SYMBOLS\n#endif\n\n/*\nReset Pulse:\n\n          | RESET_PULSE | RESET_WAIT_DURATION |\n          | _DURATION   |                     |\n          |             |   | | RESET     |   |\n          |             | * | | _PRESENCE |   |\n          |             |   | | _DURATION |   |\n----------+             +-----+           +--------------\n          |             |     |           |\n          |             |     |           |\n          |             |     |           |\n          +-------------+     +-----------+\n*: RESET_PRESENCE_WAIT_DURATION\n*/\n#define ONEWIRE_RESET_PULSE_DURATION            500 // duration of reset bit\n#define ONEWIRE_RESET_WAIT_DURATION             200 // how long should master wait for device to show its presence\n#define ONEWIRE_RESET_PRESENCE_WAIT_DURATION_MIN 15 // minimum duration for master to wait device to show its presence\n#define ONEWIRE_RESET_PRESENCE_DURATION_MIN      60 // minimum duration for master to recognize device as present\n\n/*\nWrite 1 bit:\n\n          | SLOT_START | SLOT_BIT  | SLOT_RECOVERY | NEXT\n          | _DURATION  | _DURATION | _DURATION     | SLOT\n          |            |           |               |\n----------+            +-------------------------------------\n          |            |\n          |            |\n          |            |\n          +------------+\n\nWrite 0 bit:\n\n          | SLOT_START | SLOT_BIT  | SLOT_RECOVERY | NEXT\n          | _DURATION  | _DURATION | _DURATION     | SLOT\n          |            |           |               |\n----------+                        +-------------------------\n          |                        |\n          |                        |\n          |                        |\n          +------------------------+\n\nRead 1 bit:\n\n\n          | SLOT_START | SLOT_BIT_DURATION | SLOT_RECOVERY | NEXT\n          | _DURATION  |                   | _DURATION     | SLOT\n          |            | SLOT_BIT_   |     |               |\n          |            | SAMPLE_TIME |     |               |\n----------+            +----------------------------------------------\n          |            |\n          |            |\n          |            |\n          +------------+\n\nRead 0 bit:\n\n          | SLOT_START | SLOT_BIT_DURATION | SLOT_RECOVERY | NEXT\n          | _DURATION  |                   | _DURATION     | SLOT\n          |            | SLOT_BIT_   |     |               |\n          |            | SAMPLE_TIME |     |               |\n----------+            |             |  +-----------------------------\n          |            |                |\n          |            |   PULLED DOWN  |\n          |            |    BY DEVICE   |\n          +-----------------------------+\n*/\n#define ONEWIRE_SLOT_START_DURATION             2  // bit start pulse duration\n#define ONEWIRE_SLOT_BIT_DURATION               60 // duration for each bit to transmit\n// refer to https://www.maximintegrated.com/en/design/technical-documents/app-notes/3/3829.html for more information\n#define ONEWIRE_SLOT_RECOVERY_DURATION          5  // recovery time between each bit, should be longer in parasite power mode\n#define ONEWIRE_SLOT_BIT_SAMPLE_TIME            15 // how long after bit start pulse should the master sample from the bus\n\ntypedef struct {\n    onewire_bus_t base; /*!< base class */\n    rmt_channel_handle_t tx_channel; /*!< rmt tx channel handler */\n    rmt_channel_handle_t rx_channel; /*!< rmt rx channel handler */\n\n    gpio_num_t data_gpio_num; /*!< GPIO number for 1-wire bus */\n\n    rmt_encoder_handle_t tx_bytes_encoder; /*!< used to encode commands and data */\n    rmt_encoder_handle_t tx_copy_encoder; /*!< used to encode reset pulse and bits */\n\n    rmt_symbol_word_t *rx_symbols_buf; /*!< hold rmt raw symbols */\n\n    size_t max_rx_bytes; /*!< buffer size in byte for single receive transaction */\n\n    QueueHandle_t receive_queue;\n    SemaphoreHandle_t bus_mutex;\n} onewire_bus_rmt_obj_t;\n\nstatic rmt_symbol_word_t onewire_reset_pulse_symbol = {\n    .level0 = 0,\n    .duration0 = ONEWIRE_RESET_PULSE_DURATION,\n    .level1 = 1,\n    .duration1 = ONEWIRE_RESET_WAIT_DURATION\n};\n\nstatic rmt_symbol_word_t onewire_bit0_symbol = {\n    .level0 = 0,\n    .duration0 = ONEWIRE_SLOT_START_DURATION + ONEWIRE_SLOT_BIT_DURATION,\n    .level1 = 1,\n    .duration1 = ONEWIRE_SLOT_RECOVERY_DURATION\n};\n\nstatic rmt_symbol_word_t onewire_bit1_symbol = {\n    .level0 = 0,\n    .duration0 = ONEWIRE_SLOT_START_DURATION,\n    .level1 = 1,\n    .duration1 = ONEWIRE_SLOT_BIT_DURATION + ONEWIRE_SLOT_RECOVERY_DURATION\n};\n\nconst static rmt_transmit_config_t onewire_rmt_tx_config = {\n    .loop_count = 0,     // no transfer loop\n    .flags.eot_level = 1 // onewire bus should be released in IDLE\n};\n\nconst static rmt_receive_config_t onewire_rmt_rx_config = {\n    .signal_range_min_ns = 1000000000 / ONEWIRE_RMT_RESOLUTION_HZ,\n    .signal_range_max_ns = (ONEWIRE_RESET_PULSE_DURATION + ONEWIRE_RESET_WAIT_DURATION) * 1000,\n};\n\nstatic esp_err_t onewire_bus_rmt_read_bit(onewire_bus_handle_t bus, uint8_t *rx_bit);\nstatic esp_err_t onewire_bus_rmt_write_bit(onewire_bus_handle_t bus, uint8_t tx_bit);\nstatic esp_err_t onewire_bus_rmt_read_bytes(onewire_bus_handle_t bus, uint8_t *rx_buf, size_t rx_buf_size);\nstatic esp_err_t onewire_bus_rmt_write_bytes(onewire_bus_handle_t bus, const uint8_t *tx_data, uint8_t tx_data_size);\nstatic esp_err_t onewire_bus_rmt_reset(onewire_bus_handle_t bus);\nstatic esp_err_t onewire_bus_rmt_del(onewire_bus_handle_t bus);\nstatic esp_err_t onewire_bus_rmt_destroy(onewire_bus_rmt_obj_t *bus_rmt);\n\nIRAM_ATTR\nbool onewire_rmt_rx_done_callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *user_data)\n{\n    BaseType_t task_woken = pdFALSE;\n    onewire_bus_rmt_obj_t *bus_rmt = (onewire_bus_rmt_obj_t *)user_data;\n\n    xQueueSendFromISR(bus_rmt->receive_queue, edata, &task_woken);\n\n    return task_woken;\n}\n\n/*\n[0].0 means symbol[0].duration0\n\nFirst reset pulse after rmt channel init:\n\nBus is low | Reset | Wait |  Device  |  Bus Idle\nafter init | Pulse |      | Presence |\n                   +------+          +-----------\n                   |      |          |\n                   |      |          |\n                   |      |          |\n-------------------+      +----------+\n                   1      2          3\n\n          [0].1     [0].0     [1].1     [1].0\n\n\nFollowing reset pulses:\n\nBus is high | Reset | Wait |  Device  |  Bus Idle\nafter init  | Pulse |      | Presence |\n------------+       +------+          +-----------\n            |       |      |          |\n            |       |      |          |\n            |       |      |          |\n            +-------+      +----------+\n            1       2      3          4\n\n              [0].0  [0].1     [1].0    [1].1\n*/\nstatic bool onewire_rmt_check_presence_pulse(rmt_symbol_word_t *rmt_symbols, size_t symbol_num)\n{\n    bool ret = false;\n    if (symbol_num >= 2) { // there should be at lease 2 symbols(3 or 4 edges)\n        if (rmt_symbols[0].level1 == 1) { // bus is high before reset pulse\n            if (rmt_symbols[0].duration1 > ONEWIRE_RESET_PRESENCE_WAIT_DURATION_MIN &&\n                    rmt_symbols[1].duration0 > ONEWIRE_RESET_PRESENCE_DURATION_MIN) {\n                ret = true;\n            }\n        } else { // bus is low before reset pulse(first pulse after rmt channel init)\n            if (rmt_symbols[0].duration0 > ONEWIRE_RESET_PRESENCE_WAIT_DURATION_MIN &&\n                    rmt_symbols[1].duration1 > ONEWIRE_RESET_PRESENCE_DURATION_MIN) {\n                ret = true;\n            }\n        }\n    }\n    return ret;\n}\n\nstatic void onewire_rmt_decode_data(rmt_symbol_word_t *rmt_symbols, size_t symbol_num, uint8_t *rx_buf, size_t rx_buf_size)\n{\n    size_t byte_pos = 0;\n    size_t bit_pos = 0;\n    for (size_t i = 0; i < symbol_num; i ++) {\n        if (rmt_symbols[i].duration0 > ONEWIRE_SLOT_BIT_SAMPLE_TIME) { // 0 bit\n            rx_buf[byte_pos] &= ~(1 << bit_pos); // LSB first\n        } else { // 1 bit\n            rx_buf[byte_pos] |= 1 << bit_pos;\n        }\n        bit_pos ++;\n        if (bit_pos >= 8) {\n            bit_pos = 0;\n            byte_pos ++;\n            if (byte_pos >= rx_buf_size) {\n                break;\n            }\n        }\n    }\n}\n\nesp_err_t onewire_new_bus_rmt(const onewire_bus_config_t *bus_config, const onewire_bus_rmt_config_t *rmt_config, onewire_bus_handle_t *ret_bus)\n{\n    esp_err_t ret = ESP_OK;\n    onewire_bus_rmt_obj_t *bus_rmt = NULL;\n    ESP_RETURN_ON_FALSE(bus_config && rmt_config && ret_bus, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n\n    bus_rmt = calloc(1, sizeof(onewire_bus_rmt_obj_t));\n    ESP_RETURN_ON_FALSE(bus_rmt, ESP_ERR_NO_MEM, TAG, \"no mem for onewire_bus_rmt_obj_t\");\n    bus_rmt->data_gpio_num = GPIO_NUM_NC;\n\n    // create rmt bytes encoder to transmit 1-wire commands and data\n    rmt_bytes_encoder_config_t bytes_encoder_config = {\n        .bit0 = onewire_bit0_symbol,\n        .bit1 = onewire_bit1_symbol,\n        .flags.msb_first = 0,\n    };\n    ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &bus_rmt->tx_bytes_encoder),\n                      err, TAG, \"create bytes encoder failed\");\n\n    // create rmt copy encoder to transmit 1-wire reset pulse or bits\n    rmt_copy_encoder_config_t copy_encoder_config = {};\n    ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(&copy_encoder_config, &bus_rmt->tx_copy_encoder),\n                      err, TAG, \"create copy encoder failed\");\n\n    // create RX and TX channels and bind them to the same GPIO\n    rmt_rx_channel_config_t onewire_rx_channel_cfg = {\n        .clk_src = RMT_CLK_SRC_DEFAULT,\n        .resolution_hz = ONEWIRE_RMT_RESOLUTION_HZ,\n        .gpio_num = bus_config->bus_gpio_num,\n        .mem_block_symbols = ONEWIRE_RMT_RX_MEM_BLOCK_SIZE,\n    };\n    ESP_GOTO_ON_ERROR(rmt_new_rx_channel(&onewire_rx_channel_cfg, &bus_rmt->rx_channel),\n                      err, TAG, \"create rmt rx channel failed\");\n\n    rmt_tx_channel_config_t onewire_tx_channel_cfg = {\n        .clk_src = RMT_CLK_SRC_DEFAULT,\n        .resolution_hz = ONEWIRE_RMT_RESOLUTION_HZ,\n        .gpio_num = bus_config->bus_gpio_num,\n        .mem_block_symbols = ONEWIRE_RMT_DEFAULT_MEM_BLOCK_SYMBOLS,\n        .trans_queue_depth = ONEWIRE_RMT_DEFAULT_TRANS_QUEUE_SIZE,\n#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(6, 0, 0)\n        .flags.io_loop_back = true,\n        .flags.io_od_mode = true,\n#endif\n    };\n    ESP_GOTO_ON_ERROR(rmt_new_tx_channel(&onewire_tx_channel_cfg, &bus_rmt->tx_channel),\n                      err, TAG, \"create rmt tx channel failed\");\n\n    bus_rmt->data_gpio_num = bus_config->bus_gpio_num;\n#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)\n    // enable open-drain mode for 1-wire bus\n    gpio_od_enable(bus_rmt->data_gpio_num);\n#endif\n\n    if (bus_config->flags.en_pull_up) {\n        // enable internal pull-up resistor and disable pull-down resistor\n        gpio_set_pull_mode(bus_rmt->data_gpio_num, GPIO_PULLUP_ONLY);\n    } else {\n        // disable internal pull-up and pull-down resistors\n        gpio_set_pull_mode(bus_rmt->data_gpio_num, GPIO_FLOATING);\n    }\n\n    // allocate rmt rx symbol buffer, one RMT symbol represents one bit, so x8\n    bus_rmt->rx_symbols_buf = malloc(rmt_config->max_rx_bytes * sizeof(rmt_symbol_word_t) * 8);\n    ESP_GOTO_ON_FALSE(bus_rmt->rx_symbols_buf, ESP_ERR_NO_MEM, err, TAG, \"no mem to store received RMT symbols\");\n    bus_rmt->max_rx_bytes = rmt_config->max_rx_bytes;\n\n    bus_rmt->receive_queue = xQueueCreate(1, sizeof(rmt_rx_done_event_data_t));\n    ESP_GOTO_ON_FALSE(bus_rmt->receive_queue, ESP_ERR_NO_MEM, err, TAG, \"receive queue creation failed\");\n\n    bus_rmt->bus_mutex = xSemaphoreCreateMutex();\n    ESP_GOTO_ON_FALSE(bus_rmt->bus_mutex, ESP_ERR_NO_MEM, err, TAG, \"bus mutex creation failed\");\n\n    // register rmt rx done callback\n    rmt_rx_event_callbacks_t cbs = {\n        .on_recv_done = onewire_rmt_rx_done_callback\n    };\n    ESP_GOTO_ON_ERROR(rmt_rx_register_event_callbacks(bus_rmt->rx_channel, &cbs, bus_rmt),\n                      err, TAG, \"enable rmt rx channel failed\");\n\n    // enable rmt channels\n    ESP_GOTO_ON_ERROR(rmt_enable(bus_rmt->rx_channel), err, TAG, \"enable rmt rx channel failed\");\n    ESP_GOTO_ON_ERROR(rmt_enable(bus_rmt->tx_channel), err, TAG, \"enable rmt tx channel failed\");\n\n    // release the bus by sending a special RMT symbol\n    static rmt_symbol_word_t release_symbol = {\n        .level0 = 1,\n        .duration0 = 1,\n        .level1 = 1,\n        .duration1 = 0,\n    };\n    ESP_GOTO_ON_ERROR(rmt_transmit(bus_rmt->tx_channel, bus_rmt->tx_copy_encoder, &release_symbol,\n                                   sizeof(release_symbol), &onewire_rmt_tx_config), err, TAG, \"release bus failed\");\n\n    bus_rmt->base.del = onewire_bus_rmt_del;\n    bus_rmt->base.reset = onewire_bus_rmt_reset;\n    bus_rmt->base.write_bit = onewire_bus_rmt_write_bit;\n    bus_rmt->base.write_bytes = onewire_bus_rmt_write_bytes;\n    bus_rmt->base.read_bit = onewire_bus_rmt_read_bit;\n    bus_rmt->base.read_bytes = onewire_bus_rmt_read_bytes;\n    *ret_bus = &bus_rmt->base;\n\n    return ret;\n\nerr:\n    if (bus_rmt) {\n        onewire_bus_rmt_destroy(bus_rmt);\n    }\n\n    return ret;\n}\n\nstatic esp_err_t onewire_bus_rmt_destroy(onewire_bus_rmt_obj_t *bus_rmt)\n{\n    if (bus_rmt->tx_bytes_encoder) {\n        rmt_del_encoder(bus_rmt->tx_bytes_encoder);\n    }\n    if (bus_rmt->tx_copy_encoder) {\n        rmt_del_encoder(bus_rmt->tx_copy_encoder);\n    }\n    if (bus_rmt->rx_channel) {\n        rmt_disable(bus_rmt->rx_channel);\n        rmt_del_channel(bus_rmt->rx_channel);\n    }\n    if (bus_rmt->tx_channel) {\n        rmt_disable(bus_rmt->tx_channel);\n        rmt_del_channel(bus_rmt->tx_channel);\n    }\n    if (bus_rmt->receive_queue) {\n        vQueueDelete(bus_rmt->receive_queue);\n    }\n    if (bus_rmt->bus_mutex) {\n        vSemaphoreDelete(bus_rmt->bus_mutex);\n    }\n    if (bus_rmt->rx_symbols_buf) {\n        free(bus_rmt->rx_symbols_buf);\n    }\n#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)\n    if (bus_rmt->data_gpio_num != GPIO_NUM_NC) {\n        gpio_od_disable(bus_rmt->data_gpio_num);\n    }\n#endif\n    free(bus_rmt);\n    return ESP_OK;\n}\n\nstatic esp_err_t onewire_bus_rmt_del(onewire_bus_handle_t bus)\n{\n    onewire_bus_rmt_obj_t *bus_rmt = __containerof(bus, onewire_bus_rmt_obj_t, base);\n    return onewire_bus_rmt_destroy(bus_rmt);\n}\n\nstatic esp_err_t onewire_bus_rmt_reset(onewire_bus_handle_t bus)\n{\n    onewire_bus_rmt_obj_t *bus_rmt = __containerof(bus, onewire_bus_rmt_obj_t, base);\n    esp_err_t ret = ESP_OK;\n\n    xSemaphoreTake(bus_rmt->bus_mutex, portMAX_DELAY);\n    // send reset pulse while receive presence pulse\n    ESP_GOTO_ON_ERROR(rmt_receive(bus_rmt->rx_channel, bus_rmt->rx_symbols_buf, sizeof(rmt_symbol_word_t) * 2, &onewire_rmt_rx_config),\n                      err, TAG, \"1-wire reset pulse receive failed\");\n    ESP_GOTO_ON_ERROR(rmt_transmit(bus_rmt->tx_channel, bus_rmt->tx_copy_encoder, &onewire_reset_pulse_symbol, sizeof(onewire_reset_pulse_symbol), &onewire_rmt_tx_config),\n                      err, TAG, \"1-wire reset pulse transmit failed\");\n\n    // wait and check presence pulse\n    rmt_rx_done_event_data_t rmt_rx_evt_data;\n    ESP_GOTO_ON_FALSE(xQueueReceive(bus_rmt->receive_queue, &rmt_rx_evt_data, pdMS_TO_TICKS(1000)) == pdPASS,\n                      ESP_ERR_TIMEOUT, err, TAG, \"1-wire reset pulse receive timeout\");\n    if (onewire_rmt_check_presence_pulse(rmt_rx_evt_data.received_symbols, rmt_rx_evt_data.num_symbols) == false) {\n        ret = ESP_ERR_NOT_FOUND;\n    }\n\nerr:\n    xSemaphoreGive(bus_rmt->bus_mutex);\n    return ret;\n}\n\nstatic esp_err_t onewire_bus_rmt_write_bytes(onewire_bus_handle_t bus, const uint8_t *tx_data, uint8_t tx_data_size)\n{\n    onewire_bus_rmt_obj_t *bus_rmt = __containerof(bus, onewire_bus_rmt_obj_t, base);\n    esp_err_t ret = ESP_OK;\n\n    xSemaphoreTake(bus_rmt->bus_mutex, portMAX_DELAY);\n    // transmit data with the bytes encoder\n    ESP_GOTO_ON_ERROR(rmt_transmit(bus_rmt->tx_channel, bus_rmt->tx_bytes_encoder, tx_data, tx_data_size, &onewire_rmt_tx_config),\n                      err, TAG, \"1-wire data transmit failed\");\n    // wait the transmission to complete\n    ESP_GOTO_ON_ERROR(rmt_tx_wait_all_done(bus_rmt->tx_channel, 50), err, TAG, \"wait for 1-wire data transmit failed\");\n\nerr:\n    xSemaphoreGive(bus_rmt->bus_mutex);\n    return ret;\n}\n\n// While receiving data, we use rmt transmit channel to send 0xFF to generate read pulse,\n// at the same time, receive channel is used to record weather the bus is pulled down by device.\nstatic esp_err_t onewire_bus_rmt_read_bytes(onewire_bus_handle_t bus, uint8_t *rx_buf, size_t rx_buf_size)\n{\n    onewire_bus_rmt_obj_t *bus_rmt = __containerof(bus, onewire_bus_rmt_obj_t, base);\n    esp_err_t ret = ESP_OK;\n    ESP_RETURN_ON_FALSE(rx_buf_size <= bus_rmt->max_rx_bytes, ESP_ERR_INVALID_ARG, TAG, \"rx_buf_size too large for buffer to hold\");\n    memset(rx_buf, 0, rx_buf_size);\n\n    xSemaphoreTake(bus_rmt->bus_mutex, portMAX_DELAY);\n\n    // transmit one bits to generate read clock\n    uint8_t tx_buffer[rx_buf_size];\n    memset(tx_buffer, 0xFF, rx_buf_size);\n    // transmit 1 bits while receiving\n    ESP_GOTO_ON_ERROR(rmt_receive(bus_rmt->rx_channel, bus_rmt->rx_symbols_buf, rx_buf_size * 8 * sizeof(rmt_symbol_word_t), &onewire_rmt_rx_config),\n                      err, TAG, \"1-wire data receive failed\");\n    ESP_GOTO_ON_ERROR(rmt_transmit(bus_rmt->tx_channel, bus_rmt->tx_bytes_encoder, tx_buffer, sizeof(tx_buffer), &onewire_rmt_tx_config),\n                      err, TAG, \"1-wire data transmit failed\");\n\n    // wait the transmission finishes and decode data\n    rmt_rx_done_event_data_t rmt_rx_evt_data;\n    ESP_GOTO_ON_FALSE(xQueueReceive(bus_rmt->receive_queue, &rmt_rx_evt_data, pdMS_TO_TICKS(1000)) == pdPASS, ESP_ERR_TIMEOUT,\n                      err, TAG, \"1-wire data receive timeout\");\n    onewire_rmt_decode_data(rmt_rx_evt_data.received_symbols, rmt_rx_evt_data.num_symbols, rx_buf, rx_buf_size);\n\nerr:\n    xSemaphoreGive(bus_rmt->bus_mutex);\n    return ret;\n}\n\nstatic esp_err_t onewire_bus_rmt_write_bit(onewire_bus_handle_t bus, uint8_t tx_bit)\n{\n    onewire_bus_rmt_obj_t *bus_rmt = __containerof(bus, onewire_bus_rmt_obj_t, base);\n    const rmt_symbol_word_t *symbol_to_transmit = tx_bit ? &onewire_bit1_symbol : &onewire_bit0_symbol;\n    esp_err_t ret = ESP_OK;\n\n    xSemaphoreTake(bus_rmt->bus_mutex, portMAX_DELAY);\n\n    // transmit bit\n    ESP_GOTO_ON_ERROR(rmt_transmit(bus_rmt->tx_channel, bus_rmt->tx_copy_encoder, symbol_to_transmit, sizeof(rmt_symbol_word_t), &onewire_rmt_tx_config),\n                      err, TAG, \"1-wire bit transmit failed\");\n    // wait the transmission to complete\n    ESP_GOTO_ON_ERROR(rmt_tx_wait_all_done(bus_rmt->tx_channel, 50), err, TAG, \"wait for 1-wire bit transmit failed\");\n\nerr:\n    xSemaphoreGive(bus_rmt->bus_mutex);\n    return ret;\n}\n\nstatic esp_err_t onewire_bus_rmt_read_bit(onewire_bus_handle_t bus, uint8_t *rx_bit)\n{\n    onewire_bus_rmt_obj_t *bus_rmt = __containerof(bus, onewire_bus_rmt_obj_t, base);\n    esp_err_t ret = ESP_OK;\n\n    xSemaphoreTake(bus_rmt->bus_mutex, portMAX_DELAY);\n\n    // transmit 1 bit while receiving\n    ESP_GOTO_ON_ERROR(rmt_receive(bus_rmt->rx_channel, bus_rmt->rx_symbols_buf, sizeof(rmt_symbol_word_t), &onewire_rmt_rx_config),\n                      err, TAG, \"1-wire bit receive failed\");\n    ESP_GOTO_ON_ERROR(rmt_transmit(bus_rmt->tx_channel, bus_rmt->tx_copy_encoder, &onewire_bit1_symbol, sizeof(rmt_symbol_word_t), &onewire_rmt_tx_config),\n                      err, TAG, \"1-wire bit transmit failed\");\n\n    // wait the transmission finishes and decode data\n    rmt_rx_done_event_data_t rmt_rx_evt_data;\n    ESP_GOTO_ON_FALSE(xQueueReceive(bus_rmt->receive_queue, &rmt_rx_evt_data, pdMS_TO_TICKS(1000)) == pdPASS, ESP_ERR_TIMEOUT,\n                      err, TAG, \"1-wire bit receive timeout\");\n    uint8_t rx_buffer = 0;\n    onewire_rmt_decode_data(rmt_rx_evt_data.received_symbols, rmt_rx_evt_data.num_symbols, &rx_buffer, sizeof(rx_buffer));\n    *rx_bit = rx_buffer & 0x01;\n\nerr:\n    xSemaphoreGive(bus_rmt->bus_mutex);\n    return ret;\n}\n"
  },
  {
    "path": "onewire_bus/src/onewire_bus_impl_uart.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include <string.h>\n#include <stdlib.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/semphr.h\"\n#include \"freertos/task.h\"\n#include \"esp_check.h\"\n#include \"driver/uart.h\"\n#include \"driver/gpio.h\"\n#include \"onewire_bus_impl_uart.h\"\n#include \"onewire_bus_interface.h\"\n#include \"esp_idf_version.h\"\n\nstatic const char *TAG = \"1-wire.uart\";\n\n#define ONEWIRE_UART_DEFAULT_TIMEOUT_MS    100\n// refer to https://www.analog.com/en/resources/technical-articles/using-a-uart-to-implement-a-1wire-bus-master.html for more information\n#define ONEWIRE_UART_BAUD_RESET            9600   // baud rate for reset pulse and presence detect\n#define ONEWIRE_UART_BAUD_SLOT             115200 // baud rate for read and write operations\n\n#define ONEWIRE_UART_RESET_TX              0xF0 // TX value for reset pulse and presence detect\n#define ONEWIRE_UART_RESET_RX_NO_DEVICE    0xF0 // RX value when no device is present\n\n#define ONEWIRE_UART_SLOT_TX_WRITE_1       0xFF // TX value for write 1\n#define ONEWIRE_UART_SLOT_TX_WRITE_0       0x00 // TX value for write 0\n#define ONEWIRE_UART_SLOT_TX_READ          0xFF // TX value for read\n#define ONEWIRE_UART_SLOT_RX_READ_1        0xFF // RX value when read 1\n\ntypedef struct {\n    onewire_bus_t base; /*!< base class */\n    uart_port_t uart_port_num; /*!< UART port number */\n    gpio_num_t data_gpio_num; /*!< GPIO number for 1-wire bus */\n    uint32_t current_baud_rate; /*!< Note: the baud rate returned by uart_get_baudrate() could have a slight deviation from the user-configured baud rate.\n                                     That's why we store the configured baud rate here. */\n    SemaphoreHandle_t bus_mutex;\n} onewire_bus_uart_obj_t;\n\nstatic esp_err_t onewire_bus_uart_read_bit(onewire_bus_handle_t bus, uint8_t *rx_bit);\nstatic esp_err_t onewire_bus_uart_write_bit(onewire_bus_handle_t bus, uint8_t tx_bit);\nstatic esp_err_t onewire_bus_uart_read_bytes(onewire_bus_handle_t bus, uint8_t *rx_buf, size_t rx_buf_size);\nstatic esp_err_t onewire_bus_uart_write_bytes(onewire_bus_handle_t bus, const uint8_t *tx_data, uint8_t tx_data_size);\nstatic esp_err_t onewire_bus_uart_reset(onewire_bus_handle_t bus);\nstatic esp_err_t onewire_bus_uart_del(onewire_bus_handle_t bus);\n\nstatic esp_err_t onewire_bus_uart_destroy(onewire_bus_uart_obj_t *bus_uart);\nstatic esp_err_t onewire_bus_uart_set_baud_rate(onewire_bus_uart_obj_t *bus_uart, uint32_t baud_rate);\nstatic esp_err_t onewire_bus_uart_exchange_byte(onewire_bus_uart_obj_t *bus_uart, uint8_t tx_data, uint8_t *rx_data);\nstatic esp_err_t onewire_bus_uart_write_bit_nolock(onewire_bus_uart_obj_t *bus_uart, uint8_t tx_bit);\nstatic esp_err_t onewire_bus_uart_read_bit_nolock(onewire_bus_uart_obj_t *bus_uart, uint8_t *rx_bit);\n\nesp_err_t onewire_new_bus_uart(const onewire_bus_config_t *bus_config, const onewire_bus_uart_config_t *uart_config, onewire_bus_handle_t *ret_bus)\n{\n    esp_err_t ret = ESP_OK;\n    onewire_bus_uart_obj_t *bus_uart = NULL;\n    ESP_RETURN_ON_FALSE(bus_config && uart_config && ret_bus, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(bus_config->bus_gpio_num), ESP_ERR_INVALID_ARG, TAG, \"invalid GPIO number\");\n\n    bus_uart = calloc(1, sizeof(onewire_bus_uart_obj_t));\n    ESP_RETURN_ON_FALSE(bus_uart, ESP_ERR_NO_MEM, TAG, \"no mem for onewire_bus_uart_obj_t\");\n    bus_uart->uart_port_num = UART_NUM_MAX;\n    bus_uart->data_gpio_num = GPIO_NUM_NC;\n\n    const gpio_config_t io_conf = {\n        .pin_bit_mask = (1ULL << bus_config->bus_gpio_num),\n        .mode = GPIO_MODE_INPUT_OUTPUT_OD,\n        .pull_up_en = bus_config->flags.en_pull_up ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE,\n        .pull_down_en = GPIO_PULLDOWN_DISABLE,\n        .intr_type = GPIO_INTR_DISABLE,\n    };\n    ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err, TAG, \"gpio config failed\");\n    bus_uart->data_gpio_num = bus_config->bus_gpio_num;\n\n    // Simulate a 1-Wire bus using UART 8N1 mode\n    // refer to https://www.analog.com/en/resources/technical-articles/using-a-uart-to-implement-a-1wire-bus-master.html for more information\n    const uart_config_t uart_cfg = {\n        .baud_rate = ONEWIRE_UART_BAUD_RESET,\n        .data_bits = UART_DATA_8_BITS,\n        .parity = UART_PARITY_DISABLE,\n        .stop_bits = UART_STOP_BITS_1,\n        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,\n        .source_clk = UART_SCLK_DEFAULT,\n    };\n    ESP_GOTO_ON_ERROR(uart_param_config(uart_config->uart_port_num, &uart_cfg), err, TAG, \"uart param config failed\");\n    bus_uart->current_baud_rate = uart_cfg.baud_rate;\n    ESP_GOTO_ON_ERROR(uart_set_pin(uart_config->uart_port_num, bus_config->bus_gpio_num, bus_config->bus_gpio_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE),\n                      err, TAG, \"uart set pin failed\");\n#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)\n    // Set the RX buffer to minimum size because we only need to receive 1 byte at a time\n    // Disable the TX buffer because we only need to send 1 byte at a time\n    ESP_GOTO_ON_ERROR(uart_driver_install(uart_config->uart_port_num, UART_HW_FIFO_LEN(uart_config->uart_port_num) + 1, 0, 0, NULL, 0),\n                      err, TAG, \"uart driver install failed\");\n#else\n    ESP_GOTO_ON_ERROR(uart_driver_install(uart_config->uart_port_num, UART_FIFO_LEN + 1, 0, 0, NULL, 0),\n                      err, TAG, \"uart driver install failed\");\n#endif\n    bus_uart->uart_port_num = uart_config->uart_port_num;\n\n    // Configuration optimized for this scenario\n    // We only need to receive 1 byte at a time, so set the rx full threshold to 1 for faster response\n    // Normally, the RX timeout interrupt is not expected to trigger. Setting the timeout to 1 here is simply to ensure a fast response\n    ESP_GOTO_ON_ERROR(uart_set_rx_full_threshold(uart_config->uart_port_num, 1), err, TAG, \"uart set rx full threshold failed\");\n    ESP_GOTO_ON_ERROR(uart_set_rx_timeout(uart_config->uart_port_num, 1), err, TAG, \"uart set rx timeout failed\");\n\n    bus_uart->bus_mutex = xSemaphoreCreateMutex();\n    ESP_GOTO_ON_FALSE(bus_uart->bus_mutex, ESP_ERR_NO_MEM, err, TAG, \"bus mutex creation failed\");\n\n    bus_uart->base.del = onewire_bus_uart_del;\n    bus_uart->base.reset = onewire_bus_uart_reset;\n    bus_uart->base.write_bit = onewire_bus_uart_write_bit;\n    bus_uart->base.write_bytes = onewire_bus_uart_write_bytes;\n    bus_uart->base.read_bit = onewire_bus_uart_read_bit;\n    bus_uart->base.read_bytes = onewire_bus_uart_read_bytes;\n    *ret_bus = &bus_uart->base;\n    return ret;\n\nerr:\n    if (bus_uart) {\n        onewire_bus_uart_destroy(bus_uart);\n    }\n    return ret;\n}\n\nstatic esp_err_t onewire_bus_uart_destroy(onewire_bus_uart_obj_t *bus_uart)\n{\n    if (bus_uart->bus_mutex) {\n        vSemaphoreDelete(bus_uart->bus_mutex);\n    }\n    if (bus_uart->uart_port_num != UART_NUM_MAX) {\n        uart_driver_delete(bus_uart->uart_port_num);\n    }\n    if (bus_uart->data_gpio_num != GPIO_NUM_NC) {\n        gpio_reset_pin(bus_uart->data_gpio_num);\n    }\n    free(bus_uart);\n    return ESP_OK;\n}\n\nstatic esp_err_t onewire_bus_uart_set_baud_rate(onewire_bus_uart_obj_t *bus_uart, uint32_t baud_rate)\n{\n    if (bus_uart->current_baud_rate == baud_rate) {\n        return ESP_OK;\n    }\n    esp_err_t ret = uart_set_baudrate(bus_uart->uart_port_num, baud_rate);\n    if (ret != ESP_OK) {\n        return ret;\n    }\n    bus_uart->current_baud_rate = baud_rate;\n    return ESP_OK;\n}\n\n/**\n * @brief Send and receive one byte over the UART bus.\n *\n * @note This function is used for:\n *   - reset pulse and presence detect\n *   - write or read one bit on the 1-wire bus\n */\nstatic esp_err_t onewire_bus_uart_exchange_byte(onewire_bus_uart_obj_t *bus_uart, uint8_t tx_data, uint8_t *rx_data)\n{\n    esp_err_t ret = uart_flush_input(bus_uart->uart_port_num);\n    if (ret != ESP_OK) {\n        return ret;\n    }\n    if (uart_tx_chars(bus_uart->uart_port_num, (const char *)&tx_data, 1) != 1) {\n        return ESP_FAIL;\n    }\n    if (uart_read_bytes(bus_uart->uart_port_num, rx_data, 1, pdMS_TO_TICKS(ONEWIRE_UART_DEFAULT_TIMEOUT_MS)) != 1) {\n        return ESP_ERR_TIMEOUT;\n    }\n    return ESP_OK;\n}\n\nstatic esp_err_t onewire_bus_uart_write_bit_nolock(onewire_bus_uart_obj_t *bus_uart, uint8_t tx_bit)\n{\n    uint8_t rx_data = 0;\n    const uint8_t tx_data = tx_bit ? ONEWIRE_UART_SLOT_TX_WRITE_1 : ONEWIRE_UART_SLOT_TX_WRITE_0;\n    esp_err_t ret = onewire_bus_uart_exchange_byte(bus_uart, tx_data, &rx_data);\n    if (ret != ESP_OK) {\n        return ret;\n    }\n    return (rx_data == tx_data) ? ESP_OK : ESP_ERR_INVALID_STATE;   // Check if the sent data is corrupted\n}\n\nstatic esp_err_t onewire_bus_uart_read_bit_nolock(onewire_bus_uart_obj_t *bus_uart, uint8_t *rx_bit)\n{\n    uint8_t rx_data = 0;\n    esp_err_t ret = onewire_bus_uart_exchange_byte(bus_uart, ONEWIRE_UART_SLOT_TX_READ, &rx_data);\n    if (ret != ESP_OK) {\n        return ret;\n    }\n    *rx_bit = (rx_data == ONEWIRE_UART_SLOT_RX_READ_1) ? 1 : 0;\n    return ESP_OK;\n}\n\n////////////////////////////// implementation of onewire_bus_t functions //////////////////////////////\n\nstatic esp_err_t onewire_bus_uart_del(onewire_bus_handle_t bus)\n{\n    onewire_bus_uart_obj_t *bus_uart = __containerof(bus, onewire_bus_uart_obj_t, base);\n    return onewire_bus_uart_destroy(bus_uart);\n}\n\nstatic esp_err_t onewire_bus_uart_reset(onewire_bus_handle_t bus)\n{\n    onewire_bus_uart_obj_t *bus_uart = __containerof(bus, onewire_bus_uart_obj_t, base);\n    esp_err_t ret = ESP_OK;\n    uint8_t rx_data = 0;\n\n    xSemaphoreTake(bus_uart->bus_mutex, portMAX_DELAY);\n    ESP_GOTO_ON_ERROR(onewire_bus_uart_set_baud_rate(bus_uart, ONEWIRE_UART_BAUD_RESET), err, TAG, \"set reset baudrate failed\");\n    ESP_GOTO_ON_ERROR(onewire_bus_uart_exchange_byte(bus_uart, ONEWIRE_UART_RESET_TX, &rx_data), err, TAG, \"create reset pulse failed\");\n    ESP_GOTO_ON_FALSE(rx_data != ONEWIRE_UART_RESET_RX_NO_DEVICE, ESP_ERR_NOT_FOUND, err, TAG, \"no 1-wire device found\");\n\nerr:\n    xSemaphoreGive(bus_uart->bus_mutex);\n    return ret;\n}\n\nstatic esp_err_t onewire_bus_uart_write_bytes(onewire_bus_handle_t bus, const uint8_t *tx_data, uint8_t tx_data_size)\n{\n    onewire_bus_uart_obj_t *bus_uart = __containerof(bus, onewire_bus_uart_obj_t, base);\n    esp_err_t ret = ESP_OK;\n\n    ESP_RETURN_ON_FALSE(tx_data && tx_data_size, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    xSemaphoreTake(bus_uart->bus_mutex, portMAX_DELAY);\n    ESP_GOTO_ON_ERROR(onewire_bus_uart_set_baud_rate(bus_uart, ONEWIRE_UART_BAUD_SLOT), err, TAG, \"set slot baudrate failed\");\n\n    for (uint8_t i = 0; i < tx_data_size; i++) {\n        uint8_t current = tx_data[i];\n        for (int bit = 0; bit < 8; bit++) {\n            ESP_GOTO_ON_ERROR(onewire_bus_uart_write_bit_nolock(bus_uart, current & 0x01), err, TAG, \"write bit failed\");\n            current >>= 1;\n        }\n    }\n\nerr:\n    xSemaphoreGive(bus_uart->bus_mutex);\n    return ret;\n}\n\nstatic esp_err_t onewire_bus_uart_read_bytes(onewire_bus_handle_t bus, uint8_t *rx_buf, size_t rx_buf_size)\n{\n    onewire_bus_uart_obj_t *bus_uart = __containerof(bus, onewire_bus_uart_obj_t, base);\n    esp_err_t ret = ESP_OK;\n\n    ESP_RETURN_ON_FALSE(rx_buf && rx_buf_size, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    memset(rx_buf, 0, rx_buf_size);\n    xSemaphoreTake(bus_uart->bus_mutex, portMAX_DELAY);\n    ESP_GOTO_ON_ERROR(onewire_bus_uart_set_baud_rate(bus_uart, ONEWIRE_UART_BAUD_SLOT), err, TAG, \"set slot baudrate failed\");\n\n    for (size_t i = 0; i < rx_buf_size; i++) {\n        uint8_t current = 0;\n        for (int bit = 0; bit < 8; bit++) {\n            uint8_t rx_bit = 0;\n            ESP_GOTO_ON_ERROR(onewire_bus_uart_read_bit_nolock(bus_uart, &rx_bit), err, TAG, \"read bit failed\");\n            if (rx_bit) {\n                current |= (1 << bit);\n            }\n        }\n        rx_buf[i] = current;\n    }\n\nerr:\n    xSemaphoreGive(bus_uart->bus_mutex);\n    return ret;\n}\n\nstatic esp_err_t onewire_bus_uart_write_bit(onewire_bus_handle_t bus, uint8_t tx_bit)\n{\n    onewire_bus_uart_obj_t *bus_uart = __containerof(bus, onewire_bus_uart_obj_t, base);\n    esp_err_t ret = ESP_OK;\n\n    xSemaphoreTake(bus_uart->bus_mutex, portMAX_DELAY);\n    ESP_GOTO_ON_ERROR(onewire_bus_uart_set_baud_rate(bus_uart, ONEWIRE_UART_BAUD_SLOT), err, TAG, \"set slot baudrate failed\");\n    ESP_GOTO_ON_ERROR(onewire_bus_uart_write_bit_nolock(bus_uart, tx_bit), err, TAG, \"write bit failed\");\nerr:\n    xSemaphoreGive(bus_uart->bus_mutex);\n    return ret;\n}\n\nstatic esp_err_t onewire_bus_uart_read_bit(onewire_bus_handle_t bus, uint8_t *rx_bit)\n{\n    onewire_bus_uart_obj_t *bus_uart = __containerof(bus, onewire_bus_uart_obj_t, base);\n    ESP_RETURN_ON_FALSE(rx_bit, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    esp_err_t ret = ESP_OK;\n\n    xSemaphoreTake(bus_uart->bus_mutex, portMAX_DELAY);\n    ESP_GOTO_ON_ERROR(onewire_bus_uart_set_baud_rate(bus_uart, ONEWIRE_UART_BAUD_SLOT), err, TAG, \"set slot baudrate failed\");\n    ESP_GOTO_ON_ERROR(onewire_bus_uart_read_bit_nolock(bus_uart, rx_bit), err, TAG, \"read bit failed\");\nerr:\n    xSemaphoreGive(bus_uart->bus_mutex);\n    return ret;\n}\n\n"
  },
  {
    "path": "onewire_bus/src/onewire_crc.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"onewire_crc.h\"\n\n#define FAST_CRC 1 // define this to use the fast CRC table\n\n#if FAST_CRC\n\nstatic const uint8_t dalas_crc8_table[] = {\n    0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,\n    157, 195, 33, 127, 252, 162, 64, 30, 95,  1, 227, 189, 62, 96, 130, 220,\n    35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93,  3, 128, 222, 60, 98,\n    190, 224,  2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,\n    70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89,  7,\n    219, 133, 103, 57, 186, 228,  6, 88, 25, 71, 165, 251, 120, 38, 196, 154,\n    101, 59, 217, 135,  4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,\n    248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91,  5, 231, 185,\n    140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,\n    17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,\n    175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238,\n    50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,\n    202, 148, 118, 40, 171, 245, 23, 73,  8, 86, 180, 234, 105, 55, 213, 139,\n    87,  9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,\n    233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,\n    116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53\n};\n\nuint8_t onewire_crc8(uint8_t init_crc, uint8_t *input, size_t input_size)\n{\n    uint8_t crc = init_crc;\n    for (size_t i = 0; i < input_size; i ++) {\n        crc = dalas_crc8_table[crc ^ input[i]];\n    }\n    return crc;\n}\n\n#else // FAST_CRC\n\nuint8_t onewire_crc8(uint8_t init_crc, uint8_t *input, size_t input_size)\n{\n    uint8_t crc = init_crc;\n    for (size_t i = 0; i < input_size; i++) {\n        uint8_t byte = input[i];\n        for (int j = 0; j < 8; j++) {\n            uint8_t x = (byte ^ crc) & 0x01;\n            crc >>= 1;\n            if (x != 0) {\n                crc ^= 0x8C;\n            }\n            byte >>= 1;\n        }\n    }\n    return crc;\n}\n\n#endif // FAST_CRC\n"
  },
  {
    "path": "onewire_bus/src/onewire_device.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#include <string.h>\n#include <stdbool.h>\n#include \"esp_check.h\"\n#include \"esp_log.h\"\n#include \"onewire_bus.h\"\n#include \"onewire_device.h\"\n#include \"onewire_crc.h\"\n#include \"onewire_cmd.h\"\n\nstatic const char *TAG = \"1-wire.device\";\n\ntypedef struct onewire_device_iter_t {\n    onewire_bus_handle_t bus;\n    uint16_t last_discrepancy;\n    bool is_last_device;\n    uint8_t rom_number[sizeof(onewire_device_address_t)];\n} onewire_device_iter_t;\n\nesp_err_t onewire_new_device_iter(onewire_bus_handle_t bus, onewire_device_iter_handle_t *ret_iter)\n{\n    ESP_RETURN_ON_FALSE(bus && ret_iter, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n\n    onewire_device_iter_t *iter = calloc(1, sizeof(onewire_device_iter_t));\n    ESP_RETURN_ON_FALSE(iter, ESP_ERR_NO_MEM, TAG, \"no mem for device iterator\");\n\n    iter->bus = bus;\n    *ret_iter = iter;\n\n    return ESP_OK;\n}\n\nesp_err_t onewire_del_device_iter(onewire_device_iter_handle_t iter)\n{\n    ESP_RETURN_ON_FALSE(iter, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n\n    free(iter);\n\n    return ESP_OK;\n}\n\n// Search algorithm inspired by https://www.analog.com/en/app-notes/1wire-search-algorithm.html\nesp_err_t onewire_device_iter_get_next(onewire_device_iter_handle_t iter, onewire_device_t *dev)\n{\n    ESP_RETURN_ON_FALSE(iter && dev, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    // we don't treat iterator ending and ESP_ERR_NOT_FOUND as an error condition, so just print debug message here\n    if (iter->is_last_device) {\n        ESP_LOGD(TAG, \"1-wire rom search finished\");\n        return ESP_ERR_NOT_FOUND;\n    }\n    onewire_bus_handle_t bus = iter->bus;\n    esp_err_t reset_result = onewire_bus_reset(bus);\n    if (reset_result == ESP_ERR_NOT_FOUND) {\n        ESP_LOGW(TAG, \"reset bus failed: no devices found\");\n        return ESP_ERR_NOT_FOUND;\n    }\n    ESP_RETURN_ON_ERROR(reset_result, TAG, \"reset bus failed\");\n\n    // send rom search command and start search algorithm\n    ESP_RETURN_ON_ERROR(onewire_bus_write_bytes(bus, (uint8_t[]) {\n        ONEWIRE_CMD_SEARCH_NORMAL\n    }, 1), TAG, \"send ONEWIRE_CMD_SEARCH_NORMAL failed\");\n\n    uint8_t last_zero = 0;\n    for (uint16_t rom_bit_index = 0; rom_bit_index < sizeof(onewire_device_address_t) * 8; rom_bit_index ++) {\n        uint8_t rom_byte_index = rom_bit_index / 8;\n        uint8_t rom_bit_mask = 1 << (rom_bit_index % 8); // calculate byte index and bit mask in advance for convenience\n\n        uint8_t rom_bit = 0;\n        uint8_t rom_bit_complement = 0;\n        ESP_RETURN_ON_ERROR(onewire_bus_read_bit(bus, &rom_bit), TAG, \"read rom_bit error\"); // write 1 bit to read from the bus\n        ESP_RETURN_ON_ERROR(onewire_bus_read_bit(bus, &rom_bit_complement), TAG, \"read rom_bit_complement error\"); // read a bit and its complement\n\n        // No devices participating in search.\n        if (rom_bit && rom_bit_complement) {\n            ESP_LOGE(TAG, \"no devices participating in search\");\n            return ESP_ERR_NOT_FOUND;\n        }\n\n        uint8_t search_direction;\n        if (rom_bit != rom_bit_complement) { // There are only 0s or 1s in the bit of the participating ROM numbers.\n            search_direction = rom_bit;  // just go ahead\n        } else { // There are both 0s and 1s in the current bit position of the participating ROM numbers. This is a discrepancy.\n            if (rom_bit_index < iter->last_discrepancy) { // current id bit is before the last discrepancy bit\n                search_direction = (iter->rom_number[rom_byte_index] & rom_bit_mask) ? 0x01 : 0x00; // follow previous way\n            } else {\n                search_direction = (rom_bit_index == iter->last_discrepancy) ? 0x01 : 0x00; // search for 0 bit first\n            }\n\n            if (search_direction == 0) { // record zero's position in last zero\n                last_zero = rom_bit_index;\n            }\n        }\n\n        if (search_direction == 1) { // set corresponding rom bit by search direction\n            iter->rom_number[rom_byte_index] |= rom_bit_mask;\n        } else {\n            iter->rom_number[rom_byte_index] &= ~rom_bit_mask;\n        }\n\n        // set search direction\n        ESP_RETURN_ON_ERROR(onewire_bus_write_bit(bus, search_direction), TAG, \"write direction bit error\");\n    }\n\n    // if the search was successful\n    iter->last_discrepancy = last_zero;\n    if (iter->last_discrepancy == 0) { // last zero loops back to the first bit\n        iter->is_last_device = true;\n    }\n\n    // check crc\n    ESP_RETURN_ON_FALSE(onewire_crc8(0, iter->rom_number, 7) == iter->rom_number[7], ESP_ERR_INVALID_CRC, TAG, \"bad device crc\");\n\n    // save the ROM number as the device address\n    memcpy(&dev->address, iter->rom_number, sizeof(onewire_device_address_t));\n    dev->bus = bus;\n    ESP_LOGD(TAG, \"new 1-Wire device found, address: %016llX\", dev->address);\n\n    return ESP_OK;\n}\n"
  },
  {
    "path": "onewire_bus/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(onewire_bus_test)\n"
  },
  {
    "path": "onewire_bus/test_apps/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"onewire_bus_test.c\"\n                    INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES unity)\n"
  },
  {
    "path": "onewire_bus/test_apps/main/Kconfig.projbuild",
    "content": "menu \"Example Configuration\"\n\n    choice EXAMPLE_ONEWIRE_BACKEND\n        prompt \"1-Wire backend\"\n        default EXAMPLE_ONEWIRE_BACKEND_RMT if SOC_RMT_SUPPORTED\n        default EXAMPLE_ONEWIRE_BACKEND_UART if SOC_UART_SUPPORTED\n        help\n            Select which low-level backend the test app uses.\n\n        config EXAMPLE_ONEWIRE_BACKEND_RMT\n            bool \"RMT backend\"\n            depends on SOC_RMT_SUPPORTED\n\n        config EXAMPLE_ONEWIRE_BACKEND_UART\n            bool \"UART backend\"\n            depends on SOC_UART_SUPPORTED\n    endchoice\n\n    config EXAMPLE_ONEWIRE_UART_PORT_NUM\n        int \"UART port number\"\n        depends on EXAMPLE_ONEWIRE_BACKEND_UART\n        default 1\n        range 0 2\n        help\n            UART port used by UART backend.\n            Valid UART port numbers differ across targets.\n            Note: UART0 is typically used by the console output.\n\n    config EXAMPLE_ONEWIRE_BUS_GPIO\n        int \"1-Wire data GPIO\"\n        default 0\n        range 0 63\n        help\n            GPIO number used for the 1-Wire data line.\n            Valid GPIO numbers depend on the selected target; choose a\n            data-capable GPIO within this range for your chip.\n\n    config EXAMPLE_ONEWIRE_ENABLE_INTERNAL_PULLUP\n        bool \"Enable internal pull-up\"\n        default y\n        help\n            Enable internal pull-up resistor on the GPIO pin used for the 1-Wire data line.\n            This is useful when no external pull-up resistor is present.\n\n    config EXAMPLE_ONEWIRE_MAX_DEVICES\n        int \"Maximum devices to search\"\n        default 2\n        range 1 64\n        help\n            Maximum number of devices to search on the 1-Wire bus.\n            This test app performs SEARCH ROM to collect device addresses (64-bit ROM IDs).\n\nendmenu\n"
  },
  {
    "path": "onewire_bus/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/onewire_bus:\n    version: \"*\"\n    override_path: \"../..\"\n"
  },
  {
    "path": "onewire_bus/test_apps/main/onewire_bus_test.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n#include \"esp_log.h\"\n#include \"esp_check.h\"\n#include \"sdkconfig.h\"\n#include \"onewire_bus.h\"\n#include \"onewire_device.h\"\n\nstatic const char *TAG = \"test-app\";\n\n#if CONFIG_EXAMPLE_ONEWIRE_ENABLE_INTERNAL_PULLUP\n#define EXAMPLE_ONEWIRE_ENABLE_INTERNAL_PULLUP 1\n#else\n#define EXAMPLE_ONEWIRE_ENABLE_INTERNAL_PULLUP 0\n#endif\n\n#if CONFIG_EXAMPLE_ONEWIRE_BACKEND_UART\n#define EXAMPLE_ONEWIRE_UART_PORT_NUM CONFIG_EXAMPLE_ONEWIRE_UART_PORT_NUM\n#endif\n\n#define EXAMPLE_ONEWIRE_BUS_GPIO     CONFIG_EXAMPLE_ONEWIRE_BUS_GPIO\n#define EXAMPLE_ONEWIRE_MAX_DEVICES  CONFIG_EXAMPLE_ONEWIRE_MAX_DEVICES\n\nvoid app_main(void)\n{\n    // install new 1-wire bus\n    onewire_bus_handle_t bus;\n    onewire_bus_config_t bus_config = {\n        .bus_gpio_num = EXAMPLE_ONEWIRE_BUS_GPIO,\n        .flags = {\n            .en_pull_up = EXAMPLE_ONEWIRE_ENABLE_INTERNAL_PULLUP,\n        }\n    };\n#if CONFIG_EXAMPLE_ONEWIRE_BACKEND_RMT\n    onewire_bus_rmt_config_t rmt_config = {\n        .max_rx_bytes = 10, // 1byte ROM command + 8byte ROM number + 1byte device command\n    };\n    ESP_ERROR_CHECK(onewire_new_bus_rmt(&bus_config, &rmt_config, &bus));\n    ESP_LOGI(TAG, \"1-Wire bus installed on GPIO%d by RMT backend\", EXAMPLE_ONEWIRE_BUS_GPIO);\n#elif CONFIG_EXAMPLE_ONEWIRE_BACKEND_UART\n    onewire_bus_uart_config_t uart_config = {\n        .uart_port_num = EXAMPLE_ONEWIRE_UART_PORT_NUM,\n    };\n    ESP_ERROR_CHECK(onewire_new_bus_uart(&bus_config, &uart_config, &bus));\n    ESP_LOGI(TAG, \"1-Wire bus installed on GPIO%d by UART backend (UART%d)\",\n             EXAMPLE_ONEWIRE_BUS_GPIO, EXAMPLE_ONEWIRE_UART_PORT_NUM);\n#else\n#error \"No 1-Wire backend selected in menuconfig\"\n#endif\n\n    int onewire_device_found = 0;\n    onewire_device_iter_handle_t iter = NULL;\n    onewire_device_t next_onewire_device;\n    esp_err_t search_result = ESP_OK;\n\n    // create 1-wire device iterator, which is used for device search\n    ESP_ERROR_CHECK(onewire_new_device_iter(bus, &iter));\n    ESP_LOGI(TAG, \"Device iterator created, start searching...\");\n    do {\n        search_result = onewire_device_iter_get_next(iter, &next_onewire_device);\n        // found a new device\n        if (search_result == ESP_OK) {\n            ESP_LOGI(TAG, \"Found a new device, address: %016llX\", next_onewire_device.address);\n            onewire_device_found++;\n            if (onewire_device_found >= EXAMPLE_ONEWIRE_MAX_DEVICES) {\n                ESP_LOGI(TAG, \"Max device number reached, stop searching...\");\n                break;\n            }\n        }\n    } while (search_result != ESP_ERR_NOT_FOUND);\n    ESP_ERROR_CHECK(onewire_del_device_iter(iter));\n    ESP_LOGI(TAG, \"Searching done, %d device(s) found\", onewire_device_found);\n\n    // delete the bus\n    ESP_LOGI(TAG, \"Deleting bus...\");\n    ESP_ERROR_CHECK(onewire_bus_del(bus));\n}\n"
  },
  {
    "path": "onewire_bus/test_apps/pytest_onewire_bus.py",
    "content": "# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\n\n@pytest.mark.generic\n@pytest.mark.parametrize('config', ['rmt', 'uart'], indirect=True)\ndef test_onewire_bus(dut: Dut, config: str) -> None:\n    if config == 'rmt':\n        dut.expect_exact('test-app: 1-Wire bus installed on GPIO0 by RMT backend')\n    elif config == 'uart':\n        dut.expect_exact('test-app: 1-Wire bus installed on GPIO0 by UART backend (UART1)')\n    else:\n        raise ValueError(f'Unknown test config: {config}')\n    dut.expect_exact('test-app: Device iterator created, start searching')\n    dut.expect_exact('test-app: Searching done')\n"
  },
  {
    "path": "onewire_bus/test_apps/sdkconfig.ci.rmt",
    "content": "CONFIG_EXAMPLE_ONEWIRE_BACKEND_RMT=y\nCONFIG_EXAMPLE_ONEWIRE_BACKEND_UART=n\n"
  },
  {
    "path": "onewire_bus/test_apps/sdkconfig.ci.uart",
    "content": "CONFIG_EXAMPLE_ONEWIRE_BACKEND_RMT=n\nCONFIG_EXAMPLE_ONEWIRE_BACKEND_UART=y\n"
  },
  {
    "path": "pcap/.build-test-rules.yml",
    "content": ""
  },
  {
    "path": "pcap/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"src/pcap.c\"\n                       INCLUDE_DIRS \"include\")\n"
  },
  {
    "path": "pcap/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "pcap/README.md",
    "content": "# Simple PCAP file writer\n\n[![Component Registry](https://components.espressif.com/components/espressif/pcap/badge.svg)](https://components.espressif.com/components/espressif/pcap)\n\nThis component allows users to trace their captured packets in .pcap file format.\n\nMore details about PCAP format can be found [here](https://wiki.wireshark.org/Development/LibpcapFileFormat).\n"
  },
  {
    "path": "pcap/idf_component.yml",
    "content": "version: \"1.0.2\"\ndescription: PCAP file writer\nurl: https://github.com/espressif/idf-extra-components/tree/master/pcap\ndependencies:\n  idf: \">=4.4\"\n"
  },
  {
    "path": "pcap/include/pcap.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include <stdio.h>\n#include \"esp_err.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define PCAP_DEFAULT_VERSION_MAJOR 0x02 /*!< Major Version */\n#define PCAP_DEFAULT_VERSION_MINOR 0x04 /*!< Minor Version */\n#define PCAP_DEFAULT_TIME_ZONE_GMT 0x00 /*!< Time Zone */\n\n/**\n * @brief Type of pcap file handle\n *\n */\ntypedef struct pcap_file_t *pcap_file_handle_t;\n\n/**\n* @brief Link layer Type Definition, used for Pcap reader to decode payload\n*\n*/\ntypedef enum {\n    PCAP_LINK_TYPE_LOOPBACK = 0,       /*!< Loopback devices, except for later OpenBSD */\n    PCAP_LINK_TYPE_ETHERNET = 1,       /*!< Ethernet, and Linux loopback devices */\n    PCAP_LINK_TYPE_TOKEN_RING = 6,     /*!< 802.5 Token Ring */\n    PCAP_LINK_TYPE_ARCNET = 7,         /*!< ARCnet */\n    PCAP_LINK_TYPE_SLIP = 8,           /*!< SLIP */\n    PCAP_LINK_TYPE_PPP = 9,            /*!< PPP */\n    PCAP_LINK_TYPE_FDDI = 10,          /*!< FDDI */\n    PCAP_LINK_TYPE_ATM = 100,          /*!< LLC/SNAP encapsulated ATM */\n    PCAP_LINK_TYPE_RAW_IP = 101,       /*!< Raw IP, without link */\n    PCAP_LINK_TYPE_BSD_SLIP = 102,     /*!< BSD/OS SLIP */\n    PCAP_LINK_TYPE_BSD_PPP = 103,      /*!< BSD/OS PPP */\n    PCAP_LINK_TYPE_CISCO_HDLC = 104,   /*!< Cisco HDLC */\n    PCAP_LINK_TYPE_802_11 = 105,       /*!< 802.11 */\n    PCAP_LINK_TYPE_BSD_LOOPBACK = 108, /*!< OpenBSD loopback devices(with AF_value in network byte order) */\n    PCAP_LINK_TYPE_LOCAL_TALK = 114,   /*!< LocalTalk */\n    PCAP_LINK_TYPE_USBPCAP = 249,      /*!< USB packets, beginning with a USBPcap header */\n} pcap_link_type_t;\n\n/**\n* @brief Pcap configuration Type Definition\n*\n*/\ntypedef struct {\n    FILE *fp;                   /*!< Pointer to a standard file handle */\n    unsigned int major_version; /*!< Pcap version: major */\n    unsigned int minor_version; /*!< Pcap version: minor */\n    unsigned int time_zone;     /*!< Pcap timezone code */\n    struct {\n        unsigned int little_endian: 1; /*!< Whether the pcap file is recorded in little endian format */\n    } flags;\n} pcap_config_t;\n\n/**\n * @brief Create a new pcap session, and returns pcap file handle\n *\n * @note This function won't create the low level FILE* object, the user should take care of the creation of the File Stream.\n *\n * @param[in] config pcap file configuration\n * @param[out] ret_pcap Returned pcap file handle\n * @return\n *      - ESP_OK: Create pcap file successfully\n *      - ESP_ERR_INVALID_ARG: Create pcap file failed because of invalid argument\n *      - ESP_ERR_NO_MEM: Create pcap file failed because out of memory\n *      - ESP_FAIL: Create pcap file failed\n */\nesp_err_t pcap_new_session(const pcap_config_t *config, pcap_file_handle_t *ret_pcap);\n\n/**\n * @brief Delete the pcap session, and close the File Stream\n *\n * @param[in] pcap pcap file handle created by `pcap_new_session()`\n * @return\n *      - ESP_OK: Delete pcap session successfully\n *      - ESP_ERR_INVALID_ARG: Delete pcap session failed because of invalid argument\n *      - ESP_FAIL: Delete pcap session failed\n */\nesp_err_t pcap_del_session(pcap_file_handle_t pcap);\n\n/**\n * @brief Write pcap file header\n *\n * @param[in] pcap pcap file handle created by `pcap_new_session()`\n * @param[in] link_type Network link layer type\n * @return\n *      - ESP_OK: Write pcap file header successfully\n *      - ESP_ERR_INVALID_ARG: Write pcap file header failed because of invalid argument\n *      - ESP_FAIL: Write pcap file header failed\n */\nesp_err_t pcap_write_header(pcap_file_handle_t pcap, pcap_link_type_t link_type);\n\n/**\n * @brief Capture one packet into pcap file\n *\n * @param[in] pcap pcap file handle created by `pcap_new_session()`\n * @param[in] payload pointer of the captured data buffer\n * @param[in] length length of captured data buffer\n * @param[in] seconds second of capture time\n * @param[in] microseconds microsecond of capture time\n * @return\n *      - ESP_OK: Write network packet into pcap file successfully\n *      - ESP_ERR_INVALID_ARG: Write network packet into pcap file failed because of invalid argument\n *      - ESP_FAIL: Write network packet into pcap file failed\n */\nesp_err_t pcap_capture_packet(pcap_file_handle_t pcap, void *payload, uint32_t length, uint32_t seconds, uint32_t microseconds);\n\n/**\n * @brief Print the summary of pcap file into stream\n *\n * @param[in] pcap pcap file handle created by `pcap_new_session()`\n * @param[in] print_file the file stream to save the summary\n * @return\n *      - ESP_OK: Print pcap file summary successfully\n *      - ESP_ERR_INVALID_ARG: Print pcap file summary failed because of invalid argument\n *      - ESP_FAIL: Print pcap file summary failed\n */\nesp_err_t pcap_print_summary(pcap_file_handle_t pcap, FILE *print_file);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "pcap/src/pcap.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <inttypes.h>\n#include \"esp_log.h\"\n#include \"esp_check.h\"\n#include \"pcap.h\"\n\nstatic const char *TAG = \"pcap\";\n\n#define PCAP_MAGIC_BIG_ENDIAN 0xA1B2C3D4    /*!< Big-Endian */\n#define PCAP_MAGIC_LITTLE_ENDIAN 0xD4C3B2A1 /*!< Little-Endian */\n\ntypedef struct pcap_file_t pcap_file_t;\n\n/**\n * @brief Pcap File Header\n *\n */\ntypedef struct {\n    uint32_t magic;     /*!< Magic Number */\n    uint16_t major;     /*!< Major Version */\n    uint16_t minor;     /*!< Minor Version */\n    uint32_t zone;      /*!< Time Zone Offset */\n    uint32_t sigfigs;   /*!< Timestamp Accuracy */\n    uint32_t snaplen;   /*!< Max Length to Capture */\n    uint32_t link_type; /*!< Link Layer Type */\n} pcap_file_header_t;\n\n/**\n * @brief Pcap Packet Header\n *\n */\ntypedef struct {\n    uint32_t seconds;        /*!< Number of seconds since January 1st, 1970, 00:00:00 GMT */\n    uint32_t microseconds;   /*!< Number of microseconds when the packet was captured (offset from seconds) */\n    uint32_t capture_length; /*!< Number of bytes of captured data, no longer than packet_length */\n    uint32_t packet_length;  /*!< Actual length of current packet */\n} pcap_packet_header_t;\n\n/**\n * @brief Pcap Runtime Handle\n *\n */\nstruct pcap_file_t {\n    FILE *file;                 /*!< File handle */\n    pcap_link_type_t link_type; /*!< Pcap Link Type */\n    unsigned int major_version; /*!< Pcap version: major */\n    unsigned int minor_version; /*!< Pcap version: minor */\n    unsigned int time_zone;     /*!< Pcap timezone code */\n    uint32_t endian_magic;      /*!< Magic value related to endian format */\n};\n\nesp_err_t pcap_new_session(const pcap_config_t *config, pcap_file_handle_t *ret_pcap)\n{\n    esp_err_t ret = ESP_OK;\n    pcap_file_t *pcap = NULL;\n    ESP_GOTO_ON_FALSE(config && ret_pcap, ESP_ERR_INVALID_ARG, err, TAG, \"invalid argument\");\n    ESP_GOTO_ON_FALSE(config->fp, ESP_ERR_INVALID_ARG, err, TAG, \"pcap file handle can't be NULL\");\n    pcap = calloc(1, sizeof(pcap_file_t));\n    ESP_GOTO_ON_FALSE(pcap, ESP_ERR_NO_MEM, err, TAG, \"no mem for pcap file object\");\n    pcap->file = config->fp;\n    pcap->major_version = config->major_version;\n    pcap->minor_version = config->minor_version;\n    pcap->endian_magic = config->flags.little_endian ? PCAP_MAGIC_LITTLE_ENDIAN : PCAP_MAGIC_BIG_ENDIAN;\n    pcap->time_zone = config->time_zone;\n    *ret_pcap = pcap;\n    return ret;\nerr:\n    if (pcap) {\n        free(pcap);\n    }\n    return ret;\n}\n\nesp_err_t pcap_del_session(pcap_file_handle_t pcap)\n{\n    ESP_RETURN_ON_FALSE(pcap, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    if (pcap->file) {\n        fclose(pcap->file);\n        pcap->file = NULL;\n    }\n    free(pcap);\n    return ESP_OK;\n}\n\nesp_err_t pcap_write_header(pcap_file_handle_t pcap, pcap_link_type_t link_type)\n{\n    ESP_RETURN_ON_FALSE(pcap, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    /* Write Pcap File header */\n    pcap_file_header_t header = {\n        .magic = pcap->endian_magic,\n        .major = pcap->major_version,\n        .minor = pcap->minor_version,\n        .zone = pcap->time_zone,\n        .sigfigs = 0,\n        .snaplen = 0x40000,\n        .link_type = link_type,\n    };\n    size_t real_write = fwrite(&header, sizeof(header), 1, pcap->file);\n    ESP_RETURN_ON_FALSE(real_write == 1, ESP_FAIL, TAG, \"write pcap file header failed\");\n    /* Save the link type to pcap file object */\n    pcap->link_type = link_type;\n    /* Flush content in the buffer into device */\n    fflush(pcap->file);\n    return ESP_OK;\n}\n\nesp_err_t pcap_capture_packet(pcap_file_handle_t pcap, void *payload, uint32_t length, uint32_t seconds, uint32_t microseconds)\n{\n    ESP_RETURN_ON_FALSE(pcap && payload, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    size_t real_write = 0;\n    pcap_packet_header_t header = {\n        .seconds = seconds,\n        .microseconds = microseconds,\n        .capture_length = length,\n        .packet_length = length\n    };\n    real_write = fwrite(&header, sizeof(header), 1, pcap->file);\n    ESP_RETURN_ON_FALSE(real_write == 1, ESP_FAIL, TAG, \"write packet header failed\");\n    real_write = fwrite(payload, sizeof(uint8_t), length, pcap->file);\n    ESP_RETURN_ON_FALSE(real_write == length, ESP_FAIL, TAG, \"write packet payload failed\");\n    /* Flush content in the buffer into device */\n    fflush(pcap->file);\n    return ESP_OK;\n}\n\nesp_err_t pcap_print_summary(pcap_file_handle_t pcap, FILE *print_file)\n{\n    esp_err_t ret = ESP_OK;\n    long size = 0;\n    char *packet_payload = NULL;\n    ESP_RETURN_ON_FALSE(pcap && print_file, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    // get file size\n    fseek(pcap->file, 0L, SEEK_END);\n    size = ftell(pcap->file);\n    fseek(pcap->file, 0L, SEEK_SET);\n    // file empty is allowed, so return ESP_OK\n    ESP_RETURN_ON_FALSE(size, ESP_OK, TAG, \"pcap file is empty\");\n    // packet index (by bytes)\n    uint32_t index = 0;\n    pcap_file_header_t file_header;\n    size_t real_read = fread(&file_header, sizeof(pcap_file_header_t), 1, pcap->file);\n    ESP_RETURN_ON_FALSE(real_read == 1, ESP_FAIL, TAG, \"read pcap file header failed\");\n    index += sizeof(pcap_file_header_t);\n    //print pcap header information\n    fprintf(print_file, \"------------------------------------------------------------------------\\n\");\n    fprintf(print_file, \"Pcap packet Head:\\n\");\n    fprintf(print_file, \"------------------------------------------------------------------------\\n\");\n    fprintf(print_file, \"Magic Number: %\"PRIx32\"\\n\", file_header.magic);\n    fprintf(print_file, \"Major Version: %d\\n\", file_header.major);\n    fprintf(print_file, \"Minor Version: %d\\n\", file_header.minor);\n    fprintf(print_file, \"SnapLen: %\"PRIu32\"\\n\", file_header.snaplen);\n    fprintf(print_file, \"LinkType: %\"PRIu32\"\\n\", file_header.link_type);\n    fprintf(print_file, \"------------------------------------------------------------------------\\n\");\n    uint32_t packet_num = 0;\n    pcap_packet_header_t packet_header;\n    while (index < size) {\n        real_read = fread(&packet_header, sizeof(pcap_packet_header_t), 1, pcap->file);\n        ESP_GOTO_ON_FALSE(real_read == 1, ESP_FAIL, err, TAG, \"read pcap packet header failed\");\n        // print packet header information\n        fprintf(print_file, \"Packet %\"PRIu32\":\\n\", packet_num);\n        fprintf(print_file, \"Timestamp (Seconds): %\"PRIu32\"\\n\", packet_header.seconds);\n        fprintf(print_file, \"Timestamp (Microseconds): %\"PRIu32\"\\n\", packet_header.microseconds);\n        fprintf(print_file, \"Capture Length: %\"PRIu32\"\\n\", packet_header.capture_length);\n        fprintf(print_file, \"Packet Length: %\"PRIu32\"\\n\", packet_header.packet_length);\n        size_t payload_length = packet_header.capture_length;\n        packet_payload = malloc(payload_length);\n        ESP_GOTO_ON_FALSE(packet_payload, ESP_ERR_NO_MEM, err, TAG, \"no mem to save packet payload\");\n        real_read = fread(packet_payload, payload_length, 1, pcap->file);\n        ESP_GOTO_ON_FALSE(real_read == 1, ESP_FAIL, err, TAG, \"read payload error\");\n        // print packet information\n        if (file_header.link_type == PCAP_LINK_TYPE_802_11) {\n            // Frame Control Field is coded as LSB first\n            fprintf(print_file, \"Frame Type: %2x\\n\", (packet_payload[0] >> 2) & 0x03);\n            fprintf(print_file, \"Frame Subtype: %2x\\n\", (packet_payload[0] >> 4) & 0x0F);\n            fprintf(print_file, \"Destination: \");\n            for (int j = 0; j < 5; j++) {\n                fprintf(print_file, \"%2x \", packet_payload[4 + j]);\n            }\n            fprintf(print_file, \"%2x\\n\", packet_payload[9]);\n            fprintf(print_file, \"Source: \");\n            for (int j = 0; j < 5; j++) {\n                fprintf(print_file, \"%2x \", packet_payload[10 + j]);\n            }\n            fprintf(print_file, \"%2x\\n\", packet_payload[15]);\n            fprintf(print_file, \"------------------------------------------------------------------------\\n\");\n        } else if (file_header.link_type == PCAP_LINK_TYPE_ETHERNET) {\n            fprintf(print_file, \"Destination: \");\n            for (int j = 0; j < 5; j++) {\n                fprintf(print_file, \"%2x \", packet_payload[j]);\n            }\n            fprintf(print_file, \"%2x\\n\", packet_payload[5]);\n            fprintf(print_file, \"Source: \");\n            for (int j = 0; j < 5; j++) {\n                fprintf(print_file, \"%2x \", packet_payload[6 + j]);\n            }\n            fprintf(print_file, \"%2x\\n\", packet_payload[11]);\n            fprintf(print_file, \"Type: 0x%x\\n\", packet_payload[13] | (packet_payload[12] << 8));\n            fprintf(print_file, \"------------------------------------------------------------------------\\n\");\n        } else {\n            fprintf(print_file, \"Unknown link type:%\"PRIu32\"\\n\", file_header.link_type);\n            fprintf(print_file, \"------------------------------------------------------------------------\\n\");\n        }\n        free(packet_payload);\n        packet_payload = NULL;\n        index += packet_header.capture_length + sizeof(pcap_packet_header_t);\n        packet_num ++;\n    }\n    fprintf(print_file, \"Pcap packet Number: %\"PRIu32\"\\n\", packet_num);\n    fprintf(print_file, \"------------------------------------------------------------------------\\n\");\n    return ret;\nerr:\n    if (packet_payload) {\n        free(packet_payload);\n    }\n    return ret;\n}\n"
  },
  {
    "path": "pcap/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(pcap_test)\n"
  },
  {
    "path": "pcap/test_apps/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"pcap_test.c\"\n                    INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES unity)\n"
  },
  {
    "path": "pcap/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/pcap:\n    version: \"*\"\n    override_path: \"../..\"\n"
  },
  {
    "path": "pcap/test_apps/main/pcap_test.c",
    "content": "#include <stdio.h>\n\nvoid app_main(void)\n{\n\n}\n"
  },
  {
    "path": "pid_ctrl/.build-test-rules.yml",
    "content": ""
  },
  {
    "path": "pid_ctrl/CMakeLists.txt",
    "content": "set(srcs \"src/pid_ctrl.c\")\n\nidf_component_register(SRCS \"${srcs}\"\n                       INCLUDE_DIRS \"include\")\n"
  },
  {
    "path": "pid_ctrl/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "pid_ctrl/README.md",
    "content": "# Proportional integral derivative controller\n\n[![Component Registry](https://components.espressif.com/components/espressif/pid_ctrl/badge.svg)](https://components.espressif.com/components/espressif/pid_ctrl)"
  },
  {
    "path": "pid_ctrl/idf_component.yml",
    "content": "version: \"0.2.0\"\ndescription: Proportional-integral-derivative controller\nurl: https://github.com/espressif/idf-extra-components/tree/master/pid_ctrl\ndependencies:\n  idf: \">=4.4\"\n"
  },
  {
    "path": "pid_ctrl/include/pid_ctrl.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include \"esp_err.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief PID calculation type\n *\n */\ntypedef enum {\n    PID_CAL_TYPE_INCREMENTAL, /*!< Incremental PID control */\n    PID_CAL_TYPE_POSITIONAL,  /*!< Positional PID control */\n} pid_calculate_type_t;\n\n/**\n * @brief Type of PID control block handle\n *\n */\ntypedef struct pid_ctrl_block_t *pid_ctrl_block_handle_t;\n\n/**\n * @brief PID control parameters\n *\n */\ntypedef struct {\n    float kp;                      // PID Kp parameter\n    float ki;                      // PID Ki parameter\n    float kd;                      // PID Kd parameter\n    float max_output;              // PID maximum output limitation\n    float min_output;              // PID minimum output limitation\n    float max_integral;            // PID maximum integral value limitation\n    float min_integral;            // PID minimum integral value limitation\n    pid_calculate_type_t cal_type; // PID calculation type\n} pid_ctrl_parameter_t;\n\n/**\n * @brief PID control configuration\n *\n */\ntypedef struct {\n    pid_ctrl_parameter_t init_param; // Initial parameters\n} pid_ctrl_config_t;\n\n/**\n * @brief Create a new PID control session, returns the handle of control block\n *\n * @param[in] config PID control configuration\n * @param[out] ret_pid Returned PID control block handle\n * @return\n *      - ESP_OK: Created PID control block successfully\n *      - ESP_ERR_INVALID_ARG: Created PID control block failed because of invalid argument\n *      - ESP_ERR_NO_MEM: Created PID control block failed because out of memory\n */\nesp_err_t pid_new_control_block(const pid_ctrl_config_t *config, pid_ctrl_block_handle_t *ret_pid);\n\n/**\n * @brief Delete the PID control block\n *\n * @param[in] pid PID control block handle, created by `pid_new_control_block()`\n * @return\n *      - ESP_OK: Delete PID control block successfully\n *      - ESP_ERR_INVALID_ARG: Delete PID control block failed because of invalid argument\n */\nesp_err_t pid_del_control_block(pid_ctrl_block_handle_t pid);\n\n/**\n * @brief Update PID parameters\n *\n * @param[in] pid PID control block handle, created by `pid_new_control_block()`\n * @param[in] params PID parameters\n * @return\n *      - ESP_OK: Update PID parameters successfully\n *      - ESP_ERR_INVALID_ARG: Update PID parameters failed because of invalid argument\n */\nesp_err_t pid_update_parameters(pid_ctrl_block_handle_t pid, const pid_ctrl_parameter_t *params);\n\n/**\n * @brief Input error and get PID control result\n *\n * @param[in] pid PID control block handle, created by `pid_new_control_block()`\n * @param[in] input_error error data that feed to the PID controller\n * @param[out] ret_result result after PID calculation\n * @return\n *      - ESP_OK: Run a PID compute successfully\n *      - ESP_ERR_INVALID_ARG: Run a PID compute failed because of invalid argument\n */\nesp_err_t pid_compute(pid_ctrl_block_handle_t pid, float input_error, float *ret_result);\n\n/**\n * @brief Reset the accumulation in pid_ctrl_block\n *\n * @param[in] pid PID control block handle, created by `pid_new_control_block()`\n * @return\n *      - ESP_OK: Reset successfully\n *      - ESP_ERR_INVALID_ARG: Reset failed because of invalid argument\n */\nesp_err_t pid_reset_ctrl_block(pid_ctrl_block_handle_t pid);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "pid_ctrl/src/pid_ctrl.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdbool.h>\n#include <sys/param.h>\n#include \"esp_check.h\"\n#include \"esp_log.h\"\n#include \"pid_ctrl.h\"\n\nstatic const char *TAG = \"pid_ctrl\";\n\ntypedef struct pid_ctrl_block_t pid_ctrl_block_t;\ntypedef float (*pid_cal_func_t)(pid_ctrl_block_t *pid, float error);\n\nstruct pid_ctrl_block_t {\n    float Kp; // PID Kp value\n    float Ki; // PID Ki value\n    float Kd; // PID Kd value\n    float previous_err1; // e(k-1)\n    float previous_err2; // e(k-2)\n    float integral_err;  // Sum of error\n    float last_output;  // PID output in last control period\n    float max_output;   // PID maximum output limitation\n    float min_output;   // PID minimum output limitation\n    float max_integral; // PID maximum integral value limitation\n    float min_integral; // PID minimum integral value limitation\n    pid_cal_func_t calculate_func; // calculation function, depends on actual PID type set by user\n};\n\nstatic float pid_calc_positional(pid_ctrl_block_t *pid, float error)\n{\n    float output = 0;\n    /* Add current error to the integral error */\n    pid->integral_err += error;\n    /* If the integral error is out of the range, it will be limited */\n    pid->integral_err = MIN(pid->integral_err, pid->max_integral);\n    pid->integral_err = MAX(pid->integral_err, pid->min_integral);\n\n    /* Calculate the pid control value by location formula */\n    /* u(k) = e(k)*Kp + (e(k)-e(k-1))*Kd + integral*Ki */\n    output = error * pid->Kp +\n             (error - pid->previous_err1) * pid->Kd +\n             pid->integral_err * pid->Ki;\n\n    /* If the output is out of the range, it will be limited */\n    output = MIN(output, pid->max_output);\n    output = MAX(output, pid->min_output);\n\n    /* Update previous error */\n    pid->previous_err1 = error;\n\n    return output;\n}\n\nstatic float pid_calc_incremental(pid_ctrl_block_t *pid, float error)\n{\n    float output = 0;\n\n    /* Calculate the pid control value by increment formula */\n    /* du(k) = (e(k)-e(k-1))*Kp + (e(k)-2*e(k-1)+e(k-2))*Kd + e(k)*Ki */\n    /* u(k) = du(k) + u(k-1) */\n    output = (error - pid->previous_err1) * pid->Kp +\n             (error - 2 * pid->previous_err1 + pid->previous_err2) * pid->Kd +\n             error * pid->Ki +\n             pid->last_output;\n\n    /* If the output is beyond the range, it will be limited */\n    output = MIN(output, pid->max_output);\n    output = MAX(output, pid->min_output);\n\n    /* Update previous error */\n    pid->previous_err2 = pid->previous_err1;\n    pid->previous_err1 = error;\n\n    /* Update last output */\n    pid->last_output = output;\n\n    return output;\n}\n\nesp_err_t pid_new_control_block(const pid_ctrl_config_t *config, pid_ctrl_block_handle_t *ret_pid)\n{\n    esp_err_t ret = ESP_OK;\n    pid_ctrl_block_t *pid = NULL;\n    /* Check the input pointer */\n    ESP_GOTO_ON_FALSE(config && ret_pid, ESP_ERR_INVALID_ARG, err, TAG, \"invalid argument\");\n\n    pid = calloc(1, sizeof(pid_ctrl_block_t));\n    ESP_GOTO_ON_FALSE(pid, ESP_ERR_NO_MEM, err, TAG, \"no mem for PID control block\");\n    ESP_GOTO_ON_ERROR(pid_update_parameters(pid, &config->init_param), err, TAG, \"init PID parameters failed\");\n    *ret_pid = pid;\n    return ret;\n\nerr:\n    if (pid) {\n        free(pid);\n    }\n    return ret;\n}\n\nesp_err_t pid_del_control_block(pid_ctrl_block_handle_t pid)\n{\n    ESP_RETURN_ON_FALSE(pid, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    free(pid);\n    return ESP_OK;\n}\n\nesp_err_t pid_compute(pid_ctrl_block_handle_t pid, float input_error, float *ret_result)\n{\n    ESP_RETURN_ON_FALSE(pid && ret_result, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    *ret_result = pid->calculate_func(pid, input_error);\n    return ESP_OK;\n}\n\nesp_err_t pid_update_parameters(pid_ctrl_block_handle_t pid, const pid_ctrl_parameter_t *params)\n{\n    ESP_RETURN_ON_FALSE(pid && params, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    pid->Kp = params->kp;\n    pid->Ki = params->ki;\n    pid->Kd = params->kd;\n    pid->max_output = params->max_output;\n    pid->min_output = params->min_output;\n    pid->max_integral = params->max_integral;\n    pid->min_integral = params->min_integral;\n    /* Set the calculate function according to the PID type */\n    switch (params->cal_type) {\n    case PID_CAL_TYPE_INCREMENTAL:\n        pid->calculate_func = pid_calc_incremental;\n        break;\n    case PID_CAL_TYPE_POSITIONAL:\n        pid->calculate_func = pid_calc_positional;\n        break;\n    default:\n        ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_ARG, TAG, \"invalid PID calculation type:%d\", params->cal_type);\n    }\n    return ESP_OK;\n}\n\nesp_err_t pid_reset_ctrl_block(pid_ctrl_block_handle_t pid)\n{\n    ESP_RETURN_ON_FALSE(pid, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n    pid->integral_err = 0;\n    pid->previous_err1 = 0;\n    pid->previous_err2 = 0;\n    pid->last_output = 0;\n    return ESP_OK;\n}\n"
  },
  {
    "path": "pid_ctrl/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(pid_ctrl_test)\n"
  },
  {
    "path": "pid_ctrl/test_apps/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"pid_ctrl_test.c\"\n                    INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES unity)\n"
  },
  {
    "path": "pid_ctrl/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/pid_ctrl:\n    version: \"*\"\n    override_path: \"../..\"\n"
  },
  {
    "path": "pid_ctrl/test_apps/main/pid_ctrl_test.c",
    "content": "#include <stdio.h>\n\nvoid app_main(void)\n{\n\n}\n"
  },
  {
    "path": "pytest.ini",
    "content": "[pytest]\n# only the files with prefix `pytest_` would be recognized as pytest test scripts.\npython_files = pytest_*.py\n\n# set traceback to \"short\" to prevent the overwhelming tracebacks\naddopts =\n  -s -vv\n  --embedded-services esp,idf\n  --tb short\n\nmarkers =\n  # env markers\n  generic: generic runner\n  ethernet: ethernet runners\n  spi_nand_flash: runner with SPI NAND flash connected\n  qemu: QEMU runner\n  host_test: xxx\n\n# ignore PytestExperimentalApiWarning for record_xml_attribute\nfilterwarnings =\n  ignore::_pytest.warning_types.PytestExperimentalApiWarning\n\n# log related\nlog_cli = True\nlog_cli_level = INFO\nlog_cli_format = %(asctime)s %(levelname)s %(message)s\nlog_cli_date_format = %Y-%m-%d %H:%M:%S\n# junit related\njunit_family = xunit1\n## log all to `system-out` when case fail\njunit_logging = stdout\njunit_log_passing_tests = False\n"
  },
  {
    "path": "qrcode/.build-test-rules.yml",
    "content": ""
  },
  {
    "path": "qrcode/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"esp_qrcode_main.c\" \"esp_qrcode_wrapper.c\" \"qrcodegen.c\"\n                    INCLUDE_DIRS \"include\"\n                    )\n"
  },
  {
    "path": "qrcode/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "qrcode/README.md",
    "content": "# QR Code generator component\n\n[![Component Registry](https://components.espressif.com/components/espressif/qrcode/badge.svg)](https://components.espressif.com/components/espressif/qrcode)\n\nThis component contains a QR code generator written in C. This component is based on [QR-Code-generator](https://github.com/nayuki/QR-Code-generator).\nThis component is used as part of the following ESP-IDF examples:\n- [DPP Enrollee Example](https://github.com/espressif/esp-idf/tree/master/examples/wifi/wifi_easy_connect/dpp-enrollee).\n\nTo learn more about how to use this component, please check API Documentation from header file [qrcode.h](https://github.com/espressif/idf-extra-components/tree/master/qrcode/include/qrcode.h).\n"
  },
  {
    "path": "qrcode/esp_qrcode_main.c",
    "content": "/*\r\n * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD\r\n *\r\n * SPDX-License-Identifier: Apache-2.0\r\n */\r\n\r\n#include <stdio.h>\r\n#include <esp_err.h>\r\n#include \"esp_log.h\"\r\n\r\n#include \"qrcodegen.h\"\r\n#include \"qrcode.h\"\r\n\r\nstatic const char *TAG = \"QRCODE\";\r\n\r\nstatic const char *lt[] = {\r\n    /* 0 */ \"  \",\r\n    /* 1 */ \"\\u2580 \",\r\n    /* 2 */ \" \\u2580\",\r\n    /* 3 */ \"\\u2580\\u2580\",\r\n    /* 4 */ \"\\u2584 \",\r\n    /* 5 */ \"\\u2588 \",\r\n    /* 6 */ \"\\u2584\\u2580\",\r\n    /* 7 */ \"\\u2588\\u2580\",\r\n    /* 8 */ \" \\u2584\",\r\n    /* 9 */ \"\\u2580\\u2584\",\r\n    /* 10 */ \" \\u2588\",\r\n    /* 11 */ \"\\u2580\\u2588\",\r\n    /* 12 */ \"\\u2584\\u2584\",\r\n    /* 13 */ \"\\u2588\\u2584\",\r\n    /* 14 */ \"\\u2584\\u2588\",\r\n    /* 15 */ \"\\u2588\\u2588\",\r\n};\r\n\r\nvoid esp_qrcode_print_console(esp_qrcode_handle_t qrcode)\r\n{\r\n    int size = qrcodegen_getSize(qrcode);\r\n    int border = 2;\r\n    unsigned char num = 0;\r\n\r\n    for (int y = -border; y < size + border; y += 2) {\r\n        for (int x = -border; x < size + border; x += 2) {\r\n            num = 0;\r\n            if (qrcodegen_getModule(qrcode, x, y)) {\r\n                num |= 1 << 0;\r\n            }\r\n            if ((x < size + border) && qrcodegen_getModule(qrcode, x + 1, y)) {\r\n                num |= 1 << 1;\r\n            }\r\n            if ((y < size + border) && qrcodegen_getModule(qrcode, x, y + 1)) {\r\n                num |= 1 << 2;\r\n            }\r\n            if ((x < size + border) && (y < size + border) && qrcodegen_getModule(qrcode, x + 1, y + 1)) {\r\n                num |= 1 << 3;\r\n            }\r\n            printf(\"%s\", lt[num]);\r\n        }\r\n        printf(\"\\n\");\r\n    }\r\n    printf(\"\\n\");\r\n}\r\n\r\nesp_err_t esp_qrcode_generate(esp_qrcode_config_t *cfg, const char *text)\r\n{\r\n    enum qrcodegen_Ecc ecc_lvl;\r\n    uint8_t *qrcode, *tempbuf;\r\n    esp_err_t err = ESP_FAIL;\r\n\r\n    qrcode = calloc(1, qrcodegen_BUFFER_LEN_FOR_VERSION(cfg->max_qrcode_version));\r\n    if (!qrcode) {\r\n        return ESP_ERR_NO_MEM;\r\n    }\r\n\r\n    tempbuf = calloc(1, qrcodegen_BUFFER_LEN_FOR_VERSION(cfg->max_qrcode_version));\r\n    if (!tempbuf) {\r\n        free(qrcode);\r\n        return ESP_ERR_NO_MEM;\r\n    }\r\n\r\n    switch (cfg->qrcode_ecc_level) {\r\n    case ESP_QRCODE_ECC_LOW:\r\n        ecc_lvl = qrcodegen_Ecc_LOW;\r\n        break;\r\n    case ESP_QRCODE_ECC_MED:\r\n        ecc_lvl = qrcodegen_Ecc_MEDIUM;\r\n        break;\r\n    case ESP_QRCODE_ECC_QUART:\r\n        ecc_lvl = qrcodegen_Ecc_QUARTILE;\r\n        break;\r\n    case ESP_QRCODE_ECC_HIGH:\r\n        ecc_lvl = qrcodegen_Ecc_HIGH;\r\n        break;\r\n    default:\r\n        ecc_lvl = qrcodegen_Ecc_LOW;\r\n        break;\r\n    }\r\n\r\n    ESP_LOGI(TAG, \"Encoding below text with ECC LVL %d & QR Code Version %d\",\r\n             ecc_lvl, cfg->max_qrcode_version);\r\n    ESP_LOGI(TAG, \"%s\", text);\r\n    // Make and print the QR Code symbol\r\n    bool ok = qrcodegen_encodeText(text, tempbuf, qrcode, ecc_lvl,\r\n                                   qrcodegen_VERSION_MIN, cfg->max_qrcode_version,\r\n                                   qrcodegen_Mask_AUTO, true);\r\n    if (ok && cfg->display_func) {\r\n        // If user_data is provided, use callback version\r\n        // Otherwise use simple version (backward compatible)\r\n        if (cfg->user_data != NULL) {\r\n            // Use callback version with user_data\r\n            cfg->display_func_with_cb((esp_qrcode_handle_t)qrcode, cfg->user_data);\r\n        } else {\r\n            // Use simple version without user_data (backward compatible)\r\n            cfg->display_func((esp_qrcode_handle_t)qrcode);\r\n        }\r\n        err = ESP_OK;\r\n    }\r\n\r\n    free(qrcode);\r\n    free(tempbuf);\r\n    return err;\r\n}\r\n"
  },
  {
    "path": "qrcode/esp_qrcode_wrapper.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <esp_err.h>\n\n#include \"qrcodegen.h\"\n#include \"qrcode.h\"\n\nint esp_qrcode_get_size(esp_qrcode_handle_t qrcode)\n{\n    return qrcodegen_getSize(qrcode);\n}\n\nbool esp_qrcode_get_module(esp_qrcode_handle_t qrcode, int x, int y)\n{\n    return qrcodegen_getModule(qrcode, x, y);\n}\n"
  },
  {
    "path": "qrcode/idf_component.yml",
    "content": "version: \"0.2.0\"\ndescription: QR Code generator\nurl: https://github.com/espressif/idf-extra-components/tree/master/qrcode\n"
  },
  {
    "path": "qrcode/include/qrcode.h",
    "content": "/*\r\n * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD\r\n *\r\n * SPDX-License-Identifier: Apache-2.0\r\n */\r\n\r\n#pragma once\r\n\r\n#include <esp_err.h>\r\n\r\n#ifdef __cplusplus\r\nextern \"C\" {\r\n#endif\r\n\r\n/**\r\n  * @brief  QR Code handle used by the display function\r\n  */\r\ntypedef const uint8_t *esp_qrcode_handle_t;\r\n\r\n/**\r\n  * @brief  QR Code configuration options\r\n  */\r\ntypedef struct {\r\n    union {\r\n        void (*display_func)(esp_qrcode_handle_t qrcode);                    /**< Function called for displaying the QR Code (without user_data, for backward compatibility) */\r\n        void (*display_func_with_cb)(esp_qrcode_handle_t qrcode, void *user_data);   /**< Function called for displaying the QR Code with user_data callback */\r\n    };                                                                        /**< Display function union for QR Code display */\r\n    int max_qrcode_version;                             /**< Max QR Code Version to be used. Range: 2 - 40 */\r\n    int qrcode_ecc_level;                               /**< Error Correction Level for QR Code */\r\n    void *user_data;                                    /**< User data */\r\n} esp_qrcode_config_t;\r\n\r\n/**\r\n  * @brief  Error Correction Level in a QR Code Symbol\r\n  */\r\nenum {\r\n    ESP_QRCODE_ECC_LOW,     /**< QR Code Error Tolerance of 7% */\r\n    ESP_QRCODE_ECC_MED,     /**< QR Code Error Tolerance of 15% */\r\n    ESP_QRCODE_ECC_QUART,   /**< QR Code Error Tolerance of 25% */\r\n    ESP_QRCODE_ECC_HIGH     /**< QR Code Error Tolerance of 30% */\r\n};\r\n\r\n/**\r\n  * @brief  Encodes the given string into a QR Code and calls the display function\r\n  *\r\n  * @attention 1. Can successfully encode a UTF-8 string of up to 2953 bytes or an alphanumeric\r\n  *               string of up to 4296 characters or any digit string of up to 7089 characters\r\n  *\r\n  * @param  cfg   Configuration used for QR Code encoding.\r\n  * @param  text  String to encode into a QR Code.\r\n  *\r\n  * @return\r\n  *    - ESP_OK: succeed\r\n  *    - ESP_FAIL: Failed to encode string into a QR Code\r\n  *    - ESP_ERR_NO_MEM: Failed to allocate buffer for given max_qrcode_version\r\n  */\r\nesp_err_t esp_qrcode_generate(esp_qrcode_config_t *cfg, const char *text);\r\n\r\n/**\r\n  * @brief  Displays QR Code on the console\r\n  *\r\n  * @param  qrcode  QR Code handle used by the display function.\r\n  */\r\nvoid esp_qrcode_print_console(esp_qrcode_handle_t qrcode);\r\n\r\n/**\r\n  * @brief  Returns the side length of the given QR Code\r\n  *\r\n  * @param  qrcode  QR Code handle used by the display function.\r\n  *\r\n  * @return\r\n  *    - val[21, 177]: Side length of QR Code\r\n  */\r\nint esp_qrcode_get_size(esp_qrcode_handle_t qrcode);\r\n\r\n/**\r\n  * @brief  Returns the Pixel value for the given coordinates\r\n  *         False indicates White and True indicates Black\r\n  *\r\n  * @attention 1. Coordinates for top left corner are (x=0, y=0)\r\n  * @attention 2. For out of bound coordinates false (White) is returned\r\n  *\r\n  * @param  qrcode  QR Code handle used by the display function.\r\n  * @param  x  X-Coordinate of QR Code module\r\n  * @param  y  Y-Coordinate of QR Code module\r\n  *\r\n  * @return\r\n  *    - true: (x, y) Pixel is Black\r\n  *    - false: (x, y) Pixel is White\r\n  */\r\nbool esp_qrcode_get_module(esp_qrcode_handle_t qrcode, int x, int y);\r\n\r\n#define ESP_QRCODE_CONFIG_DEFAULT() (esp_qrcode_config_t) { \\\r\n    .display_func = esp_qrcode_print_console, \\\r\n    .max_qrcode_version = 10, \\\r\n    .qrcode_ecc_level = ESP_QRCODE_ECC_LOW, \\\r\n    .user_data = NULL, \\\r\n}\r\n\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n"
  },
  {
    "path": "qrcode/qrcodegen.c",
    "content": "/*\r\n * QR Code generator library (C)\r\n *\r\n * Copyright (c) Project Nayuki. (MIT License)\r\n * https://www.nayuki.io/page/qr-code-generator-library\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n * this software and associated documentation files (the \"Software\"), to deal in\r\n * the Software without restriction, including without limitation the rights to\r\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n * the Software, and to permit persons to whom the Software is furnished to do so,\r\n * subject to the following conditions:\r\n * - The above copyright notice and this permission notice shall be included in\r\n *   all copies or substantial portions of the Software.\r\n * - The Software is provided \"as is\", without warranty of any kind, express or\r\n *   implied, including but not limited to the warranties of merchantability,\r\n *   fitness for a particular purpose and noninfringement. In no event shall the\r\n *   authors or copyright holders be liable for any claim, damages or other\r\n *   liability, whether in an action of contract, tort or otherwise, arising from,\r\n *   out of or in connection with the Software or the use or other dealings in the\r\n *   Software.\r\n */\r\n\r\n#include <assert.h>\r\n#include <limits.h>\r\n#include <stdlib.h>\r\n#include <string.h>\r\n#include \"qrcodegen.h\"\r\n\r\n#ifndef QRCODEGEN_TEST\r\n#define testable static  // Keep functions private\r\n#else\r\n#define testable  // Expose private functions\r\n#endif\r\n\r\n\r\n/*---- Forward declarations for private functions ----*/\r\n\r\n// Regarding all public and private functions defined in this source file:\r\n// - They require all pointer/array arguments to be not null unless the array length is zero.\r\n// - They only read input scalar/array arguments, write to output pointer/array\r\n//   arguments, and return scalar values; they are \"pure\" functions.\r\n// - They don't read mutable global variables or write to any global variables.\r\n// - They don't perform I/O, read the clock, print to console, etc.\r\n// - They allocate a small and constant amount of stack memory.\r\n// - They don't allocate or free any memory on the heap.\r\n// - They don't recurse or mutually recurse. All the code\r\n//   could be inlined into the top-level public functions.\r\n// - They run in at most quadratic time with respect to input arguments.\r\n//   Most functions run in linear time, and some in constant time.\r\n//   There are no unbounded loops or non-obvious termination conditions.\r\n// - They are completely thread-safe if the caller does not give the\r\n//   same writable buffer to concurrent calls to these functions.\r\n\r\ntestable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen);\r\n\r\ntestable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]);\r\ntestable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl);\r\ntestable int getNumRawDataModules(int ver);\r\n\r\ntestable void reedSolomonComputeDivisor(int degree, uint8_t result[]);\r\ntestable void reedSolomonComputeRemainder(const uint8_t data[], int dataLen,\r\n        const uint8_t generator[], int degree, uint8_t result[]);\r\ntestable uint8_t reedSolomonMultiply(uint8_t x, uint8_t y);\r\n\r\ntestable void initializeFunctionModules(int version, uint8_t qrcode[]);\r\nstatic void drawWhiteFunctionModules(uint8_t qrcode[], int version);\r\nstatic void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uint8_t qrcode[]);\r\ntestable int getAlignmentPatternPositions(int version, uint8_t result[7]);\r\nstatic void fillRectangle(int left, int top, int width, int height, uint8_t qrcode[]);\r\n\r\nstatic void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[]);\r\nstatic void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qrcodegen_Mask mask);\r\nstatic long getPenaltyScore(const uint8_t qrcode[]);\r\nstatic int finderPenaltyCountPatterns(const int runHistory[7], int qrsize);\r\nstatic int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, int runHistory[7], int qrsize);\r\nstatic void finderPenaltyAddHistory(int currentRunLength, int runHistory[7]);\r\n\r\ntestable bool getModule(const uint8_t qrcode[], int x, int y);\r\ntestable void setModule(uint8_t qrcode[], int x, int y, bool isBlack);\r\ntestable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isBlack);\r\nstatic bool getBit(int x, int i);\r\n\r\ntestable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars);\r\ntestable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version);\r\nstatic int numCharCountBits(enum qrcodegen_Mode mode, int version);\r\n\r\n\r\n\r\n/*---- Private tables of constants ----*/\r\n\r\n// The set of all legal characters in alphanumeric mode, where each character\r\n// value maps to the index in the string. For checking text and encoding segments.\r\nstatic const char *ALPHANUMERIC_CHARSET = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:\";\r\n\r\n// For generating error correction codes.\r\ntestable const int8_t ECC_CODEWORDS_PER_BLOCK[4][41] = {\r\n    // Version: (note that index 0 is for padding, and is set to an illegal value)\r\n    //0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40    Error correction level\r\n    {-1,  7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},  // Low\r\n    {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28},  // Medium\r\n    {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},  // Quartile\r\n    {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},  // High\r\n};\r\n\r\n#define qrcodegen_REED_SOLOMON_DEGREE_MAX 30  // Based on the table above\r\n\r\n// For generating error correction codes.\r\ntestable const int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41] = {\r\n    // Version: (note that index 0 is for padding, and is set to an illegal value)\r\n    //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40    Error correction level\r\n    {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4,  4,  4,  4,  4,  6,  6,  6,  6,  7,  8,  8,  9,  9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25},  // Low\r\n    {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5,  5,  8,  9,  9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49},  // Medium\r\n    {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8,  8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68},  // Quartile\r\n    {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81},  // High\r\n};\r\n\r\n// For automatic mask pattern selection.\r\nstatic const int PENALTY_N1 =  3;\r\nstatic const int PENALTY_N2 =  3;\r\nstatic const int PENALTY_N3 = 40;\r\nstatic const int PENALTY_N4 = 10;\r\n\r\n\r\n\r\n/*---- High-level QR Code encoding functions ----*/\r\n\r\n// Public function - see documentation comment in header file.\r\nbool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[],\r\n                          enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl)\r\n{\r\n\r\n    size_t textLen = strlen(text);\r\n    if (textLen == 0) {\r\n        return qrcodegen_encodeSegmentsAdvanced(NULL, 0, ecl, minVersion, maxVersion, mask, boostEcl, tempBuffer, qrcode);\r\n    }\r\n    size_t bufLen = (size_t)qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion);\r\n\r\n    struct qrcodegen_Segment seg;\r\n    if (qrcodegen_isNumeric(text)) {\r\n        if (qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, textLen) > bufLen) {\r\n            goto fail;\r\n        }\r\n        seg = qrcodegen_makeNumeric(text, tempBuffer);\r\n    } else if (qrcodegen_isAlphanumeric(text)) {\r\n        if (qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ALPHANUMERIC, textLen) > bufLen) {\r\n            goto fail;\r\n        }\r\n        seg = qrcodegen_makeAlphanumeric(text, tempBuffer);\r\n    } else {\r\n        if (textLen > bufLen) {\r\n            goto fail;\r\n        }\r\n        for (size_t i = 0; i < textLen; i++) {\r\n            tempBuffer[i] = (uint8_t)text[i];\r\n        }\r\n        seg.mode = qrcodegen_Mode_BYTE;\r\n        seg.bitLength = calcSegmentBitLength(seg.mode, textLen);\r\n        if (seg.bitLength == -1) {\r\n            goto fail;\r\n        }\r\n        seg.numChars = (int)textLen;\r\n        seg.data = tempBuffer;\r\n    }\r\n    return qrcodegen_encodeSegmentsAdvanced(&seg, 1, ecl, minVersion, maxVersion, mask, boostEcl, tempBuffer, qrcode);\r\n\r\nfail:\r\n    qrcode[0] = 0;  // Set size to invalid value for safety\r\n    return false;\r\n}\r\n\r\n\r\n// Public function - see documentation comment in header file.\r\nbool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[],\r\n                            enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl)\r\n{\r\n\r\n    struct qrcodegen_Segment seg;\r\n    seg.mode = qrcodegen_Mode_BYTE;\r\n    seg.bitLength = calcSegmentBitLength(seg.mode, dataLen);\r\n    if (seg.bitLength == -1) {\r\n        qrcode[0] = 0;  // Set size to invalid value for safety\r\n        return false;\r\n    }\r\n    seg.numChars = (int)dataLen;\r\n    seg.data = dataAndTemp;\r\n    return qrcodegen_encodeSegmentsAdvanced(&seg, 1, ecl, minVersion, maxVersion, mask, boostEcl, dataAndTemp, qrcode);\r\n}\r\n\r\n\r\n// Appends the given number of low-order bits of the given value to the given byte-based\r\n// bit buffer, increasing the bit length. Requires 0 <= numBits <= 16 and val < 2^numBits.\r\ntestable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen)\r\n{\r\n    assert(0 <= numBits && numBits <= 16 && (unsigned long)val >> numBits == 0);\r\n    for (int i = numBits - 1; i >= 0; i--, (*bitLen)++) {\r\n        buffer[*bitLen >> 3] |= ((val >> i) & 1) << (7 - (*bitLen & 7));\r\n    }\r\n}\r\n\r\n\r\n\r\n/*---- Low-level QR Code encoding functions ----*/\r\n\r\n// Public function - see documentation comment in header file.\r\nbool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len,\r\n                              enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[])\r\n{\r\n    return qrcodegen_encodeSegmentsAdvanced(segs, len, ecl,\r\n                                            qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true, tempBuffer, qrcode);\r\n}\r\n\r\n\r\n// Public function - see documentation comment in header file.\r\nbool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl,\r\n                                      int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl, uint8_t tempBuffer[], uint8_t qrcode[])\r\n{\r\n    assert(segs != NULL || len == 0);\r\n    assert(qrcodegen_VERSION_MIN <= minVersion && minVersion <= maxVersion && maxVersion <= qrcodegen_VERSION_MAX);\r\n    assert(0 <= (int)ecl && (int)ecl <= 3 && -1 <= (int)mask && (int)mask <= 7);\r\n\r\n    // Find the minimal version number to use\r\n    int version, dataUsedBits;\r\n    for (version = minVersion; ; version++) {\r\n        int dataCapacityBits = getNumDataCodewords(version, ecl) * 8;  // Number of data bits available\r\n        dataUsedBits = getTotalBits(segs, len, version);\r\n        if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits) {\r\n            break;    // This version number is found to be suitable\r\n        }\r\n        if (version >= maxVersion) {  // All versions in the range could not fit the given data\r\n            qrcode[0] = 0;  // Set size to invalid value for safety\r\n            return false;\r\n        }\r\n    }\r\n    assert(dataUsedBits != -1);\r\n\r\n    // Increase the error correction level while the data still fits in the current version number\r\n    for (int i = (int)qrcodegen_Ecc_MEDIUM; i <= (int)qrcodegen_Ecc_HIGH; i++) {  // From low to high\r\n        if (boostEcl && dataUsedBits <= getNumDataCodewords(version, (enum qrcodegen_Ecc)i) * 8) {\r\n            ecl = (enum qrcodegen_Ecc)i;\r\n        }\r\n    }\r\n\r\n    // Concatenate all segments to create the data bit string\r\n    memset(qrcode, 0, (size_t)qrcodegen_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0]));\r\n    int bitLen = 0;\r\n    for (size_t i = 0; i < len; i++) {\r\n        const struct qrcodegen_Segment *seg = &segs[i];\r\n        appendBitsToBuffer((unsigned int)seg->mode, 4, qrcode, &bitLen);\r\n        appendBitsToBuffer((unsigned int)seg->numChars, numCharCountBits(seg->mode, version), qrcode, &bitLen);\r\n        for (int j = 0; j < seg->bitLength; j++) {\r\n            int bit = (seg->data[j >> 3] >> (7 - (j & 7))) & 1;\r\n            appendBitsToBuffer((unsigned int)bit, 1, qrcode, &bitLen);\r\n        }\r\n    }\r\n    assert(bitLen == dataUsedBits);\r\n\r\n    // Add terminator and pad up to a byte if applicable\r\n    int dataCapacityBits = getNumDataCodewords(version, ecl) * 8;\r\n    assert(bitLen <= dataCapacityBits);\r\n    int terminatorBits = dataCapacityBits - bitLen;\r\n    if (terminatorBits > 4) {\r\n        terminatorBits = 4;\r\n    }\r\n    appendBitsToBuffer(0, terminatorBits, qrcode, &bitLen);\r\n    appendBitsToBuffer(0, (8 - bitLen % 8) % 8, qrcode, &bitLen);\r\n    assert(bitLen % 8 == 0);\r\n\r\n    // Pad with alternating bytes until data capacity is reached\r\n    for (uint8_t padByte = 0xEC; bitLen < dataCapacityBits; padByte ^= 0xEC ^ 0x11) {\r\n        appendBitsToBuffer(padByte, 8, qrcode, &bitLen);\r\n    }\r\n\r\n    // Draw function and data codeword modules\r\n    addEccAndInterleave(qrcode, version, ecl, tempBuffer);\r\n    initializeFunctionModules(version, qrcode);\r\n    drawCodewords(tempBuffer, getNumRawDataModules(version) / 8, qrcode);\r\n    drawWhiteFunctionModules(qrcode, version);\r\n    initializeFunctionModules(version, tempBuffer);\r\n\r\n    // Handle masking\r\n    if (mask == qrcodegen_Mask_AUTO) {  // Automatically choose best mask\r\n        long minPenalty = LONG_MAX;\r\n        for (int i = 0; i < 8; i++) {\r\n            enum qrcodegen_Mask msk = (enum qrcodegen_Mask)i;\r\n            applyMask(tempBuffer, qrcode, msk);\r\n            drawFormatBits(ecl, msk, qrcode);\r\n            long penalty = getPenaltyScore(qrcode);\r\n            if (penalty < minPenalty) {\r\n                mask = msk;\r\n                minPenalty = penalty;\r\n            }\r\n            applyMask(tempBuffer, qrcode, msk);  // Undoes the mask due to XOR\r\n        }\r\n    }\r\n    assert(0 <= (int)mask && (int)mask <= 7);\r\n    applyMask(tempBuffer, qrcode, mask);\r\n    drawFormatBits(ecl, mask, qrcode);\r\n    return true;\r\n}\r\n\r\n\r\n\r\n/*---- Error correction code generation functions ----*/\r\n\r\n// Appends error correction bytes to each block of the given data array, then interleaves\r\n// bytes from the blocks and stores them in the result array. data[0 : dataLen] contains\r\n// the input data. data[dataLen : rawCodewords] is used as a temporary work area and will\r\n// be clobbered by this function. The final answer is stored in result[0 : rawCodewords].\r\ntestable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[])\r\n{\r\n    // Calculate parameter numbers\r\n    assert(0 <= (int)ecl && (int)ecl < 4 && qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX);\r\n    int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[(int)ecl][version];\r\n    int blockEccLen = ECC_CODEWORDS_PER_BLOCK  [(int)ecl][version];\r\n    int rawCodewords = getNumRawDataModules(version) / 8;\r\n    int dataLen = getNumDataCodewords(version, ecl);\r\n    int numShortBlocks = numBlocks - rawCodewords % numBlocks;\r\n    int shortBlockDataLen = rawCodewords / numBlocks - blockEccLen;\r\n\r\n    // Split data into blocks, calculate ECC, and interleave\r\n    // (not concatenate) the bytes into a single sequence\r\n    uint8_t rsdiv[qrcodegen_REED_SOLOMON_DEGREE_MAX];\r\n    reedSolomonComputeDivisor(blockEccLen, rsdiv);\r\n    const uint8_t *dat = data;\r\n    for (int i = 0; i < numBlocks; i++) {\r\n        int datLen = shortBlockDataLen + (i < numShortBlocks ? 0 : 1);\r\n        uint8_t *ecc = &data[dataLen];  // Temporary storage\r\n        reedSolomonComputeRemainder(dat, datLen, rsdiv, blockEccLen, ecc);\r\n        for (int j = 0, k = i; j < datLen; j++, k += numBlocks) {  // Copy data\r\n            if (j == shortBlockDataLen) {\r\n                k -= numShortBlocks;\r\n            }\r\n            result[k] = dat[j];\r\n        }\r\n        for (int j = 0, k = dataLen + i; j < blockEccLen; j++, k += numBlocks) { // Copy ECC\r\n            result[k] = ecc[j];\r\n        }\r\n        dat += datLen;\r\n    }\r\n}\r\n\r\n\r\n// Returns the number of 8-bit codewords that can be used for storing data (not ECC),\r\n// for the given version number and error correction level. The result is in the range [9, 2956].\r\ntestable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl)\r\n{\r\n    int v = version, e = (int)ecl;\r\n    assert(0 <= e && e < 4);\r\n    return getNumRawDataModules(v) / 8\r\n           - ECC_CODEWORDS_PER_BLOCK    [e][v]\r\n           * NUM_ERROR_CORRECTION_BLOCKS[e][v];\r\n}\r\n\r\n\r\n// Returns the number of data bits that can be stored in a QR Code of the given version number, after\r\n// all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.\r\n// The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.\r\ntestable int getNumRawDataModules(int ver)\r\n{\r\n    assert(qrcodegen_VERSION_MIN <= ver && ver <= qrcodegen_VERSION_MAX);\r\n    int result = (16 * ver + 128) * ver + 64;\r\n    if (ver >= 2) {\r\n        int numAlign = ver / 7 + 2;\r\n        result -= (25 * numAlign - 10) * numAlign - 55;\r\n        if (ver >= 7) {\r\n            result -= 36;\r\n        }\r\n    }\r\n    assert(208 <= result && result <= 29648);\r\n    return result;\r\n}\r\n\r\n\r\n\r\n/*---- Reed-Solomon ECC generator functions ----*/\r\n\r\n// Computes a Reed-Solomon ECC generator polynomial for the given degree, storing in result[0 : degree].\r\n// This could be implemented as a lookup table over all possible parameter values, instead of as an algorithm.\r\ntestable void reedSolomonComputeDivisor(int degree, uint8_t result[])\r\n{\r\n    assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX);\r\n    // Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1.\r\n    // For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}.\r\n    memset(result, 0, (size_t)degree * sizeof(result[0]));\r\n    result[degree - 1] = 1;  // Start off with the monomial x^0\r\n\r\n    // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),\r\n    // drop the highest monomial term which is always 1x^degree.\r\n    // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).\r\n    uint8_t root = 1;\r\n    for (int i = 0; i < degree; i++) {\r\n        // Multiply the current product by (x - r^i)\r\n        for (int j = 0; j < degree; j++) {\r\n            result[j] = reedSolomonMultiply(result[j], root);\r\n            if (j + 1 < degree) {\r\n                result[j] ^= result[j + 1];\r\n            }\r\n        }\r\n        root = reedSolomonMultiply(root, 0x02);\r\n    }\r\n}\r\n\r\n\r\n// Computes the Reed-Solomon error correction codeword for the given data and divisor polynomials.\r\n// The remainder when data[0 : dataLen] is divided by divisor[0 : degree] is stored in result[0 : degree].\r\n// All polynomials are in big endian, and the generator has an implicit leading 1 term.\r\ntestable void reedSolomonComputeRemainder(const uint8_t data[], int dataLen,\r\n        const uint8_t generator[], int degree, uint8_t result[])\r\n{\r\n    assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX);\r\n    memset(result, 0, (size_t)degree * sizeof(result[0]));\r\n    for (int i = 0; i < dataLen; i++) {  // Polynomial division\r\n        uint8_t factor = data[i] ^ result[0];\r\n        memmove(&result[0], &result[1], (size_t)(degree - 1) * sizeof(result[0]));\r\n        result[degree - 1] = 0;\r\n        for (int j = 0; j < degree; j++) {\r\n            result[j] ^= reedSolomonMultiply(generator[j], factor);\r\n        }\r\n    }\r\n}\r\n\r\n#undef qrcodegen_REED_SOLOMON_DEGREE_MAX\r\n\r\n\r\n// Returns the product of the two given field elements modulo GF(2^8/0x11D).\r\n// All inputs are valid. This could be implemented as a 256*256 lookup table.\r\ntestable uint8_t reedSolomonMultiply(uint8_t x, uint8_t y)\r\n{\r\n    // Russian peasant multiplication\r\n    uint8_t z = 0;\r\n    for (int i = 7; i >= 0; i--) {\r\n        z = (uint8_t)((z << 1) ^ ((z >> 7) * 0x11D));\r\n        z ^= ((y >> i) & 1) * x;\r\n    }\r\n    return z;\r\n}\r\n\r\n\r\n\r\n/*---- Drawing function modules ----*/\r\n\r\n// Clears the given QR Code grid with white modules for the given\r\n// version's size, then marks every function module as black.\r\ntestable void initializeFunctionModules(int version, uint8_t qrcode[])\r\n{\r\n    // Initialize QR Code\r\n    int qrsize = version * 4 + 17;\r\n    memset(qrcode, 0, (size_t)((qrsize * qrsize + 7) / 8 + 1) * sizeof(qrcode[0]));\r\n    qrcode[0] = (uint8_t)qrsize;\r\n\r\n    // Fill horizontal and vertical timing patterns\r\n    fillRectangle(6, 0, 1, qrsize, qrcode);\r\n    fillRectangle(0, 6, qrsize, 1, qrcode);\r\n\r\n    // Fill 3 finder patterns (all corners except bottom right) and format bits\r\n    fillRectangle(0, 0, 9, 9, qrcode);\r\n    fillRectangle(qrsize - 8, 0, 8, 9, qrcode);\r\n    fillRectangle(0, qrsize - 8, 9, 8, qrcode);\r\n\r\n    // Fill numerous alignment patterns\r\n    uint8_t alignPatPos[7];\r\n    int numAlign = getAlignmentPatternPositions(version, alignPatPos);\r\n    for (int i = 0; i < numAlign; i++) {\r\n        for (int j = 0; j < numAlign; j++) {\r\n            // Don't draw on the three finder corners\r\n            if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0))) {\r\n                fillRectangle(alignPatPos[i] - 2, alignPatPos[j] - 2, 5, 5, qrcode);\r\n            }\r\n        }\r\n    }\r\n\r\n    // Fill version blocks\r\n    if (version >= 7) {\r\n        fillRectangle(qrsize - 11, 0, 3, 6, qrcode);\r\n        fillRectangle(0, qrsize - 11, 6, 3, qrcode);\r\n    }\r\n}\r\n\r\n\r\n// Draws white function modules and possibly some black modules onto the given QR Code, without changing\r\n// non-function modules. This does not draw the format bits. This requires all function modules to be previously\r\n// marked black (namely by initializeFunctionModules()), because this may skip redrawing black function modules.\r\nstatic void drawWhiteFunctionModules(uint8_t qrcode[], int version)\r\n{\r\n    // Draw horizontal and vertical timing patterns\r\n    int qrsize = qrcodegen_getSize(qrcode);\r\n    for (int i = 7; i < qrsize - 7; i += 2) {\r\n        setModule(qrcode, 6, i, false);\r\n        setModule(qrcode, i, 6, false);\r\n    }\r\n\r\n    // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)\r\n    for (int dy = -4; dy <= 4; dy++) {\r\n        for (int dx = -4; dx <= 4; dx++) {\r\n            int dist = abs(dx);\r\n            if (abs(dy) > dist) {\r\n                dist = abs(dy);\r\n            }\r\n            if (dist == 2 || dist == 4) {\r\n                setModuleBounded(qrcode, 3 + dx, 3 + dy, false);\r\n                setModuleBounded(qrcode, qrsize - 4 + dx, 3 + dy, false);\r\n                setModuleBounded(qrcode, 3 + dx, qrsize - 4 + dy, false);\r\n            }\r\n        }\r\n    }\r\n\r\n    // Draw numerous alignment patterns\r\n    uint8_t alignPatPos[7];\r\n    int numAlign = getAlignmentPatternPositions(version, alignPatPos);\r\n    for (int i = 0; i < numAlign; i++) {\r\n        for (int j = 0; j < numAlign; j++) {\r\n            if ((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0)) {\r\n                continue;    // Don't draw on the three finder corners\r\n            }\r\n            for (int dy = -1; dy <= 1; dy++) {\r\n                for (int dx = -1; dx <= 1; dx++) {\r\n                    setModule(qrcode, alignPatPos[i] + dx, alignPatPos[j] + dy, dx == 0 && dy == 0);\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    // Draw version blocks\r\n    if (version >= 7) {\r\n        // Calculate error correction code and pack bits\r\n        int rem = version;  // version is uint6, in the range [7, 40]\r\n        for (int i = 0; i < 12; i++) {\r\n            rem = (rem << 1) ^ ((rem >> 11) * 0x1F25);\r\n        }\r\n        long bits = (long)version << 12 | rem;  // uint18\r\n        assert(bits >> 18 == 0);\r\n\r\n        // Draw two copies\r\n        for (int i = 0; i < 6; i++) {\r\n            for (int j = 0; j < 3; j++) {\r\n                int k = qrsize - 11 + j;\r\n                setModule(qrcode, k, i, (bits & 1) != 0);\r\n                setModule(qrcode, i, k, (bits & 1) != 0);\r\n                bits >>= 1;\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\n\r\n// Draws two copies of the format bits (with its own error correction code) based\r\n// on the given mask and error correction level. This always draws all modules of\r\n// the format bits, unlike drawWhiteFunctionModules() which might skip black modules.\r\nstatic void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uint8_t qrcode[])\r\n{\r\n    // Calculate error correction code and pack bits\r\n    assert(0 <= (int)mask && (int)mask <= 7);\r\n    static const int table[] = {1, 0, 3, 2};\r\n    int data = table[(int)ecl] << 3 | (int)mask;  // errCorrLvl is uint2, mask is uint3\r\n    int rem = data;\r\n    for (int i = 0; i < 10; i++) {\r\n        rem = (rem << 1) ^ ((rem >> 9) * 0x537);\r\n    }\r\n    int bits = (data << 10 | rem) ^ 0x5412;  // uint15\r\n    assert(bits >> 15 == 0);\r\n\r\n    // Draw first copy\r\n    for (int i = 0; i <= 5; i++) {\r\n        setModule(qrcode, 8, i, getBit(bits, i));\r\n    }\r\n    setModule(qrcode, 8, 7, getBit(bits, 6));\r\n    setModule(qrcode, 8, 8, getBit(bits, 7));\r\n    setModule(qrcode, 7, 8, getBit(bits, 8));\r\n    for (int i = 9; i < 15; i++) {\r\n        setModule(qrcode, 14 - i, 8, getBit(bits, i));\r\n    }\r\n\r\n    // Draw second copy\r\n    int qrsize = qrcodegen_getSize(qrcode);\r\n    for (int i = 0; i < 8; i++) {\r\n        setModule(qrcode, qrsize - 1 - i, 8, getBit(bits, i));\r\n    }\r\n    for (int i = 8; i < 15; i++) {\r\n        setModule(qrcode, 8, qrsize - 15 + i, getBit(bits, i));\r\n    }\r\n    setModule(qrcode, 8, qrsize - 8, true);  // Always black\r\n}\r\n\r\n\r\n// Calculates and stores an ascending list of positions of alignment patterns\r\n// for this version number, returning the length of the list (in the range [0,7]).\r\n// Each position is in the range [0,177), and are used on both the x and y axes.\r\n// This could be implemented as lookup table of 40 variable-length lists of unsigned bytes.\r\ntestable int getAlignmentPatternPositions(int version, uint8_t result[7])\r\n{\r\n    if (version == 1) {\r\n        return 0;\r\n    }\r\n    int numAlign = version / 7 + 2;\r\n    int step = (version == 32) ? 26 :\r\n               (version * 4 + numAlign * 2 + 1) / (numAlign * 2 - 2) * 2;\r\n    for (int i = numAlign - 1, pos = version * 4 + 10; i >= 1; i--, pos -= step) {\r\n        result[i] = (uint8_t)pos;\r\n    }\r\n    result[0] = 6;\r\n    return numAlign;\r\n}\r\n\r\n\r\n// Sets every pixel in the range [left : left + width] * [top : top + height] to black.\r\nstatic void fillRectangle(int left, int top, int width, int height, uint8_t qrcode[])\r\n{\r\n    for (int dy = 0; dy < height; dy++) {\r\n        for (int dx = 0; dx < width; dx++) {\r\n            setModule(qrcode, left + dx, top + dy, true);\r\n        }\r\n    }\r\n}\r\n\r\n\r\n\r\n/*---- Drawing data modules and masking ----*/\r\n\r\n// Draws the raw codewords (including data and ECC) onto the given QR Code. This requires the initial state of\r\n// the QR Code to be black at function modules and white at codeword modules (including unused remainder bits).\r\nstatic void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[])\r\n{\r\n    int qrsize = qrcodegen_getSize(qrcode);\r\n    int i = 0;  // Bit index into the data\r\n    // Do the funny zigzag scan\r\n    for (int right = qrsize - 1; right >= 1; right -= 2) {  // Index of right column in each column pair\r\n        if (right == 6) {\r\n            right = 5;\r\n        }\r\n        for (int vert = 0; vert < qrsize; vert++) {  // Vertical counter\r\n            for (int j = 0; j < 2; j++) {\r\n                int x = right - j;  // Actual x coordinate\r\n                bool upward = ((right + 1) & 2) == 0;\r\n                int y = upward ? qrsize - 1 - vert : vert;  // Actual y coordinate\r\n                if (!getModule(qrcode, x, y) && i < dataLen * 8) {\r\n                    bool black = getBit(data[i >> 3], 7 - (i & 7));\r\n                    setModule(qrcode, x, y, black);\r\n                    i++;\r\n                }\r\n                // If this QR Code has any remainder bits (0 to 7), they were assigned as\r\n                // 0/false/white by the constructor and are left unchanged by this method\r\n            }\r\n        }\r\n    }\r\n    assert(i == dataLen * 8);\r\n}\r\n\r\n\r\n// XORs the codeword modules in this QR Code with the given mask pattern.\r\n// The function modules must be marked and the codeword bits must be drawn\r\n// before masking. Due to the arithmetic of XOR, calling applyMask() with\r\n// the same mask value a second time will undo the mask. A final well-formed\r\n// QR Code needs exactly one (not zero, two, etc.) mask applied.\r\nstatic void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qrcodegen_Mask mask)\r\n{\r\n    assert(0 <= (int)mask && (int)mask <= 7);  // Disallows qrcodegen_Mask_AUTO\r\n    int qrsize = qrcodegen_getSize(qrcode);\r\n    for (int y = 0; y < qrsize; y++) {\r\n        for (int x = 0; x < qrsize; x++) {\r\n            if (getModule(functionModules, x, y)) {\r\n                continue;\r\n            }\r\n            bool invert;\r\n            switch ((int)mask) {\r\n            case 0:  invert = (x + y) % 2 == 0;                    break;\r\n            case 1:  invert = y % 2 == 0;                          break;\r\n            case 2:  invert = x % 3 == 0;                          break;\r\n            case 3:  invert = (x + y) % 3 == 0;                    break;\r\n            case 4:  invert = (x / 3 + y / 2) % 2 == 0;            break;\r\n            case 5:  invert = x * y % 2 + x * y % 3 == 0;          break;\r\n            case 6:  invert = (x * y % 2 + x * y % 3) % 2 == 0;    break;\r\n            case 7:  invert = ((x + y) % 2 + x * y % 3) % 2 == 0;  break;\r\n            default:  assert(false);  return;\r\n            }\r\n            bool val = getModule(qrcode, x, y);\r\n            setModule(qrcode, x, y, val ^ invert);\r\n        }\r\n    }\r\n}\r\n\r\n\r\n// Calculates and returns the penalty score based on state of the given QR Code's current modules.\r\n// This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.\r\nstatic long getPenaltyScore(const uint8_t qrcode[])\r\n{\r\n    int qrsize = qrcodegen_getSize(qrcode);\r\n    long result = 0;\r\n\r\n    // Adjacent modules in row having same color, and finder-like patterns\r\n    for (int y = 0; y < qrsize; y++) {\r\n        bool runColor = false;\r\n        int runX = 0;\r\n        int runHistory[7] = {0};\r\n        int padRun = qrsize;  // Add white border to initial run\r\n        for (int x = 0; x < qrsize; x++) {\r\n            if (getModule(qrcode, x, y) == runColor) {\r\n                runX++;\r\n                if (runX == 5) {\r\n                    result += PENALTY_N1;\r\n                } else if (runX > 5) {\r\n                    result++;\r\n                }\r\n            } else {\r\n                finderPenaltyAddHistory(runX + padRun, runHistory);\r\n                padRun = 0;\r\n                if (!runColor) {\r\n                    result += finderPenaltyCountPatterns(runHistory, qrsize) * PENALTY_N3;\r\n                }\r\n                runColor = getModule(qrcode, x, y);\r\n                runX = 1;\r\n            }\r\n        }\r\n        result += finderPenaltyTerminateAndCount(runColor, runX + padRun, runHistory, qrsize) * PENALTY_N3;\r\n    }\r\n    // Adjacent modules in column having same color, and finder-like patterns\r\n    for (int x = 0; x < qrsize; x++) {\r\n        bool runColor = false;\r\n        int runY = 0;\r\n        int runHistory[7] = {0};\r\n        int padRun = qrsize;  // Add white border to initial run\r\n        for (int y = 0; y < qrsize; y++) {\r\n            if (getModule(qrcode, x, y) == runColor) {\r\n                runY++;\r\n                if (runY == 5) {\r\n                    result += PENALTY_N1;\r\n                } else if (runY > 5) {\r\n                    result++;\r\n                }\r\n            } else {\r\n                finderPenaltyAddHistory(runY + padRun, runHistory);\r\n                padRun = 0;\r\n                if (!runColor) {\r\n                    result += finderPenaltyCountPatterns(runHistory, qrsize) * PENALTY_N3;\r\n                }\r\n                runColor = getModule(qrcode, x, y);\r\n                runY = 1;\r\n            }\r\n        }\r\n        result += finderPenaltyTerminateAndCount(runColor, runY + padRun, runHistory, qrsize) * PENALTY_N3;\r\n    }\r\n\r\n    // 2*2 blocks of modules having same color\r\n    for (int y = 0; y < qrsize - 1; y++) {\r\n        for (int x = 0; x < qrsize - 1; x++) {\r\n            bool  color = getModule(qrcode, x, y);\r\n            if (  color == getModule(qrcode, x + 1, y) &&\r\n                    color == getModule(qrcode, x, y + 1) &&\r\n                    color == getModule(qrcode, x + 1, y + 1)) {\r\n                result += PENALTY_N2;\r\n            }\r\n        }\r\n    }\r\n\r\n    // Balance of black and white modules\r\n    int black = 0;\r\n    for (int y = 0; y < qrsize; y++) {\r\n        for (int x = 0; x < qrsize; x++) {\r\n            if (getModule(qrcode, x, y)) {\r\n                black++;\r\n            }\r\n        }\r\n    }\r\n    int total = qrsize * qrsize;  // Note that size is odd, so black/total != 1/2\r\n    // Compute the smallest integer k >= 0 such that (45-5k)% <= black/total <= (55+5k)%\r\n    int k = (int)((labs(black * 20L - total * 10L) + total - 1) / total) - 1;\r\n    result += k * PENALTY_N4;\r\n    return result;\r\n}\r\n\r\n\r\n// Can only be called immediately after a white run is added, and\r\n// returns either 0, 1, or 2. A helper function for getPenaltyScore().\r\nstatic int finderPenaltyCountPatterns(const int runHistory[7], int qrsize)\r\n{\r\n    int n = runHistory[1];\r\n    assert(n <= qrsize * 3);\r\n    bool core = n > 0 && runHistory[2] == n && runHistory[3] == n * 3 && runHistory[4] == n && runHistory[5] == n;\r\n    // The maximum QR Code size is 177, hence the black run length n <= 177.\r\n    // Arithmetic is promoted to int, so n*4 will not overflow.\r\n    return (core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0)\r\n           + (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0);\r\n}\r\n\r\n\r\n// Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore().\r\nstatic int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, int runHistory[7], int qrsize)\r\n{\r\n    if (currentRunColor) {  // Terminate black run\r\n        finderPenaltyAddHistory(currentRunLength, runHistory);\r\n        currentRunLength = 0;\r\n    }\r\n    currentRunLength += qrsize;  // Add white border to final run\r\n    finderPenaltyAddHistory(currentRunLength, runHistory);\r\n    return finderPenaltyCountPatterns(runHistory, qrsize);\r\n}\r\n\r\n\r\n// Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore().\r\nstatic void finderPenaltyAddHistory(int currentRunLength, int runHistory[7])\r\n{\r\n    memmove(&runHistory[1], &runHistory[0], 6 * sizeof(runHistory[0]));\r\n    runHistory[0] = currentRunLength;\r\n}\r\n\r\n\r\n\r\n/*---- Basic QR Code information ----*/\r\n\r\n// Public function - see documentation comment in header file.\r\nint qrcodegen_getSize(const uint8_t qrcode[])\r\n{\r\n    assert(qrcode != NULL);\r\n    int result = qrcode[0];\r\n    assert((qrcodegen_VERSION_MIN * 4 + 17) <= result\r\n           && result <= (qrcodegen_VERSION_MAX * 4 + 17));\r\n    return result;\r\n}\r\n\r\n\r\n// Public function - see documentation comment in header file.\r\nbool qrcodegen_getModule(const uint8_t qrcode[], int x, int y)\r\n{\r\n    assert(qrcode != NULL);\r\n    int qrsize = qrcode[0];\r\n    return (0 <= x && x < qrsize && 0 <= y && y < qrsize) && getModule(qrcode, x, y);\r\n}\r\n\r\n\r\n// Gets the module at the given coordinates, which must be in bounds.\r\ntestable bool getModule(const uint8_t qrcode[], int x, int y)\r\n{\r\n    int qrsize = qrcode[0];\r\n    assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize);\r\n    int index = y * qrsize + x;\r\n    return getBit(qrcode[(index >> 3) + 1], index & 7);\r\n}\r\n\r\n\r\n// Sets the module at the given coordinates, which must be in bounds.\r\ntestable void setModule(uint8_t qrcode[], int x, int y, bool isBlack)\r\n{\r\n    int qrsize = qrcode[0];\r\n    assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize);\r\n    int index = y * qrsize + x;\r\n    int bitIndex = index & 7;\r\n    int byteIndex = (index >> 3) + 1;\r\n    if (isBlack) {\r\n        qrcode[byteIndex] |= 1 << bitIndex;\r\n    } else {\r\n        qrcode[byteIndex] &= (1 << bitIndex) ^ 0xFF;\r\n    }\r\n}\r\n\r\n\r\n// Sets the module at the given coordinates, doing nothing if out of bounds.\r\ntestable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isBlack)\r\n{\r\n    int qrsize = qrcode[0];\r\n    if (0 <= x && x < qrsize && 0 <= y && y < qrsize) {\r\n        setModule(qrcode, x, y, isBlack);\r\n    }\r\n}\r\n\r\n\r\n// Returns true iff the i'th bit of x is set to 1. Requires x >= 0 and 0 <= i <= 14.\r\nstatic bool getBit(int x, int i)\r\n{\r\n    return ((x >> i) & 1) != 0;\r\n}\r\n\r\n\r\n\r\n/*---- Segment handling ----*/\r\n\r\n// Public function - see documentation comment in header file.\r\nbool qrcodegen_isAlphanumeric(const char *text)\r\n{\r\n    assert(text != NULL);\r\n    for (; *text != '\\0'; text++) {\r\n        if (strchr(ALPHANUMERIC_CHARSET, *text) == NULL) {\r\n            return false;\r\n        }\r\n    }\r\n    return true;\r\n}\r\n\r\n\r\n// Public function - see documentation comment in header file.\r\nbool qrcodegen_isNumeric(const char *text)\r\n{\r\n    assert(text != NULL);\r\n    for (; *text != '\\0'; text++) {\r\n        if (*text < '0' || *text > '9') {\r\n            return false;\r\n        }\r\n    }\r\n    return true;\r\n}\r\n\r\n\r\n// Public function - see documentation comment in header file.\r\nsize_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars)\r\n{\r\n    int temp = calcSegmentBitLength(mode, numChars);\r\n    if (temp == -1) {\r\n        return SIZE_MAX;\r\n    }\r\n    assert(0 <= temp && temp <= INT16_MAX);\r\n    return ((size_t)temp + 7) / 8;\r\n}\r\n\r\n\r\n// Returns the number of data bits needed to represent a segment\r\n// containing the given number of characters using the given mode. Notes:\r\n// - Returns -1 on failure, i.e. numChars > INT16_MAX or\r\n//   the number of needed bits exceeds INT16_MAX (i.e. 32767).\r\n// - Otherwise, all valid results are in the range [0, INT16_MAX].\r\n// - For byte mode, numChars measures the number of bytes, not Unicode code points.\r\n// - For ECI mode, numChars must be 0, and the worst-case number of bits is returned.\r\n//   An actual ECI segment can have shorter data. For non-ECI modes, the result is exact.\r\ntestable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars)\r\n{\r\n    // All calculations are designed to avoid overflow on all platforms\r\n    if (numChars > (unsigned int)INT16_MAX) {\r\n        return -1;\r\n    }\r\n    long result = (long)numChars;\r\n    if (mode == qrcodegen_Mode_NUMERIC) {\r\n        result = (result * 10 + 2) / 3;    // ceil(10/3 * n)\r\n    } else if (mode == qrcodegen_Mode_ALPHANUMERIC) {\r\n        result = (result * 11 + 1) / 2;    // ceil(11/2 * n)\r\n    } else if (mode == qrcodegen_Mode_BYTE) {\r\n        result *= 8;\r\n    } else if (mode == qrcodegen_Mode_KANJI) {\r\n        result *= 13;\r\n    } else if (mode == qrcodegen_Mode_ECI && numChars == 0) {\r\n        result = 3 * 8;\r\n    } else { // Invalid argument\r\n        assert(false);\r\n        return -1;\r\n    }\r\n    assert(result >= 0);\r\n    if (result > INT16_MAX) {\r\n        return -1;\r\n    }\r\n    return (int)result;\r\n}\r\n\r\n\r\n// Public function - see documentation comment in header file.\r\nstruct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[])\r\n{\r\n    assert(data != NULL || len == 0);\r\n    struct qrcodegen_Segment result;\r\n    result.mode = qrcodegen_Mode_BYTE;\r\n    result.bitLength = calcSegmentBitLength(result.mode, len);\r\n    assert(result.bitLength != -1);\r\n    result.numChars = (int)len;\r\n    if (len > 0) {\r\n        memcpy(buf, data, len * sizeof(buf[0]));\r\n    }\r\n    result.data = buf;\r\n    return result;\r\n}\r\n\r\n\r\n// Public function - see documentation comment in header file.\r\nstruct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[])\r\n{\r\n    assert(digits != NULL);\r\n    struct qrcodegen_Segment result;\r\n    size_t len = strlen(digits);\r\n    result.mode = qrcodegen_Mode_NUMERIC;\r\n    int bitLen = calcSegmentBitLength(result.mode, len);\r\n    assert(bitLen != -1);\r\n    result.numChars = (int)len;\r\n    if (bitLen > 0) {\r\n        memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0]));\r\n    }\r\n    result.bitLength = 0;\r\n\r\n    unsigned int accumData = 0;\r\n    int accumCount = 0;\r\n    for (; *digits != '\\0'; digits++) {\r\n        char c = *digits;\r\n        assert('0' <= c && c <= '9');\r\n        accumData = accumData * 10 + (unsigned int)(c - '0');\r\n        accumCount++;\r\n        if (accumCount == 3) {\r\n            appendBitsToBuffer(accumData, 10, buf, &result.bitLength);\r\n            accumData = 0;\r\n            accumCount = 0;\r\n        }\r\n    }\r\n    if (accumCount > 0) { // 1 or 2 digits remaining\r\n        appendBitsToBuffer(accumData, accumCount * 3 + 1, buf, &result.bitLength);\r\n    }\r\n    assert(result.bitLength == bitLen);\r\n    result.data = buf;\r\n    return result;\r\n}\r\n\r\n\r\n// Public function - see documentation comment in header file.\r\nstruct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[])\r\n{\r\n    assert(text != NULL);\r\n    struct qrcodegen_Segment result;\r\n    size_t len = strlen(text);\r\n    result.mode = qrcodegen_Mode_ALPHANUMERIC;\r\n    int bitLen = calcSegmentBitLength(result.mode, len);\r\n    assert(bitLen != -1);\r\n    result.numChars = (int)len;\r\n    if (bitLen > 0) {\r\n        memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0]));\r\n    }\r\n    result.bitLength = 0;\r\n\r\n    unsigned int accumData = 0;\r\n    int accumCount = 0;\r\n    for (; *text != '\\0'; text++) {\r\n        const char *temp = strchr(ALPHANUMERIC_CHARSET, *text);\r\n        assert(temp != NULL);\r\n        accumData = accumData * 45 + (unsigned int)(temp - ALPHANUMERIC_CHARSET);\r\n        accumCount++;\r\n        if (accumCount == 2) {\r\n            appendBitsToBuffer(accumData, 11, buf, &result.bitLength);\r\n            accumData = 0;\r\n            accumCount = 0;\r\n        }\r\n    }\r\n    if (accumCount > 0) { // 1 character remaining\r\n        appendBitsToBuffer(accumData, 6, buf, &result.bitLength);\r\n    }\r\n    assert(result.bitLength == bitLen);\r\n    result.data = buf;\r\n    return result;\r\n}\r\n\r\n\r\n// Public function - see documentation comment in header file.\r\nstruct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[])\r\n{\r\n    struct qrcodegen_Segment result;\r\n    result.mode = qrcodegen_Mode_ECI;\r\n    result.numChars = 0;\r\n    result.bitLength = 0;\r\n    if (assignVal < 0) {\r\n        assert(false);\r\n    } else if (assignVal < (1 << 7)) {\r\n        memset(buf, 0, 1 * sizeof(buf[0]));\r\n        appendBitsToBuffer((unsigned int)assignVal, 8, buf, &result.bitLength);\r\n    } else if (assignVal < (1 << 14)) {\r\n        memset(buf, 0, 2 * sizeof(buf[0]));\r\n        appendBitsToBuffer(2, 2, buf, &result.bitLength);\r\n        appendBitsToBuffer((unsigned int)assignVal, 14, buf, &result.bitLength);\r\n    } else if (assignVal < 1000000L) {\r\n        memset(buf, 0, 3 * sizeof(buf[0]));\r\n        appendBitsToBuffer(6, 3, buf, &result.bitLength);\r\n        appendBitsToBuffer((unsigned int)(assignVal >> 10), 11, buf, &result.bitLength);\r\n        appendBitsToBuffer((unsigned int)(assignVal & 0x3FF), 10, buf, &result.bitLength);\r\n    } else {\r\n        assert(false);\r\n    }\r\n    result.data = buf;\r\n    return result;\r\n}\r\n\r\n\r\n// Calculates the number of bits needed to encode the given segments at the given version.\r\n// Returns a non-negative number if successful. Otherwise returns -1 if a segment has too\r\n// many characters to fit its length field, or the total bits exceeds INT16_MAX.\r\ntestable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version)\r\n{\r\n    assert(segs != NULL || len == 0);\r\n    long result = 0;\r\n    for (size_t i = 0; i < len; i++) {\r\n        int numChars  = segs[i].numChars;\r\n        int bitLength = segs[i].bitLength;\r\n        assert(0 <= numChars  && numChars  <= INT16_MAX);\r\n        assert(0 <= bitLength && bitLength <= INT16_MAX);\r\n        int ccbits = numCharCountBits(segs[i].mode, version);\r\n        assert(0 <= ccbits && ccbits <= 16);\r\n        if (numChars >= (1L << ccbits)) {\r\n            return -1;    // The segment's length doesn't fit the field's bit width\r\n        }\r\n        result += 4L + ccbits + bitLength;\r\n        if (result > INT16_MAX) {\r\n            return -1;    // The sum might overflow an int type\r\n        }\r\n    }\r\n    assert(0 <= result && result <= INT16_MAX);\r\n    return (int)result;\r\n}\r\n\r\n\r\n// Returns the bit width of the character count field for a segment in the given mode\r\n// in a QR Code at the given version number. The result is in the range [0, 16].\r\nstatic int numCharCountBits(enum qrcodegen_Mode mode, int version)\r\n{\r\n    assert(qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX);\r\n    int i = (version + 7) / 17;\r\n    switch (mode) {\r\n    case qrcodegen_Mode_NUMERIC     : {\r\n        static const int temp[] = {10, 12, 14};\r\n        return temp[i];\r\n    }\r\n    case qrcodegen_Mode_ALPHANUMERIC: {\r\n        static const int temp[] = { 9, 11, 13};\r\n        return temp[i];\r\n    }\r\n    case qrcodegen_Mode_BYTE        : {\r\n        static const int temp[] = { 8, 16, 16};\r\n        return temp[i];\r\n    }\r\n    case qrcodegen_Mode_KANJI       : {\r\n        static const int temp[] = { 8, 10, 12};\r\n        return temp[i];\r\n    }\r\n    case qrcodegen_Mode_ECI         : return 0;\r\n    default:  assert(false);  return -1;  // Dummy value\r\n    }\r\n}\r\n"
  },
  {
    "path": "qrcode/qrcodegen.h",
    "content": "/*\r\n * QR Code generator library (C)\r\n *\r\n * Copyright (c) Project Nayuki. (MIT License)\r\n * https://www.nayuki.io/page/qr-code-generator-library\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n * this software and associated documentation files (the \"Software\"), to deal in\r\n * the Software without restriction, including without limitation the rights to\r\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n * the Software, and to permit persons to whom the Software is furnished to do so,\r\n * subject to the following conditions:\r\n * - The above copyright notice and this permission notice shall be included in\r\n *   all copies or substantial portions of the Software.\r\n * - The Software is provided \"as is\", without warranty of any kind, express or\r\n *   implied, including but not limited to the warranties of merchantability,\r\n *   fitness for a particular purpose and noninfringement. In no event shall the\r\n *   authors or copyright holders be liable for any claim, damages or other\r\n *   liability, whether in an action of contract, tort or otherwise, arising from,\r\n *   out of or in connection with the Software or the use or other dealings in the\r\n *   Software.\r\n */\r\n\r\n#pragma once\r\n\r\n#include <stdbool.h>\r\n#include <stddef.h>\r\n#include <stdint.h>\r\n\r\n\r\n#ifdef __cplusplus\r\nextern \"C\" {\r\n#endif\r\n\r\n\r\n/*\r\n * This library creates QR Code symbols, which is a type of two-dimension barcode.\r\n * Invented by Denso Wave and described in the ISO/IEC 18004 standard.\r\n * A QR Code structure is an immutable square grid of black and white cells.\r\n * The library provides functions to create a QR Code from text or binary data.\r\n * The library covers the QR Code Model 2 specification, supporting all versions (sizes)\r\n * from 1 to 40, all 4 error correction levels, and 4 character encoding modes.\r\n *\r\n * Ways to create a QR Code object:\r\n * - High level: Take the payload data and call qrcodegen_encodeText() or qrcodegen_encodeBinary().\r\n * - Low level: Custom-make the list of segments and call\r\n *   qrcodegen_encodeSegments() or qrcodegen_encodeSegmentsAdvanced().\r\n * (Note that all ways require supplying the desired error correction level and various byte buffers.)\r\n */\r\n\r\n\r\n/*---- Enum and struct types----*/\r\n\r\n/*\r\n * The error correction level in a QR Code symbol.\r\n */\r\nenum qrcodegen_Ecc {\r\n    // Must be declared in ascending order of error protection\r\n    // so that an internal qrcodegen function works properly\r\n    qrcodegen_Ecc_LOW = 0,   // The QR Code can tolerate about  7% erroneous codewords\r\n    qrcodegen_Ecc_MEDIUM,    // The QR Code can tolerate about 15% erroneous codewords\r\n    qrcodegen_Ecc_QUARTILE,  // The QR Code can tolerate about 25% erroneous codewords\r\n    qrcodegen_Ecc_HIGH,      // The QR Code can tolerate about 30% erroneous codewords\r\n};\r\n\r\n\r\n/*\r\n * The mask pattern used in a QR Code symbol.\r\n */\r\nenum qrcodegen_Mask {\r\n    // A special value to tell the QR Code encoder to\r\n    // automatically select an appropriate mask pattern\r\n    qrcodegen_Mask_AUTO = -1,\r\n    // The eight actual mask patterns\r\n    qrcodegen_Mask_0 = 0,\r\n    qrcodegen_Mask_1,\r\n    qrcodegen_Mask_2,\r\n    qrcodegen_Mask_3,\r\n    qrcodegen_Mask_4,\r\n    qrcodegen_Mask_5,\r\n    qrcodegen_Mask_6,\r\n    qrcodegen_Mask_7,\r\n};\r\n\r\n\r\n/*\r\n * Describes how a segment's data bits are interpreted.\r\n */\r\nenum qrcodegen_Mode {\r\n    qrcodegen_Mode_NUMERIC      = 0x1,\r\n    qrcodegen_Mode_ALPHANUMERIC = 0x2,\r\n    qrcodegen_Mode_BYTE         = 0x4,\r\n    qrcodegen_Mode_KANJI        = 0x8,\r\n    qrcodegen_Mode_ECI          = 0x7,\r\n};\r\n\r\n\r\n/*\r\n * A segment of character/binary/control data in a QR Code symbol.\r\n * The mid-level way to create a segment is to take the payload data\r\n * and call a factory function such as qrcodegen_makeNumeric().\r\n * The low-level way to create a segment is to custom-make the bit buffer\r\n * and initialize a qrcodegen_Segment struct with appropriate values.\r\n * Even in the most favorable conditions, a QR Code can only hold 7089 characters of data.\r\n * Any segment longer than this is meaningless for the purpose of generating QR Codes.\r\n * Moreover, the maximum allowed bit length is 32767 because\r\n * the largest QR Code (version 40) has 31329 modules.\r\n */\r\nstruct qrcodegen_Segment {\r\n    // The mode indicator of this segment.\r\n    enum qrcodegen_Mode mode;\r\n\r\n    // The length of this segment's unencoded data. Measured in characters for\r\n    // numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode.\r\n    // Always zero or positive. Not the same as the data's bit length.\r\n    int numChars;\r\n\r\n    // The data bits of this segment, packed in bitwise big endian.\r\n    // Can be null if the bit length is zero.\r\n    uint8_t *data;\r\n\r\n    // The number of valid data bits used in the buffer. Requires\r\n    // 0 <= bitLength <= 32767, and bitLength <= (capacity of data array) * 8.\r\n    // The character count (numChars) must agree with the mode and the bit buffer length.\r\n    int bitLength;\r\n};\r\n\r\n\r\n\r\n/*---- Macro constants and functions ----*/\r\n\r\n#define qrcodegen_VERSION_MIN   1  // The minimum version number supported in the QR Code Model 2 standard\r\n#define qrcodegen_VERSION_MAX  40  // The maximum version number supported in the QR Code Model 2 standard\r\n\r\n// Calculates the number of bytes needed to store any QR Code up to and including the given version number,\r\n// as a compile-time constant. For example, 'uint8_t buffer[qrcodegen_BUFFER_LEN_FOR_VERSION(25)];'\r\n// can store any single QR Code from version 1 to 25 (inclusive). The result fits in an int (or int16).\r\n// Requires qrcodegen_VERSION_MIN <= n <= qrcodegen_VERSION_MAX.\r\n#define qrcodegen_BUFFER_LEN_FOR_VERSION(n)  ((((n) * 4 + 17) * ((n) * 4 + 17) + 7) / 8 + 1)\r\n\r\n// The worst-case number of bytes needed to store one QR Code, up to and including\r\n// version 40. This value equals 3918, which is just under 4 kilobytes.\r\n// Use this more convenient value to avoid calculating tighter memory bounds for buffers.\r\n#define qrcodegen_BUFFER_LEN_MAX  qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MAX)\r\n\r\n\r\n\r\n/*---- Functions (high level) to generate QR Codes ----*/\r\n\r\n/*\r\n * Encodes the given text string to a QR Code, returning true if encoding succeeded.\r\n * If the data is too long to fit in any version in the given range\r\n * at the given ECC level, then false is returned.\r\n * - The input text must be encoded in UTF-8 and contain no NULs.\r\n * - The variables ecl and mask must correspond to enum constant values.\r\n * - Requires 1 <= minVersion <= maxVersion <= 40.\r\n * - The arrays tempBuffer and qrcode must each have a length\r\n *   of at least qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion).\r\n * - After the function returns, tempBuffer contains no useful data.\r\n * - If successful, the resulting QR Code may use numeric,\r\n *   alphanumeric, or byte mode to encode the text.\r\n * - In the most optimistic case, a QR Code at version 40 with low ECC\r\n *   can hold any UTF-8 string up to 2953 bytes, or any alphanumeric string\r\n *   up to 4296 characters, or any digit string up to 7089 characters.\r\n *   These numbers represent the hard upper limit of the QR Code standard.\r\n * - Please consult the QR Code specification for information on\r\n *   data capacities per version, ECC level, and text encoding mode.\r\n */\r\nbool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[],\r\n                          enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl);\r\n\r\n\r\n/*\r\n * Encodes the given binary data to a QR Code, returning true if encoding succeeded.\r\n * If the data is too long to fit in any version in the given range\r\n * at the given ECC level, then false is returned.\r\n * - The input array range dataAndTemp[0 : dataLen] should normally be\r\n *   valid UTF-8 text, but is not required by the QR Code standard.\r\n * - The variables ecl and mask must correspond to enum constant values.\r\n * - Requires 1 <= minVersion <= maxVersion <= 40.\r\n * - The arrays dataAndTemp and qrcode must each have a length\r\n *   of at least qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion).\r\n * - After the function returns, the contents of dataAndTemp may have changed,\r\n *   and does not represent useful data anymore.\r\n * - If successful, the resulting QR Code will use byte mode to encode the data.\r\n * - In the most optimistic case, a QR Code at version 40 with low ECC can hold any byte\r\n *   sequence up to length 2953. This is the hard upper limit of the QR Code standard.\r\n * - Please consult the QR Code specification for information on\r\n *   data capacities per version, ECC level, and text encoding mode.\r\n */\r\nbool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[],\r\n                            enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl);\r\n\r\n\r\n/*---- Functions (low level) to generate QR Codes ----*/\r\n\r\n/*\r\n * Renders a QR Code representing the given segments at the given error correction level.\r\n * The smallest possible QR Code version is automatically chosen for the output. Returns true if\r\n * QR Code creation succeeded, or false if the data is too long to fit in any version. The ECC level\r\n * of the result may be higher than the ecl argument if it can be done without increasing the version.\r\n * This function allows the user to create a custom sequence of segments that switches\r\n * between modes (such as alphanumeric and byte) to encode text in less space.\r\n * This is a low-level API; the high-level API is qrcodegen_encodeText() and qrcodegen_encodeBinary().\r\n * To save memory, the segments' data buffers can alias/overlap tempBuffer, and will\r\n * result in them being clobbered, but the QR Code output will still be correct.\r\n * But the qrcode array must not overlap tempBuffer or any segment's data buffer.\r\n */\r\nbool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len,\r\n                              enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[]);\r\n\r\n\r\n/*\r\n * Renders a QR Code representing the given segments with the given encoding parameters.\r\n * Returns true if QR Code creation succeeded, or false if the data is too long to fit in the range of versions.\r\n * The smallest possible QR Code version within the given range is automatically\r\n * chosen for the output. Iff boostEcl is true, then the ECC level of the result\r\n * may be higher than the ecl argument if it can be done without increasing the\r\n * version. The mask is either between qrcodegen_Mask_0 to 7 to force that mask, or\r\n * qrcodegen_Mask_AUTO to automatically choose an appropriate mask (which may be slow).\r\n * This function allows the user to create a custom sequence of segments that switches\r\n * between modes (such as alphanumeric and byte) to encode text in less space.\r\n * This is a low-level API; the high-level API is qrcodegen_encodeText() and qrcodegen_encodeBinary().\r\n * To save memory, the segments' data buffers can alias/overlap tempBuffer, and will\r\n * result in them being clobbered, but the QR Code output will still be correct.\r\n * But the qrcode array must not overlap tempBuffer or any segment's data buffer.\r\n */\r\nbool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl,\r\n                                      int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl, uint8_t tempBuffer[], uint8_t qrcode[]);\r\n\r\n\r\n/*\r\n * Tests whether the given string can be encoded as a segment in alphanumeric mode.\r\n * A string is encodable iff each character is in the following set: 0 to 9, A to Z\r\n * (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.\r\n */\r\nbool qrcodegen_isAlphanumeric(const char *text);\r\n\r\n\r\n/*\r\n * Tests whether the given string can be encoded as a segment in numeric mode.\r\n * A string is encodable iff each character is in the range 0 to 9.\r\n */\r\nbool qrcodegen_isNumeric(const char *text);\r\n\r\n\r\n/*\r\n * Returns the number of bytes (uint8_t) needed for the data buffer of a segment\r\n * containing the given number of characters using the given mode. Notes:\r\n * - Returns SIZE_MAX on failure, i.e. numChars > INT16_MAX or\r\n *   the number of needed bits exceeds INT16_MAX (i.e. 32767).\r\n * - Otherwise, all valid results are in the range [0, ceil(INT16_MAX / 8)], i.e. at most 4096.\r\n * - It is okay for the user to allocate more bytes for the buffer than needed.\r\n * - For byte mode, numChars measures the number of bytes, not Unicode code points.\r\n * - For ECI mode, numChars must be 0, and the worst-case number of bytes is returned.\r\n *   An actual ECI segment can have shorter data. For non-ECI modes, the result is exact.\r\n */\r\nsize_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars);\r\n\r\n\r\n/*\r\n * Returns a segment representing the given binary data encoded in\r\n * byte mode. All input byte arrays are acceptable. Any text string\r\n * can be converted to UTF-8 bytes and encoded as a byte mode segment.\r\n */\r\nstruct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]);\r\n\r\n\r\n/*\r\n * Returns a segment representing the given string of decimal digits encoded in numeric mode.\r\n */\r\nstruct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]);\r\n\r\n\r\n/*\r\n * Returns a segment representing the given text string encoded in alphanumeric mode.\r\n * The characters allowed are: 0 to 9, A to Z (uppercase only), space,\r\n * dollar, percent, asterisk, plus, hyphen, period, slash, colon.\r\n */\r\nstruct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]);\r\n\r\n\r\n/*\r\n * Returns a segment representing an Extended Channel Interpretation\r\n * (ECI) designator with the given assignment value.\r\n */\r\nstruct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]);\r\n\r\n\r\n/*---- Functions to extract raw data from QR Codes ----*/\r\n\r\n/*\r\n * Returns the side length of the given QR Code, assuming that encoding succeeded.\r\n * The result is in the range [21, 177]. Note that the length of the array buffer\r\n * is related to the side length - every 'uint8_t qrcode[]' must have length at least\r\n * qrcodegen_BUFFER_LEN_FOR_VERSION(version), which equals ceil(size^2 / 8 + 1).\r\n */\r\nint qrcodegen_getSize(const uint8_t qrcode[]);\r\n\r\n\r\n/*\r\n * Returns the color of the module (pixel) at the given coordinates, which is false\r\n * for white or true for black. The top left corner has the coordinates (x=0, y=0).\r\n * If the given coordinates are out of bounds, then false (white) is returned.\r\n */\r\nbool qrcodegen_getModule(const uint8_t qrcode[], int x, int y);\r\n\r\n\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n"
  },
  {
    "path": "qrcode/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(qrcode_test)\n"
  },
  {
    "path": "qrcode/test_apps/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"qrcode_test.c\"\n                    INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES unity)\n"
  },
  {
    "path": "qrcode/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/qrcode:\n    version: \"*\"\n    override_path: \"../..\"\n"
  },
  {
    "path": "qrcode/test_apps/main/qrcode_test.c",
    "content": "#include <stdio.h>\n\nvoid app_main(void)\n{\n\n}\n"
  },
  {
    "path": "quirc/.build-test-rules.yml",
    "content": "quirc/test_apps:\n  enable:\n    - if: IDF_TARGET in [\"esp32\", \"esp32c3\"]\n      reason: \"Sufficient to test on one Xtensa and one RISC-V target\"\n"
  },
  {
    "path": "quirc/CMakeLists.txt",
    "content": "idf_component_register(SRCS quirc/lib/decode.c\n                            quirc/lib/identify.c\n                            quirc/lib/quirc.c\n                            quirc/lib/version_db.c\n                       INCLUDE_DIRS quirc/lib)\n\n# Performance optimization; see quirc README.md for an explanation of these options\ntarget_compile_definitions(${COMPONENT_LIB} PRIVATE QUIRC_FLOAT_TYPE=float)\ntarget_compile_definitions(${COMPONENT_LIB} PRIVATE QUIRC_USE_TGMATH)\n"
  },
  {
    "path": "quirc/LICENSE",
    "content": "quirc -- QR-code recognition library\nCopyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com>\n\nISC License\n===========\n\nPermission to use, copy, modify, and/or distribute this software for\nany purpose with or without fee is hereby granted, provided that the\nabove copyright notice and this permission notice appear in all\ncopies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL\nWARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE\nAUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL\nDAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR\nPROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER\nTORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n"
  },
  {
    "path": "quirc/README.md",
    "content": "# Quirc QR code decoding library\n\n[![Component Registry](https://components.espressif.com/components/espressif/quirc/badge.svg)](https://components.espressif.com/components/espressif/quirc)\n\nThis is an ESP-IDF component for [quirc](https://github.com/dlbeer/quirc), a QR code decoding library.\n\nPlease refer to https://github.com/dlbeer/quirc#library-use for the introduction to this library.\n\nSee also the `qrcode` component for generation of QR codes ([registry](https://components.espressif.com/components/espressif/qrcode), [source](../qrcode/README.md)).\n"
  },
  {
    "path": "quirc/idf_component.yml",
    "content": "version: \"1.2.0\"\ndescription: Quirc QR code decoding library\nurl: https://github.com/espressif/idf-extra-components/tree/master/quirc\nrepository: https://github.com/espressif/idf-extra-components.git\nissues: https://github.com/espressif/idf-extra-components/issues\ndocumentation: https://github.com/dlbeer/quirc#library-use\ndependencies:\n  idf: \">=4.3.0\"\n"
  },
  {
    "path": "quirc/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(quirc_test)\n"
  },
  {
    "path": "quirc/test_apps/main/CMakeLists.txt",
    "content": "idf_component_register(\n    SRCS test_quirc.c test_main.c\n    PRIV_REQUIRES unity\n    EMBED_FILES test_qrcode.pgm\n    WHOLE_ARCHIVE)\n"
  },
  {
    "path": "quirc/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/quirc:\n    version: \"*\"\n    override_path: \"../..\"\n"
  },
  {
    "path": "quirc/test_apps/main/test_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"unity.h\"\n#include \"unity_test_runner.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_newlib.h\"\n#include \"unity_test_utils_memory.h\"\n\nvoid setUp(void)\n{\n    unity_utils_record_free_mem();\n}\n\nvoid tearDown(void)\n{\n    esp_reent_cleanup();    //clean up some of the newlib's lazy allocations\n    unity_utils_evaluate_leaks_direct(0);\n}\n\nvoid app_main(void)\n{\n    printf(\"Running quirc component tests\\n\");\n    unity_run_menu();\n}\n"
  },
  {
    "path": "quirc/test_apps/main/test_quirc.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include <stdio.h>\n#include <stdint.h>\n#include \"esp_log.h\"\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"freertos/semphr.h\"\n#include \"quirc.h\"\n#include \"unity.h\"\n\nstatic const char *TAG = \"test_quirc\";\n\nextern const uint8_t test_qrcode_pgm_start[] asm(\"_binary_test_qrcode_pgm_start\");\nextern const uint8_t test_qrcode_pgm_end[]   asm(\"_binary_test_qrcode_pgm_end\");\n\nstatic void copy_test_image_into_quirc_buffer(struct quirc *q)\n{\n    // get the size of the image from the PGM header\n    const uint8_t *p = test_qrcode_pgm_start;\n    int width, height;\n    sscanf((const char *)p, \"P5 %d %d 255\", &width, &height);\n    TEST_ASSERT_EQUAL_INT(128, width);\n    TEST_ASSERT_EQUAL_INT(113, height);\n\n    // resize the quirc buffer to match the image\n    TEST_ASSERT_EQUAL_INT(0, quirc_resize(q, width, height));\n\n    // find the start of the image data\n    p = memchr(p, '\\n', test_qrcode_pgm_end - p) + 1;\n\n    // copy the image into the quirc buffer\n    memcpy(quirc_begin(q, NULL, NULL), p, width * height);\n}\n\ntypedef struct {\n    struct quirc *q;\n    struct quirc_code code;\n    struct quirc_data data;\n    SemaphoreHandle_t done;\n} quirc_decode_task_args_t;\n\nstatic void quirc_decode_task(void *arg)\n{\n    quirc_decode_task_args_t *args = (quirc_decode_task_args_t *)arg;\n    quirc_end(args->q);\n    TEST_ASSERT_EQUAL_INT(1, quirc_count(args->q));\n    quirc_extract(args->q, 0, &args->code);\n    TEST_ASSERT_EQUAL(QUIRC_SUCCESS, quirc_decode(&args->code, &args->data));\n\n    const size_t stack_space_free = uxTaskGetStackHighWaterMark(NULL);\n    ESP_LOGI(TAG, \"quirc_decode_task stack space free: %d\", stack_space_free);\n    xSemaphoreGive(args->done);\n    vTaskDelete(NULL);\n}\n\nTEST_CASE(\"quirc can load a QR code\", \"[quirc]\")\n{\n    struct quirc *q = quirc_new();\n    TEST_ASSERT_NOT_NULL(q);\n\n    // load the test image into the quirc buffer\n    copy_test_image_into_quirc_buffer(q);\n\n    // decode the QR code in the image\n    // quirc uses a lot of stack space (around 10kB on ESP32 for this particular QR code),\n    // so do this in a separate task\n    quirc_decode_task_args_t *args = calloc(1, sizeof(*args));\n    TEST_ASSERT_NOT_NULL(args);\n    args->q = q;\n    args->done = xSemaphoreCreateBinary();\n    TEST_ASSERT(xTaskCreate(quirc_decode_task, \"quirc_decode_task\", 12000, args, 5, NULL));\n    TEST_ASSERT(xSemaphoreTake(args->done, pdMS_TO_TICKS(10000)));\n    vSemaphoreDelete(args->done);\n\n    // check the QR code data\n    TEST_ASSERT_EQUAL_INT(1, args->data.version);\n    TEST_ASSERT_EQUAL_INT(1, args->data.ecc_level);\n    TEST_ASSERT_EQUAL_INT(4, args->data.data_type);\n    TEST_ASSERT_EQUAL_INT(13, args->data.payload_len);\n    TEST_ASSERT_EQUAL_STRING(\"test of quirc\", args->data.payload);\n\n    free(args);\n    quirc_destroy(q);\n    vTaskDelay(2);  // allow the task to clean up\n}\n"
  },
  {
    "path": "quirc/test_apps/pytest_quirc.py",
    "content": "import pytest\n\n\n@pytest.mark.generic\ndef test_quirc(dut) -> None:\n    dut.run_all_single_board_cases()\n"
  },
  {
    "path": "quirc/test_apps/sdkconfig.defaults",
    "content": "# This file was generated using idf.py save-defconfig. It can be edited manually.\n# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration\n#\nCONFIG_ESP_TASK_WDT_INIT=n\n"
  },
  {
    "path": "sh2lib/CHANGELOG.md",
    "content": "## 1.1.0\n\n### Features\n- Make task stack size configurable\n- Add configurable inbound buffer length support\n- Add TCP keepalive configuration\n- Capture and report TLS errors\n- Forward underlying nghttp2 execution error codes\n- Log and report underlying get/post error codes\n\n### Fixes\n- Update API documentation for return values\n- Fix CI build error due to an undefined Kconfig option\n\n## 1.0.5\n\n- Added http2_request example in the component.\n"
  },
  {
    "path": "sh2lib/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"sh2lib.c\"\n                    INCLUDE_DIRS .\n                    REQUIRES http_parser\n                    PRIV_REQUIRES lwip esp-tls)\n"
  },
  {
    "path": "sh2lib/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "sh2lib/README.md",
    "content": "# Abstraction layer for HTTP2 with TLS\n\n[![Component Registry](https://components.espressif.com/components/espressif/sh2lib/badge.svg)](https://components.espressif.com/components/espressif/sh2lib)\n\nThis component contains an abstraction layer which exposes simpler set of APIs combining `nghttp2` (HTTP/2 C Library) and `esp-tls` (from ESP-IDF) components.\n\n"
  },
  {
    "path": "sh2lib/examples/http2_request/CMakeLists.txt",
    "content": "# The following lines of boilerplate have to be in your project's CMakeLists\n# in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\n\n# (Not part of the boilerplate)\n# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.\nset(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nproject(http2_request)\n"
  },
  {
    "path": "sh2lib/examples/http2_request/README.md",
    "content": "# HTTP/2 Request Example\n\nEstablish an HTTP/2 connection with https://http2.github.io\n- Performs a GET on /index.html\n\n## How to use example\nBefore project configuration and build, be sure to set the correct chip target using `idf.py set-target <chip_name>`.\n\n### Hardware Required\n\n* A development board with ESP32/ESP32-S2/ESP32-C3 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)\n* A USB cable for power supply and programming\n\n### Configure the project\n\n```\nidf.py menuconfig\n```\nOpen the project configuration menu (`idf.py menuconfig`) to configure Wi-Fi or Ethernet. See \"Establishing Wi-Fi or Ethernet Connection\" section in [examples/protocols/README.md](../../README.md) for more details.\n\n### Build and Flash\n\nBuild the project and flash it to the board, then run monitor tool to view serial output:\n\n```\nidf.py -p PORT flash monitor\n```\n\n(Replace PORT with the name of the serial port to use.)\n\n(To exit the serial monitor, type ``Ctrl-]``.)\n\nSee the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.\n\n## Example Output\n\n```\nI (5609) example_connect: - IPv4 address: 192.168.0.103\nI (5609) example_connect: - IPv6 address: fe80:0000:0000:0000:ae67:b2ff:fe45:0194, type: ESP_IP6_ADDR_IS_LINK_LOCAL\nConnecting to server\nConnection done\n[get-response] <!DOCTYPE HTML>\n<html lang=\"en\">\n.\n.\n.\nBody of index.html\n.\n.\n.\n.\n</html>\n[get-response] Frame fully received\n[get-response] Stream Closed\n```\n"
  },
  {
    "path": "sh2lib/examples/http2_request/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"http2_request_example_main.c\"\n                    INCLUDE_DIRS \".\")\n"
  },
  {
    "path": "sh2lib/examples/http2_request/main/Kconfig.projbuild",
    "content": "menu \"Example Configuration\"\n\n    config EXAMPLE_NGHTTP2_TASK_STACK_SIZE\n        int \"Nghttp2 task stack size\"\n        default 8192\n        help\n            This is the stack size for the nghttp task.\n\nendmenu\n"
  },
  {
    "path": "sh2lib/examples/http2_request/main/http2_request_example_main.c",
    "content": "/* HTTP2 GET Example using nghttp2\n\n   Contacts http2.github.io and executes the GET request. A thin API\n   wrapper on top of nghttp2, to properly demonstrate the interactions.\n\n   This example code is in the Public Domain (or CC0 licensed, at your option.)\n\n   Unless required by applicable law or agreed to in writing, this\n   software is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n   CONDITIONS OF ANY KIND, either express or implied.\n\n */\n#include <string.h>\n#include <stdlib.h>\n#include <sys/time.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"esp_event.h\"\n#include \"esp_system.h\"\n#include \"nvs_flash.h\"\n#include \"protocol_examples_common.h\"\n#include \"esp_netif.h\"\n#include \"esp_idf_version.h\"\n#if ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(5, 1, 0)\n#include \"lwip/apps/sntp.h\"\n#else\n#include \"esp_netif_sntp.h\"\n#endif\n#include \"sdkconfig.h\"\n\n#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE\n#include \"esp_crt_bundle.h\"\n#endif\n\n#include \"sh2lib.h\"\n\n// Compile-time check to ensure stack size is larger than inbound buffer length\n#if CONFIG_EXAMPLE_NGHTTP2_TASK_STACK_SIZE <= CONFIG_ESP_NGHTTP2_INBOUND_BUFFER_LENGTH\n#warning \"CONFIG_EXAMPLE_NGHTTP2_TASK_STACK_SIZE should be larger than CONFIG_ESP_NGHTTP2_INBOUND_BUFFER_LENGTH\"\n#endif\n\n/* The HTTP/2 server to connect to */\n#define HTTP2_SERVER_URI  \"https://http2.github.io\"\n/* A GET request that keeps streaming current time every second */\n#define HTTP2_STREAMING_GET_PATH  \"/index.html\"\n\n\nint handle_get_response(struct sh2lib_handle *handle, const char *data, size_t len, int flags)\n{\n    if (len) {\n        printf(\"[get-response] %.*s\\n\", (int)len, data);\n    }\n    if (flags == DATA_RECV_FRAME_COMPLETE) {\n        printf(\"[get-response] Frame fully received\\n\");\n    }\n    if (flags == DATA_RECV_RST_STREAM) {\n        printf(\"[get-response] Stream Closed\\n\");\n        printf(\"Remaining task stask size: %d\\n\", uxTaskGetStackHighWaterMark(NULL));\n    }\n    return 0;\n}\n\nint handle_echo_response(struct sh2lib_handle *handle, const char *data, size_t len, int flags)\n{\n    if (len) {\n        printf(\"[echo-response] %.*s\\n\", (int)len, data);\n    }\n    if (flags == DATA_RECV_FRAME_COMPLETE) {\n        printf(\"[echo-response] Frame fully received\\n\");\n    }\n    if (flags == DATA_RECV_RST_STREAM) {\n        printf(\"[echo-response] Stream Closed\\n\");\n    }\n    return 0;\n}\n\nint send_put_data(struct sh2lib_handle *handle, char *buf, size_t length, uint32_t *data_flags)\n{\n#define DATA_TO_SEND \"Hello World\"\n    int copylen = strlen(DATA_TO_SEND);\n    if (copylen < length) {\n        printf(\"[data-prvd] Sending %d bytes\\n\", copylen);\n        memcpy(buf, DATA_TO_SEND, copylen);\n    } else {\n        copylen = 0;\n    }\n\n    (*data_flags) |= NGHTTP2_DATA_FLAG_EOF;\n    return copylen;\n}\n\nstatic void set_time(void)\n{\n    struct timeval tv = {\n        .tv_sec = 1509449941,\n    };\n    struct timezone tz = {\n        0, 0\n    };\n    settimeofday(&tv, &tz);\n\n    /* Start SNTP service */\n#if ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(5, 1, 0)\n    sntp_setoperatingmode(SNTP_OPMODE_POLL);\n    sntp_init();\n#else\n    esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(\"time.windows.com\");\n    esp_netif_sntp_init(&config);\n    if (esp_netif_sntp_sync_wait(pdMS_TO_TICKS(10000)) != ESP_OK) {\n        printf(\"Failed to update system time, continuing\");\n    }\n    esp_netif_sntp_deinit();\n#endif\n}\n\nstatic void http2_task(void *args)\n{\n    /* Set current time: proper system time is required for TLS based\n     * certificate verification.\n     */\n    set_time();\n\n    /* HTTP2: one connection multiple requests. Do the TLS/TCP connection first */\n    printf(\"Connecting to server\\n\");\n\n    struct sh2lib_config_t cfg = {\n        .uri = HTTP2_SERVER_URI,\n#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE\n        .crt_bundle_attach = esp_crt_bundle_attach,\n#endif\n    };\n    struct sh2lib_handle hd;\n\n    if (sh2lib_connect(&cfg, &hd) != 0) {\n        printf(\"Failed to connect\\n\");\n        vTaskDelete(NULL);\n        return;\n    }\n    printf(\"Connection done\\n\");\n\n    /* HTTP GET with proper error handling */\n    int stream_id = sh2lib_do_get(&hd, HTTP2_STREAMING_GET_PATH, handle_get_response);\n    if (stream_id < 0) {\n        printf(\"Failed to setup GET request, error code: %d\\n\", stream_id);\n        goto end;\n    }\n\n    printf(\"GET request setup successful, stream ID: %d\\n\", stream_id);\n    while (1) {\n        /* Process HTTP2 send/receive */\n        if (sh2lib_execute(&hd) < 0) {\n            printf(\"Error in send/receive, tls error code: %d\\n\", hd.http2_tls_rc);\n            break;\n        }\n        vTaskDelay(2);\n    }\n\nend:\n    sh2lib_free(&hd);\n    vTaskDelete(NULL);\n    return;\n}\n\nvoid app_main(void)\n{\n    ESP_ERROR_CHECK(nvs_flash_init());\n    ESP_ERROR_CHECK(esp_netif_init());\n    ESP_ERROR_CHECK(esp_event_loop_create_default());\n\n    /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.\n     * Read \"Establishing Wi-Fi or Ethernet Connection\" section in\n     * examples/protocols/README.md for more information about this function.\n     */\n    ESP_ERROR_CHECK(example_connect());\n\n    xTaskCreate(&http2_task, \"http2_task\", CONFIG_EXAMPLE_NGHTTP2_TASK_STACK_SIZE, NULL, 5, NULL);\n}\n"
  },
  {
    "path": "sh2lib/examples/http2_request/main/idf_component.yml",
    "content": "## IDF Component Manager Manifest File\nversion: \"1.0.0\"\ndescription: HTTP2 Request Examples\ndependencies:\n  espressif/sh2lib:\n    version: \"^1.0.0\"\n    override_path: '../../../'\n"
  },
  {
    "path": "sh2lib/examples/http2_request/pytest_http2_request.py",
    "content": "#!/usr/bin/env python\n#\n# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\n\nimport http.client\nimport logging\nimport os\n\nimport pytest\nfrom pytest_embedded import Dut\n\nHTTP_OK = 200\nTEST_SERVER = 'http2.github.io'\n\n\ndef is_test_server_available():  # type: () -> bool\n    # 443 - default https port\n    try:\n        conn = http.client.HTTPSConnection(TEST_SERVER, 443, timeout=10)\n        conn.request('GET', '/')\n        resp = conn.getresponse()\n        return True if resp.status == HTTP_OK else False\n    except Exception as msg:\n        logging.info('Exception occurred when connecting to {}: {}'.format(TEST_SERVER, msg))\n        return False\n    finally:\n        conn.close()\n\n\n@pytest.mark.ethernet\ndef test_examples_protocol_http2_request(dut: Dut) -> None:\n    \"\"\"\n    steps: |\n      1. join AP\n      2. connect to http2.github.io\n      3. send http2 request\n      4. send http2 put response\n    \"\"\"\n    # check and log bin size\n    binary_file = os.path.join(dut.app.binary_path, 'http2_request.bin')\n    bin_size = os.path.getsize(binary_file)\n    logging.info('http2_request_bin_size : {}KB'.format(bin_size // 1024))\n    # start the test\n    # check if test server is available\n    test_server_available = is_test_server_available()\n    # Skip the test if the server test server (http2.github.io) is not available at the moment.\n    if test_server_available:\n        logging.info('test server \\\"{}\\\" is available'.format(TEST_SERVER))\n        # check for connection\n        dut.expect('Connection done', timeout=30)\n        # check for get response\n        dut.expect('Frame fully received')\n    else:\n        logging.info('test server \\\"{0}\\\" is not available at the moment.\\nSkipping the test with status = success.'.format(TEST_SERVER))\n"
  },
  {
    "path": "sh2lib/examples/http2_request/sdkconfig.ci",
    "content": "CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y\nCONFIG_EXAMPLE_CONNECT_ETHERNET=y\nCONFIG_EXAMPLE_CONNECT_WIFI=n\nCONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y\nCONFIG_EXAMPLE_ETH_MDC_GPIO=23\nCONFIG_EXAMPLE_ETH_MDIO_GPIO=18\nCONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5\nCONFIG_EXAMPLE_ETH_PHY_ADDR=1\nCONFIG_EXAMPLE_CONNECT_IPV6=y\n"
  },
  {
    "path": "sh2lib/examples/http2_request/sdkconfig.ci.esp32",
    "content": "CONFIG_SPIRAM=y\n"
  },
  {
    "path": "sh2lib/examples/http2_request/sdkconfig.defaults",
    "content": "CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN=y\n"
  },
  {
    "path": "sh2lib/idf_component.yml",
    "content": "version: \"1.1.0\"\ndescription: HTTP2 TLS Abstraction Layer\nurl: https://github.com/espressif/idf-extra-components/tree/master/sh2lib\ndependencies:\n  idf: \">=5.0\"\n  espressif/nghttp:\n    version: \">=1.41.0\"\n    override_path: \"../nghttp\"\n"
  },
  {
    "path": "sh2lib/sh2lib.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2017-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <inttypes.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stddef.h>\n#include <stdio.h>\n#include <string.h>\n#include <unistd.h>\n#include <ctype.h>\n#include <netdb.h>\n#include <esp_log.h>\n#include <http_parser.h>\n#include <esp_idf_version.h>\n\n#include \"sh2lib.h\"\n\nstatic const char *TAG = \"sh2lib\";\n\n#define DBG_FRAME_SEND 1\n\n/*\n * The implementation of nghttp2_send_callback type. Here we write\n * |data| with size |length| to the network and return the number of\n * bytes actually written. See the documentation of\n * nghttp2_send_callback for the details.\n */\nstatic ssize_t callback_send_inner(struct sh2lib_handle *hd, const uint8_t *data,\n                                   size_t length)\n{\n    int rv = esp_tls_conn_write(hd->http2_tls, data, length);\n    if (rv <= 0) {\n        if (rv == ESP_TLS_ERR_SSL_WANT_READ || rv == ESP_TLS_ERR_SSL_WANT_WRITE) {\n            rv = NGHTTP2_ERR_WOULDBLOCK;\n        } else {\n            hd->http2_tls_rc = rv;\n            rv = NGHTTP2_ERR_CALLBACK_FAILURE;\n        }\n    }\n    return rv;\n}\n\nstatic int callback_error(nghttp2_session *session, int lib_error_code,\n                          const char *msg, size_t len, void *user_data)\n{\n    ESP_LOGE(TAG, \"[error] code %i msg:%.*s\", lib_error_code, len, msg);\n    return 0;\n}\n\nstatic ssize_t callback_send(nghttp2_session *session, const uint8_t *data,\n                             size_t length, int flags, void *user_data)\n{\n    ssize_t rv = 0;\n    struct sh2lib_handle *hd = user_data;\n\n    size_t copy_offset = 0;\n    size_t pending_data = length;\n\n    /* Send data in 1000 byte chunks */\n    while (copy_offset < length) {\n        size_t chunk_len = pending_data > 1000 ? 1000 : pending_data;\n        ssize_t subrv = callback_send_inner(hd, data + copy_offset, chunk_len);\n        if (subrv <= 0) {\n            if (copy_offset == 0) {\n                /* If no data is transferred, send the error code */\n                rv = subrv;\n            }\n            break;\n        }\n        copy_offset += subrv;\n        pending_data -= subrv;\n        rv += subrv;\n    }\n    return rv;\n}\n\n/*\n * The implementation of nghttp2_recv_callback type. Here we read data\n * from the network and write them in |buf|. The capacity of |buf| is\n * |length| bytes. Returns the number of bytes stored in |buf|. See\n * the documentation of nghttp2_recv_callback for the details.\n */\nstatic ssize_t callback_recv(nghttp2_session *session, uint8_t *buf,\n                             size_t length, int flags, void *user_data)\n{\n    struct sh2lib_handle *hd = user_data;\n    int rv;\n    rv = esp_tls_conn_read(hd->http2_tls, (char *)buf, (int)length);\n    if (rv < 0) {\n        if (rv == ESP_TLS_ERR_SSL_WANT_READ || rv == ESP_TLS_ERR_SSL_WANT_WRITE) {\n            rv = NGHTTP2_ERR_WOULDBLOCK;\n        } else {\n            hd->http2_tls_rc = rv;\n            rv = NGHTTP2_ERR_CALLBACK_FAILURE;\n        }\n    } else if (rv == 0) {\n        rv = NGHTTP2_ERR_EOF;\n    }\n    return rv;\n}\n\nconst char *sh2lib_frame_type_str(int type)\n{\n    switch (type) {\n    case NGHTTP2_HEADERS:\n        return \"HEADERS\";\n        break;\n    case NGHTTP2_RST_STREAM:\n        return \"RST_STREAM\";\n        break;\n    case NGHTTP2_GOAWAY:\n        return \"GOAWAY\";\n        break;\n    case NGHTTP2_DATA:\n        return \"DATA\";\n        break;\n    case NGHTTP2_SETTINGS:\n        return \"SETTINGS\";\n        break;\n    case NGHTTP2_PUSH_PROMISE:\n        return \"PUSH_PROMISE\";\n        break;\n    case NGHTTP2_PING:\n        return \"PING\";\n        break;\n    default:\n        return \"other\";\n        break;\n    }\n}\n\nstatic int callback_on_frame_send(nghttp2_session *session,\n                                  const nghttp2_frame *frame, void *user_data)\n{\n    ESP_LOGD(TAG, \"[frame-send] frame type %s\", sh2lib_frame_type_str(frame->hd.type));\n    switch (frame->hd.type) {\n    case NGHTTP2_HEADERS:\n        if (nghttp2_session_get_stream_user_data(session, frame->hd.stream_id)) {\n            ESP_LOGD(TAG, \"[frame-send] C ----------------------------> S (HEADERS)\");\n#if DBG_FRAME_SEND\n            ESP_LOGD(TAG, \"[frame-send] headers nv-len = %d\", frame->headers.nvlen);\n            for (size_t i = 0; i < frame->headers.nvlen; ++i) {\n                ESP_LOGD(TAG, \"[frame-send] %s : %s\", frame->headers.nva[i].name, frame->headers.nva[i].value);\n            }\n#endif\n        }\n        break;\n    }\n    return 0;\n}\n\nstatic int callback_on_frame_not_send(nghttp2_session *session,\n                                      const nghttp2_frame *frame, int lib_error_code, void *user_data)\n{\n    ESP_LOGW(TAG, \"[frame-not-send] code %i frame type %s\", lib_error_code, sh2lib_frame_type_str(frame->hd.type));\n    return 0;\n}\n\nstatic int callback_on_frame_recv(nghttp2_session *session,\n                                  const nghttp2_frame *frame, void *user_data)\n{\n    struct sh2lib_handle *h2 = user_data;\n    ESP_LOGD(TAG, \"[frame-recv][sid: %\" PRIi32 \"] frame type  %s\", frame->hd.stream_id, sh2lib_frame_type_str(frame->hd.type));\n    sh2lib_frame_data_recv_cb_t data_recv_cb = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);\n    if (frame->hd.type == NGHTTP2_DATA && data_recv_cb) {\n        (*data_recv_cb)(h2, NULL, 0, DATA_RECV_FRAME_COMPLETE);\n    }\n    if (frame->hd.type == NGHTTP2_GOAWAY) {\n        ESP_LOGW(TAG, \"[frame-recv] GOAWAY: no more requests may be sent\");\n        h2->http2_goaway = true;\n    }\n    return 0;\n}\n\nstatic int callback_on_stream_close(nghttp2_session *session, int32_t stream_id,\n                                    uint32_t error_code, void *user_data)\n{\n    ESP_LOGD(TAG, \"[stream-close][sid %\" PRIi32 \"]\", stream_id);\n    sh2lib_frame_data_recv_cb_t data_recv_cb = nghttp2_session_get_stream_user_data(session, stream_id);\n    if (data_recv_cb) {\n        struct sh2lib_handle *h2 = user_data;\n        (*data_recv_cb)(h2, NULL, 0, DATA_RECV_RST_STREAM);\n    }\n    return 0;\n}\n\nstatic int callback_on_data_chunk_recv(nghttp2_session *session, uint8_t flags,\n                                       int32_t stream_id, const uint8_t *data,\n                                       size_t len, void *user_data)\n{\n    sh2lib_frame_data_recv_cb_t data_recv_cb;\n    ESP_LOGD(TAG, \"[data-chunk][sid: %\" PRIi32 \"]\", stream_id);\n    data_recv_cb = nghttp2_session_get_stream_user_data(session, stream_id);\n    if (data_recv_cb) {\n        ESP_LOGD(TAG, \"[data-chunk] C <---------------------------- S (DATA chunk)\"\n                 \"%lu bytes\",\n                 (unsigned long int)len);\n        struct sh2lib_handle *h2 = user_data;\n        (*data_recv_cb)(h2, (char *)data, len, 0);\n        /* TODO: What to do with the return value: look for pause/abort */\n    }\n    return 0;\n}\n\nstatic int callback_on_header(nghttp2_session *session, const nghttp2_frame *frame,\n                              const uint8_t *name, size_t namelen, const uint8_t *value,\n                              size_t valuelen, uint8_t flags, void *user_data)\n{\n    ESP_LOGD(TAG, \"[hdr-recv][sid: %\" PRIi32 \"] %s : %s\", frame->hd.stream_id, name, value);\n    return 0;\n}\n\nstatic int callback_on_invalid_header(nghttp2_session *session, const nghttp2_frame *frame,\n                                      const uint8_t *name, size_t namelen, const uint8_t *value,\n                                      size_t valuelen, uint8_t flags, void *user_data)\n{\n    ESP_LOGW(TAG, \"[inv-hdr][sid: %\" PRIi32 \"] %s : %s\", frame->hd.stream_id, name, value);\n    return 0;\n}\n\nstatic int do_http2_connect(struct sh2lib_handle *hd)\n{\n    int ret;\n    nghttp2_session_callbacks *callbacks;\n    ret = nghttp2_session_callbacks_new(&callbacks);\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"[sh2-connect] Failed to create session callbacks\");\n        return -1;\n    }\n    nghttp2_session_callbacks_set_error_callback2(callbacks, callback_error);\n    nghttp2_session_callbacks_set_send_callback(callbacks, callback_send);\n    nghttp2_session_callbacks_set_recv_callback(callbacks, callback_recv);\n    nghttp2_session_callbacks_set_on_frame_send_callback(callbacks, callback_on_frame_send);\n    nghttp2_session_callbacks_set_on_frame_not_send_callback(callbacks, callback_on_frame_not_send);\n    nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks, callback_on_frame_recv);\n    nghttp2_session_callbacks_set_on_invalid_header_callback(callbacks, callback_on_invalid_header);\n    nghttp2_session_callbacks_set_on_stream_close_callback(callbacks, callback_on_stream_close);\n    nghttp2_session_callbacks_set_on_data_chunk_recv_callback(callbacks, callback_on_data_chunk_recv);\n    nghttp2_session_callbacks_set_on_header_callback(callbacks, callback_on_header);\n    ret = nghttp2_session_client_new(&hd->http2_sess, callbacks, hd);\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"[sh2-connect] New http2 session failed\");\n        nghttp2_session_callbacks_del(callbacks);\n        return -1;\n    }\n    nghttp2_session_callbacks_del(callbacks);\n\n    /* Create the SETTINGS frame */\n    ret = nghttp2_submit_settings(hd->http2_sess, NGHTTP2_FLAG_NONE, NULL, 0);\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"[sh2-connect] Submit settings failed\");\n        /* Clean up session to prevent memory leak on error path */\n        nghttp2_session_del(hd->http2_sess);\n        hd->http2_sess = NULL;\n        return -1;\n    }\n    return 0;\n}\n\nint sh2lib_connect(struct sh2lib_config_t *cfg, struct sh2lib_handle *hd)\n{\n    if (hd == NULL || cfg == NULL || cfg->uri == NULL) {\n        ESP_LOGE(TAG, \"[sh2-connect] Invalid argument\");\n        return -1;\n    }\n\n    memset(hd, 0, sizeof(*hd));\n\n    const char *proto[] = {\"h2\", NULL};\n    esp_tls_cfg_t tls_cfg = {\n        .alpn_protos = proto,\n        .cacert_buf = cfg->cacert_buf,\n        .cacert_bytes = cfg->cacert_bytes,\n        .keep_alive_cfg = cfg->keep_alive_cfg,\n        .crt_bundle_attach = cfg->crt_bundle_attach,\n        .non_block = true,\n        .timeout_ms = 10 * 1000,\n    };\n\n#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)\n    hd->http2_tls = esp_tls_init();\n    if (!hd->http2_tls) {\n        ESP_LOGE(TAG, \"Failed to allocate esp_tls handle!\");\n        goto error;\n    }\n\n    // NOTE: This API is an alternative to previous `esp_tls_conn_http_new` from ESP-IDF v5.0 onwards.\n    if (esp_tls_conn_http_new_sync(cfg->uri, &tls_cfg, hd->http2_tls) != 1) {\n#else\n    if ((hd->http2_tls = esp_tls_conn_http_new(cfg->uri, &tls_cfg)) == NULL) {\n#endif\n        ESP_LOGE(TAG, \"[sh2-connect] esp-tls connection failed\");\n        goto error;\n    }\n\n    struct http_parser_url u;\n    http_parser_url_init(&u);\n    if (http_parser_parse_url(cfg->uri, strlen(cfg->uri), 0, &u) != 0) {\n        ESP_LOGE(TAG, \"[sh2-connect] Failed to parse URI\");\n        goto error;\n    }\n    if (!(u.field_set & (1 << UF_HOST))) {\n        ESP_LOGE(TAG, \"[sh2-connect] Host field not present in URI\");\n        goto error;\n    }\n    hd->hostname = strndup(&cfg->uri[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len);\n    if (!hd->hostname) {\n        ESP_LOGE(TAG, \"[sh2-connect] Failed to allocate memory for hostname\");\n        goto error;\n    }\n\n    /* HTTP/2 Connection */\n    if (do_http2_connect(hd) != 0) {\n        ESP_LOGE(TAG, \"[sh2-connect] HTTP2 Connection failed with %s\", cfg->uri);\n        goto error;\n    }\n\n    return 0;\nerror:\n    sh2lib_free(hd);\n    return -1;\n}\n\nvoid sh2lib_free(struct sh2lib_handle *hd)\n{\n    if (hd == NULL) {\n        return;\n    }\n\n    if (hd->http2_sess) {\n        nghttp2_session_del(hd->http2_sess);\n        hd->http2_sess = NULL;\n    }\n    if (hd->http2_tls) {\n        esp_tls_conn_destroy(hd->http2_tls);\n        hd->http2_tls = NULL;\n    }\n    if (hd->hostname) {\n        free(hd->hostname);\n        hd->hostname = NULL;\n    }\n}\n\nint sh2lib_execute(struct sh2lib_handle *hd)\n{\n    if (hd == NULL) {\n        ESP_LOGE(TAG, \"[sh2-execute] Invalid argument\");\n        return -1;\n    }\n\n    int ret;\n    ret = sh2lib_execute_send(hd);\n    if (ret != 0) {\n        return ret;\n    }\n\n    ret = sh2lib_execute_recv(hd);\n    if (ret != 0) {\n        return ret;\n    }\n\n    return 0;\n}\n\nint sh2lib_execute_recv(struct sh2lib_handle *hd)\n{\n    if (hd == NULL) {\n        ESP_LOGE(TAG, \"[sh2-execute-recv] Invalid argument\");\n        return -1;\n    }\n\n    int ret = nghttp2_session_recv(hd->http2_sess);\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"[sh2-execute-recv] HTTP2 session recv failed %d\", ret);\n    }\n\n    return ret;\n}\n\nint sh2lib_execute_send(struct sh2lib_handle *hd)\n{\n    if (hd == NULL) {\n        ESP_LOGE(TAG, \"[sh2-execute-send] Invalid argument\");\n        return -1;\n    }\n\n    int ret = nghttp2_session_send(hd->http2_sess);\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"[sh2-execute-send] HTTP2 session send failed %d\", ret);\n    }\n\n    return ret;\n}\n\nint sh2lib_do_get_with_nv(struct sh2lib_handle *hd, const nghttp2_nv *nva, size_t nvlen, sh2lib_frame_data_recv_cb_t recv_cb)\n{\n    if (hd == NULL || (nva == NULL && nvlen > 0)) {\n        ESP_LOGE(TAG, \"[sh2-do-get] Invalid argument\");\n        return -1;\n    }\n\n    int ret = nghttp2_submit_request(hd->http2_sess, NULL, nva, nvlen, NULL, recv_cb);\n    if (ret < 0) {\n        ESP_LOGE(TAG, \"[sh2-do-get] HEADERS call failed %i\", ret);\n    }\n    return ret;\n}\n\nint sh2lib_do_get(struct sh2lib_handle *hd, const char *path, sh2lib_frame_data_recv_cb_t recv_cb)\n{\n    if (hd == NULL || path == NULL || hd->hostname == NULL) {\n        ESP_LOGE(TAG, \"[sh2-do-get] Invalid argument\");\n        return -1;\n    }\n\n    const nghttp2_nv nva[] = { SH2LIB_MAKE_NV(\":method\", \"GET\"),\n                               SH2LIB_MAKE_NV(\":scheme\", \"https\"),\n                               SH2LIB_MAKE_NV(\":authority\", hd->hostname),\n                               SH2LIB_MAKE_NV(\":path\", path),\n                             };\n    return sh2lib_do_get_with_nv(hd, nva, sizeof(nva) / sizeof(nva[0]), recv_cb);\n}\n\nssize_t sh2lib_data_provider_cb(nghttp2_session *session, int32_t stream_id, uint8_t *buf,\n                                size_t length, uint32_t *data_flags,\n                                nghttp2_data_source *source, void *user_data)\n{\n    struct sh2lib_handle *h2 = user_data;\n    sh2lib_putpost_data_cb_t data_cb = source->ptr;\n    return (*data_cb)(h2, (char *)buf, length, data_flags);\n}\n\nint sh2lib_do_putpost_with_nv(struct sh2lib_handle *hd, const nghttp2_nv *nva, size_t nvlen,\n                              sh2lib_putpost_data_cb_t send_cb,\n                              sh2lib_frame_data_recv_cb_t recv_cb)\n{\n    if (hd == NULL || (nva == NULL && nvlen > 0) || send_cb == NULL) {\n        ESP_LOGE(TAG, \"[sh2-do-putpost] Invalid argument\");\n        return -1;\n    }\n\n    nghttp2_data_provider sh2lib_data_provider;\n    sh2lib_data_provider.read_callback = sh2lib_data_provider_cb;\n    sh2lib_data_provider.source.ptr = send_cb;\n    int ret = nghttp2_submit_request(hd->http2_sess, NULL, nva, nvlen, &sh2lib_data_provider, recv_cb);\n    if (ret < 0) {\n        ESP_LOGE(TAG, \"[sh2-do-putpost] HEADERS call failed %i\", ret);\n    }\n    return ret;\n}\n\nint sh2lib_do_post(struct sh2lib_handle *hd, const char *path,\n                   sh2lib_putpost_data_cb_t send_cb,\n                   sh2lib_frame_data_recv_cb_t recv_cb)\n{\n    if (hd == NULL || path == NULL || send_cb == NULL || hd->hostname == NULL) {\n        ESP_LOGE(TAG, \"[sh2-do-post] Invalid argument\");\n        return -1;\n    }\n\n    const nghttp2_nv nva[] = { SH2LIB_MAKE_NV(\":method\", \"POST\"),\n                               SH2LIB_MAKE_NV(\":scheme\", \"https\"),\n                               SH2LIB_MAKE_NV(\":authority\", hd->hostname),\n                               SH2LIB_MAKE_NV(\":path\", path),\n                             };\n    return sh2lib_do_putpost_with_nv(hd, nva, sizeof(nva) / sizeof(nva[0]), send_cb, recv_cb);\n}\n\nint sh2lib_do_put(struct sh2lib_handle *hd, const char *path,\n                  sh2lib_putpost_data_cb_t send_cb,\n                  sh2lib_frame_data_recv_cb_t recv_cb)\n{\n    if (hd == NULL || path == NULL || send_cb == NULL || hd->hostname == NULL) {\n        ESP_LOGE(TAG, \"[sh2-do-put] Invalid argument\");\n        return -1;\n    }\n\n    const nghttp2_nv nva[] = { SH2LIB_MAKE_NV(\":method\", \"PUT\"),\n                               SH2LIB_MAKE_NV(\":scheme\", \"https\"),\n                               SH2LIB_MAKE_NV(\":authority\", hd->hostname),\n                               SH2LIB_MAKE_NV(\":path\", path),\n                             };\n    return sh2lib_do_putpost_with_nv(hd, nva, sizeof(nva) / sizeof(nva[0]), send_cb, recv_cb);\n}\n"
  },
  {
    "path": "sh2lib/sh2lib.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2027-2021 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include <stdbool.h>\n#include \"esp_tls.h\"\n#include <nghttp2/nghttp2.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n * This is a thin API wrapper over nghttp2 that offers simplified APIs for usage\n * in the application. The intention of this wrapper is to act as a stepping\n * stone to quickly get started with using the HTTP/2 client. Since the focus is\n * on simplicity, not all the features of HTTP/2 are supported through this\n * wrapper. Once you are fairly comfortable with nghttp2, feel free to directly\n * use nghttp2 APIs or make changes to sh2lib.c for realising your objectives.\n *\n * TODO:\n * - Allowing to query response code, content-type etc in the receive callback\n * - A simple function for per-stream header callback\n */\n/**\n * @brief Handle for working with sh2lib APIs\n */\nstruct sh2lib_handle {\n    nghttp2_session *http2_sess;   /*!< Pointer to the HTTP2 session handle */\n    char            *hostname;     /*!< The hostname we are connected to */\n    struct esp_tls  *http2_tls;    /*!< Pointer to the TLS session handle */\n    int             http2_tls_rc;  /*!< Error code from http2_tls */\n    bool            http2_goaway;  /*!< HTTP2 server sent GOAWAY */\n};\n\n/**\n * @brief sh2lib configuration structure\n */\nstruct sh2lib_config_t {\n    const char *uri;                    /*!< Pointer to the URI that should be connected to */\n    const unsigned char *cacert_buf;    /*!< Pointer to the buffer containing CA certificate */\n    unsigned int cacert_bytes;          /*!< Size of the CA certifiacte pointed by cacert_buf */\n    esp_err_t (*crt_bundle_attach)(void *conf);\n    /*!< Function pointer to esp_crt_bundle_attach. Enables the use of certification\n         bundle for server verification, must be enabled in menuconfig */\n    tls_keep_alive_cfg_t *keep_alive_cfg;/*!< Enable TCP keep-alive timeout for SSL connection */\n};\n\n/** Flag indicating receive stream is reset */\n#define DATA_RECV_RST_STREAM      1\n/** Flag indicating frame is completely received  */\n#define DATA_RECV_FRAME_COMPLETE  2\n\n/**\n * @brief Function Prototype for data receive callback\n *\n * This function gets called whenever data is received on any stream. The\n * function is also called for indicating events like frame receive complete, or\n * end of stream. The function may get called multiple times as long as data is\n * received on the stream.\n *\n * @param[in] handle     Pointer to the sh2lib handle.\n * @param[in] data       Pointer to a buffer that contains the data received.\n * @param[in] len        The length of valid data stored at the 'data' pointer.\n * @param[in] flags      Flags indicating whether the stream is reset (DATA_RECV_RST_STREAM) or\n *                       this particularly frame is completely received\n *                       DATA_RECV_FRAME_COMPLETE).\n *\n * @return The function should return 0\n */\ntypedef int (*sh2lib_frame_data_recv_cb_t)(struct sh2lib_handle *handle, const char *data, size_t len, int flags);\n\n/**\n * @brief Function Prototype for callback to send data in PUT/POST\n *\n * This function gets called whenever nghttp2 wishes to send data, like for\n * PUT/POST requests to the server. The function keeps getting called until this\n * function sets the flag NGHTTP2_DATA_FLAG_EOF to indicate end of data.\n *\n * @param[in] handle       Pointer to the sh2lib handle.\n * @param[out] data        Pointer to a buffer that should contain the data to send.\n * @param[in] len          The maximum length of data that can be sent out by this function.\n * @param[out] data_flags  Pointer to the data flags. The NGHTTP2_DATA_FLAG_EOF\n *                         should be set in the data flags to indicate end of new data.\n *\n * @return The function should return the number of valid bytes stored in the\n * data pointer\n */\ntypedef int (*sh2lib_putpost_data_cb_t)(struct sh2lib_handle *handle, char *data, size_t len, uint32_t *data_flags);\n\n/**\n * @brief Connect to a URI using HTTP/2\n *\n * This API opens an HTTP/2 connection with the provided URI. If successful, the\n * hd pointer is populated with a valid handle for subsequent communication.\n *\n * Only 'https' URIs are supported.\n *\n * @param[in]  cfg     Pointer to the sh2lib configurations of the type 'struct sh2lib_config_t'.\n * @param[out] hd      Pointer to a variable of the type 'struct sh2lib_handle'.\n * @return\n *             - 0 if the connection was successful\n *             - -1 if the connection fails\n */\nint sh2lib_connect(struct sh2lib_config_t *cfg, struct sh2lib_handle *hd);\n\n/**\n * @brief Free a sh2lib handle\n *\n * This API frees-up an sh2lib handle, thus closing any open connections that\n * may be associated with this handle, and freeing up any resources.\n *\n * @param[in] hd      Pointer to a variable of the type 'struct sh2lib_handle'.\n *\n */\nvoid sh2lib_free(struct sh2lib_handle *hd);\n\n/**\n * @brief Setup an HTTP GET request stream\n *\n * This API sets up an HTTP GET request to be sent out to the server. A new\n * stream is created for handling the request. Once the request is setup, the\n * API sh2lib_execute() must be called to actually perform the socket I/O with\n * the server.\n *\n * @param[in] hd        Pointer to a variable of the type 'struct sh2lib_handle'.\n * @param[in] path      Pointer to the string that contains the resource to\n *                      perform the HTTP GET operation on (for example, /users).\n * @param[in] recv_cb   The callback function that should be called for\n *                      processing the request's response\n *\n * @return\n *             - Stream ID (positive integer) if request setup is successful\n *             - Negative error code if the request setup fails\n */\nint sh2lib_do_get(struct sh2lib_handle *hd, const char *path, sh2lib_frame_data_recv_cb_t recv_cb);\n\n/**\n * @brief Setup an HTTP POST request stream\n *\n * This API sets up an HTTP POST request to be sent out to the server. A new\n * stream is created for handling the request. Once the request is setup, the\n * API sh2lib_execute() must be called to actually perform the socket I/O with\n * the server.\n *\n * @param[in] hd        Pointer to a variable of the type 'struct sh2lib_handle'.\n * @param[in] path      Pointer to the string that contains the resource to\n *                      perform the HTTP POST operation on (for example, /users).\n * @param[in] send_cb   The callback function that should be called for\n *                      sending data as part of this request.\n * @param[in] recv_cb   The callback function that should be called for\n *                      processing the request's response\n *\n * @return\n *             - Stream ID (positive integer) if request setup is successful\n *             - Negative error code if the request setup fails\n */\nint sh2lib_do_post(struct sh2lib_handle *hd, const char *path,\n                   sh2lib_putpost_data_cb_t send_cb,\n                   sh2lib_frame_data_recv_cb_t recv_cb);\n\n/**\n * @brief Setup an HTTP PUT request stream\n *\n * This API sets up an HTTP PUT request to be sent out to the server. A new\n * stream is created for handling the request. Once the request is setup, the\n * API sh2lib_execute() must be called to actually perform the socket I/O with\n * the server.\n *\n * @param[in] hd        Pointer to a variable of the type 'struct sh2lib_handle'.\n * @param[in] path      Pointer to the string that contains the resource to\n *                      perform the HTTP PUT operation on (for example, /users).\n * @param[in] send_cb   The callback function that should be called for\n *                      sending data as part of this request.\n * @param[in] recv_cb   The callback function that should be called for\n *                      processing the request's response\n *\n * @return\n *             - Stream ID (positive integer) if request setup is successful\n *             - Negative error code if the request setup fails\n */\nint sh2lib_do_put(struct sh2lib_handle *hd, const char *path,\n                  sh2lib_putpost_data_cb_t send_cb,\n                  sh2lib_frame_data_recv_cb_t recv_cb);\n\n/**\n * @brief Execute send/receive on an HTTP/2 connection\n *\n * While the API sh2lib_do_get(), sh2lib_do_post() setup the requests to be\n * initiated with the server, this API performs the actual data send/receive\n * operations on the HTTP/2 connection. The callback functions are accordingly\n * called during the processing of these requests.\n *\n * @param[in] hd      Pointer to a variable of the type 'struct sh2lib_handle'\n *\n * @return\n *             - 0 if it succeeds\n *             - Negative error code from nghttp2 on failure\n */\nint sh2lib_execute(struct sh2lib_handle *hd);\n\n/**\n * @brief Execute receive on an HTTP/2 connection\n *\n * While the API sh2lib_do_get(), sh2lib_do_post() setup the requests to be\n * initiated with the server, this API performs the actual data send/receive\n * operations on the HTTP/2 connection. The callback functions are accordingly\n * called during the processing of these requests.\n *\n * @param[in] hd      Pointer to a variable of the type 'struct sh2lib_handle'\n *\n * @return\n *             - 0 if it succeeds\n *             - Negative error code from nghttp2 on failure\n */\nint sh2lib_execute_recv(struct sh2lib_handle *hd);\n\n/**\n * @brief Execute send on an HTTP/2 connection\n *\n * While the API sh2lib_do_get(), sh2lib_do_post() setup the requests to be\n * initiated with the server, this API performs the actual data send/receive\n * operations on the HTTP/2 connection. The callback functions are accordingly\n * called during the processing of these requests.\n *\n * @param[in] hd      Pointer to a variable of the type 'struct sh2lib_handle'\n *\n * @return\n *             - 0 if it succeeds\n *             - Negative error code from nghttp2 on failure\n */\nint sh2lib_execute_send(struct sh2lib_handle *hd);\n\n#define SH2LIB_MAKE_NV(NAME, VALUE)                                    \\\n  {                                                                    \\\n    (uint8_t *)NAME, (uint8_t *)VALUE, strlen(NAME), strlen(VALUE),    \\\n        NGHTTP2_NV_FLAG_NONE                                           \\\n  }\n\n/**\n * @brief Setup an HTTP GET request stream with custom name-value pairs\n *\n * For a simpler version of the API, please refer to sh2lib_do_get().\n *\n * This API sets up an HTTP GET request to be sent out to the server. A new\n * stream is created for handling the request. Once the request is setup, the\n * API sh2lib_execute() must be called to actually perform the socket I/O with\n * the server.\n *\n * Please note that the following name value pairs MUST be a part of the request\n *     -  name:value\n *     -  \":method\":\"GET\"\n *     -  \":scheme\":\"https\"\n *     -  \":path\":<the-path-for-the-GET-operation>  (for example, /users)\n *\n * @param[in] hd        Pointer to a variable of the type 'struct sh2lib_handle'.\n * @param[in] nva       An array of name-value pairs that should be part of the request.\n * @param[in] nvlen     The number of elements in the array pointed to by 'nva'.\n * @param[in] recv_cb   The callback function that should be called for\n *                      processing the request's response\n *\n * @return\n *             - Stream ID (positive integer) if request setup is successful\n *             - Negative error code if the request setup fails\n */\nint sh2lib_do_get_with_nv(struct sh2lib_handle *hd, const nghttp2_nv *nva, size_t nvlen, sh2lib_frame_data_recv_cb_t recv_cb);\n\n/**\n * @brief Setup an HTTP PUT/POST request stream with custom name-value pairs\n *\n * For a simpler version of the API, please refer to sh2lib_do_put() or\n * sh2lib_do_post().\n *\n * This API sets up an HTTP PUT/POST request to be sent out to the server. A new\n * stream is created for handling the request. Once the request is setup, the\n * API sh2lib_execute() must be called to actually perform the socket I/O with\n * the server.\n *\n * Please note that the following name value pairs MUST be a part of the request\n *     -  name:value\n *     -  \":method\":\"PUT\" (or POST)\n *     -  \":scheme\":\"https\"\n *     -  \":path\":<the-path-for-the-PUT-operation>  (for example, /users)\n *\n * @param[in] hd        Pointer to a variable of the type 'struct sh2lib_handle'.\n * @param[in] nva       An array of name-value pairs that should be part of the request.\n * @param[in] nvlen     The number of elements in the array pointed to by 'nva'.\n * @param[in] send_cb   The callback function that should be called for\n *                      sending data as part of this request.\n * @param[in] recv_cb   The callback function that should be called for\n *                      processing the request's response\n *\n * @return\n *             - Stream ID (positive integer) if request setup is successful\n *             - Negative error code if the request setup fails\n */\nint sh2lib_do_putpost_with_nv(struct sh2lib_handle *hd, const nghttp2_nv *nva, size_t nvlen,\n                              sh2lib_putpost_data_cb_t send_cb,\n                              sh2lib_frame_data_recv_cb_t recv_cb);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "spi_nand_flash/CHANGELOG.md",
    "content": "# Changelog\n\nVersioning policy: see [VERSIONING.md](VERSIONING.md). From **v1.0.0** onward this component follows [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html).\n\n## [1.0.2]\n### Fixes\n- BDL error logging: correct format specifiers for size fields on 64-bit Linux (avoids undefined behavior and wrong log output).\n- Linux NAND emulation: OOB markers and free-page detection aligned with the real hardware path.\n- Linux mmap: correct backing file path selection for the emulated image.\n- Linux mmap layout: on-disk stride accounts for interleaved OOB vs user-visible erase block size (bad-block handling, erase, and OOB clearing).\n\n### Documentation\n- Linux mmap emulator config: note how backing file size maps to interleaved OOB and reported user capacity.\n\n### Testing\n- Linux host tests: broader FTL and BDL coverage.\n- Shared buffer pattern helpers (including seeded patterns) for host tests and the in-tree test application.\n\n## [1.0.1]\n- fix: fix incorrect flash geometry parameter for flash GD5F4GM8xExxG\n\n## [1.0.0]\n### Breaking Changes\n- FATFS integration has been moved to a separate `spi_nand_flash_fatfs` component. Projects using FATFS with NAND flash must add `spi_nand_flash_fatfs` as a dependency. FatFs on SPI NAND still requires the **legacy** init path: keep **`CONFIG_NAND_FLASH_ENABLE_BDL` disabled** for that use case (no FatFs-on-BDL support in this release).\n- When `CONFIG_NAND_FLASH_ENABLE_BDL` is enabled, the legacy `spi_nand_flash_init_device()` returns `ESP_ERR_NOT_SUPPORTED`. Use `spi_nand_flash_init_with_layers()` instead for block-device consumers.\n- `spi_nand_erase_chip()` performs a physical full-media erase. Previously, the driver incorrectly attempted to erase every block without checking bad-block markers, which could erase factory-marked bad blocks. It now skips bad blocks and physically erases only blocks that are not marked bad.\n\n### New Features\n- Added Block Device Layer (BDL) support, available from ESP-IDF v6.0. Provides standard `esp_blockdev_t` interfaces for both raw flash access and wear-leveling.\n- Added `spi_nand_flash_init_with_layers()` API for layered block device initialization.\n- Added page-based API terminology (`read_page`, `write_page`, `get_page_count`, `get_page_size`) with backward-compatible sector aliases.\n\n### Improvements\n- Refactor the component for improved structure, maintainability and readability\n- Sector API functions are now deprecated aliases for the page API equivalents.\n\n**Migration:** See **Migration Guide (0.x → 1.0.0)** in [layered_architecture.md](layered_architecture.md).\n\n## [0.21.0]\n- fix: spi_nand_read fails in case buffer is not DMA aligned (https://github.com/espressif/idf-extra-components/issues/708)\n\n## [0.20.0]\n- feat: added support for Gigadevice (GD5F1GM7xExxG) NAND flash\n\n## [0.19.0]\n- fix: spi_nand_program_load fails in case buffer is not DMA aligned (https://github.com/espressif/idf-extra-components/issues/684)\n\n## [0.18.0]\n- fix: Update esp_vfs_fat_register prototype to esp_vfs_fat_register_cfg to align with ESP-IDF v6.0. The cfg version is now the primary API and remains aliased for compatibility.\n\n## [0.17.0] \n- fix: fix a compilation error caused by the missing freertos/FreeRTOS.h header when building with ESP-IDF v6.0 and later.\n- update: improvements to the lower-level APIs following updates in esp_driver_spi.\n\n## [0.16.0]\n- fix: fix nand flash issue caused by data length unalignment on esp32p4\n\n## [0.15.0]\n- feat: added support for Gigadevice (GD5F2GM7xExxG) NAND flash\n\n## [0.14.0]\n- feat: added support for XTX (XT26G08D) and Gigadevice (GD5F4GM8) NAND flash\n\n## [0.13.0]\n- feat: added support for Zetta (ZD35Q1GC) NAND flash\n        and Winbond (W25N02KVxxIR/U, W25N04KVxxIR/U) NAND flash chips.\n\n## [0.12.0]\n- feat: added micron dual-plane nand flash chip (MT29F2G) support\n- fix: fixed build failure in host tests\n\n## [0.11.0]\n- feat: added QIO mode support\n\n## [0.10.0]\n- feat: added support for standard SPI mode (full-duplex) and DIO mode\n\n## [0.9.0]\n- feat: added linux target support\n- fix: fixed memory alignment issue occurring on esp32c3\n\n## [0.8.0]\n- feat: added diagnostics application\n\n## [0.7.0]\n- feat: exposed lower-level API and make it usable without dhara library\n\n## [0.6.0]\n- feat: implemented CTRL_TRIM in fatfs diskio layer\n- feat: added data refresh threshold for ECC correction\n\n## [0.5.0]\n- feat: added Kconfig option to verify write operations\n- feat: added support for Micron MT29F1G01ABAFDSF-AAT:F\n\n## [0.4.1]\n- update: handled alignment and DMA requirements for work buffers\n\n## [0.4.0]\n- fix: fixed memory leaks in test, add performance log\n\n## [0.3.1]\n- fix: correct calloc call arguments for GCC14 compat\n\n## [0.3.0]\n- fix: use 32 bit sector size and id\n\n## [0.2.0]\n- feat: added support for Micron MT29F nand flash\n\n## [0.1.0]\n- Initial release with basic NAND flash support based on dhara nand library\n- Support for Winbond, Alliance and Gigadevice devices\n- Added test application for the same\n\n"
  },
  {
    "path": "spi_nand_flash/CMakeLists.txt",
    "content": "idf_build_get_property(target IDF_TARGET)\n\nset(reqs)\nset(inc include)\nset(priv_inc priv_include)\nset(srcs \"src/nand.c\"\n         \"src/dhara_glue.c\"\n         \"src/nand_impl_wrap.c\")\n\nif(\"${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}\" GREATER_EQUAL \"6.0\")\n    list(APPEND reqs esp_blockdev)\n    if(CONFIG_NAND_FLASH_ENABLE_BDL)\n        list(APPEND srcs \"src/nand_flash_blockdev.c\"\n                         \"src/nand_wl_blockdev.c\")\n    endif()\nendif()\n\nif(${target} STREQUAL \"linux\")\n    list(APPEND srcs \"src/nand_impl_linux.c\"\n                     \"src/nand_linux_mmap_emul.c\"\n                     \"src/spi_nand_flash_test_helpers.c\")\nelse()\n    list(APPEND srcs \"src/devices/nand_winbond.c\"\n                     \"src/devices/nand_gigadevice.c\"\n                     \"src/devices/nand_alliance.c\"\n                     \"src/devices/nand_micron.c\"\n                     \"src/devices/nand_zetta.c\"\n                     \"src/devices/nand_xtx.c\"\n                     \"src/nand_impl.c\"\n                     \"src/nand_diag_api.c\"\n                     \"src/spi_nand_flash_test_helpers.c\"\n                     \"src/spi_nand_oper.c\")\n    \n    set(priv_reqs esp_mm)\n    \n    if(\"${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}\" VERSION_GREATER \"5.3\")\n        list(APPEND reqs esp_driver_spi)\n    else()\n        list(APPEND reqs driver)\n    endif()\nendif()\n\n\nidf_component_register(SRCS ${srcs}\n        INCLUDE_DIRS ${inc}\n        PRIV_INCLUDE_DIRS ${priv_inc}\n        REQUIRES ${reqs}\n        PRIV_REQUIRES ${priv_reqs})\n"
  },
  {
    "path": "spi_nand_flash/Kconfig",
    "content": "menu \"SPI NAND Flash configuration\"\n\n    config NAND_FLASH_VERIFY_WRITE\n        bool \"Verify SPI NAND flash writes\"\n        default n\n        help\n            If this option is enabled, any time SPI NAND flash is written then the data will be read\n            back and verified. This can catch hardware problems with SPI NAND flash, or flash which\n            was not erased before verification.\n\n    config NAND_FLASH_ENABLE_BDL\n        bool \"Enable Block Device Layer (BDL) support\"\n        depends on IDF_INIT_VERSION >= \"6.0\"\n        default n\n        help\n            Enable Block Device Layer (BDL) support for SPI NAND Flash. This provides:\n            - Standard esp_blockdev_t interface for layered architecture\n            - Flash Block Device Layer (raw NAND flash access)\n            - Wear-Leveling Block Device Layer (logical sector access with wear leveling)\n            - Advanced layered API (spi_nand_flash_init_with_layers)\n            When disabled, only the legacy API is available.\n            When enabled, the legacy spi_nand_flash_init_device() is not available (returns\n            ESP_ERR_NOT_SUPPORTED). Use spi_nand_flash_init_with_layers().\n\n            Note: This option requires ESP-IDF >= 6.0 (esp_blockdev component).\n            Enabling this on ESP-IDF < 6.0 will result in a build error.\n\n    config NAND_ENABLE_STATS\n        bool \"Host test statistics enabled\"\n        depends on IDF_TARGET_LINUX\n        default n\n        help\n            This option enables gathering host test statistics and SPI NAND flash wear levelling simulation.\n\nendmenu\n"
  },
  {
    "path": "spi_nand_flash/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "spi_nand_flash/README.md",
    "content": "# SPI NAND Flash Driver\n\nThis driver is designed to support SPI NAND Flash with ESP chipsets.\n\nThis component incorporates the [dhara library](https://github.com/dlbeer/dhara), licenced under the [LICENCE](https://github.com/dlbeer/dhara/blob/master/LICENSE)\n\n## About SPI NAND Flash\nSPI NAND Flash combines the benefits of NAND Flash technology with the simplicity of the SPI interface, providing an efficient and cost-effective solution for non-volatile data storage in diverse applications. Its versatility, reliability, and affordability make it a popular choice for many embedded systems and electronic devices.\n\n### Key Features:\n* Non-Volatile Storage: SPI NAND Flash provides non-volatile storage, retaining data even when power is removed. This characteristic makes it ideal for storing critical system information and application data.\n\n* SPI Interface: The SPI protocol allows for straightforward communication between the microcontroller and the NAND Flash. This simplicity in interface design facilitates easy integration into embedded systems.\n\n* Cost-Effective: SPI NAND Flash offers a cost-effective storage solution, making it attractive for applications with budget constraints. Its competitive pricing makes it a viable option for a wide range of projects.\n\n* High Density: NAND Flash technology inherently supports high-density storage, enabling the storage of large amounts of data in a compact form factor. This is advantageous for applications requiring extensive data storage in constrained spaces.\n\n* Fast Read/Write Operations: The SPI interface enables reasonably fast read and write operations, making it suitable for applications where data access speed is crucial.\n\n### Implementation Architecture\n\nThe component now features a layered architecture for better maintainability and modularity:\n\n```mermaid\ngraph TD\n    A[Application/FS] --> B[SPI NAND Flash API]\n    B --> C[NAND Wear-Leveling BDL]\n    C --> D[NAND Flash BDL] \n    D --> E{Target}\n    E -->|ESP Chips| F[SPI NAND Operations]\n    F --> G[Hardware via SPI]\n    E -->|Linux| H[NAND Emulation]\n    H --> I[Memory-Mapped File]\n    \n    subgraph \"Layered Architecture\"\n        B[\"spi_nand_flash.h<br/>(Backward Compatible)\"]\n        C[\"nand_wl_bdl<br/>(Wear Leveling)\"]\n        D[\"nand_flash_bdl<br/>(Physical Flash)\"]\n    end\n    \n    subgraph \"Hardware Layer\"\n        F[\"spi_nand_oper<br/>(SPI Commands)\"]\n        H[\"nand_linux_mmap_emul<br/>(Host Test)\"]\n    end\n```\n\n**Key Benefits:**\n- **Backward Compatible**: Existing code works unchanged; sector-named APIs are retained as aliases of the page API\n- **Page terminology**: Public API uses *page* (read_page, write_page, get_page_count, get_page_size) to align with NAND flash; sector names remain for compatibility\n- **Modular Design**: Clear separation between wear-leveling and flash management\n- **Enhanced Features**: Direct access to flash and wear-leveling layers\n\n**📖 Architecture and migration:**\nFor layered architecture, BDL usage, API details, and **upgrading from 0.x to 1.0.0** (including the FATFS component split and legacy vs BDL init), see:\n- [Layered Architecture Guide](layered_architecture.md) — includes the **Migration Guide (0.x → 1.0.0)** section\n\n## ESP-IDF version and API modes\n\n- **ESP-IDF 5.0–5.x:** Use the **legacy** API only (`spi_nand_flash_init_device()`, page/sector helpers). The BDL Kconfig option is not available on these IDF versions. Component **1.0.0** remains compatible with this range when BDL is not used.\n- **ESP-IDF 6.0 and newer:** You may enable **`CONFIG_NAND_FLASH_ENABLE_BDL`** and use **`spi_nand_flash_init_with_layers()`** with **`esp_blockdev_t`** for block-device consumers. If BDL is **disabled**, the legacy API behaves as on older IDF versions.\n\n**Linux mmap emulation (host tests):** On the Linux target, the driver can use a memory-mapped backing file instead of SPI hardware. Configuration examples and how to build the host test app live in [`host_test/README.md`](host_test/README.md).\n\n## Supported SPI NAND Flash chips\n\nAt present, `spi_nand_flash` component is compatible with the chips produced by the following manufacturers and and their respective model numbers:\n\n* Winbond - W25N01GVxxxG/T/R, W25N512GVxIG/IT, W25N512GWxxR/T, W25N01JWxxxG/T, W25N02KVxxIR/U, W25N04KVxxIR/U\n* Gigadevice -  GD5F1GQ5UExxG, GD5F1GQ5RExxG, GD5F2GQ5UExxG, GD5F2GQ5RExxG, GD5F2GM7xExxG, GD5F4GQ6UExxG, GD5F4GQ6RExxG, GD5F4GM8xExxG, GD5F1GM7xExxG\n* Alliance - AS5F31G04SND-08LIN, AS5F32G04SND-08LIN, AS5F12G04SND-10LIN, AS5F34G04SND-08LIN, AS5F14G04SND-10LIN, AS5F38G04SND-08LIN, AS5F18G04SND-10LIN\n* Micron - MT29F4G01ABAFDWB, MT29F1G01ABAFDSF-AAT:F, MT29F2G01ABAGDWB-IT:G\n* Zetta - ZD35Q1GC\n* XTX - XT26G08D\n\n## FATFS Integration\n\nFor FATFS filesystem support, use the separate [`spi_nand_flash_fatfs`](../spi_nand_flash_fatfs) component:\n- Provides diskio adapters and VFS mount helpers for the **legacy** `spi_nand_flash_device_t` path only\n- **Do not enable BDL** if you use this FatFs stack on the same NAND instance (see [`spi_nand_flash_fatfs/README.md`](../spi_nand_flash_fatfs/README.md))\n\n## Troubleshooting\n\nTo verify SPI NAND Flash writes, enable the `NAND_FLASH_VERIFY_WRITE` option in menuconfig. When this option is enabled, every time data is written to the SPI NAND Flash, it will be read back and verified. This helps in identifying hardware issues with the SPI NAND Flash.\n\nTo configure the project for this setting, follow these steps:\n\n```\nidf.py menuconfig\n-> Component config\n-> SPI NAND Flash configuration\n-> NAND_FLASH_VERIFY_WRITE\n```\n\nRun `idf.py -p PORT flash monitor` and if the write verification fails, an error log will be printed to the console.\n"
  },
  {
    "path": "spi_nand_flash/VERSIONING.md",
    "content": "# Versioning\n\nFrom **v1.0.0** onward, this component follows **[Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html)**. The published version is the `version` field in [`idf_component.yml`](idf_component.yml).\n\n## Summary\n\n| Level   | When to bump |\n|--------|----------------|\n| **MAJOR** | Breaking changes for integrators: removed or incompatible APIs, required migration, or other incompatible contract changes called out under **Breaking Changes** in [`CHANGELOG.md`](CHANGELOG.md). |\n| **MINOR** | Backward-compatible additions: new APIs, new supported devices or modes, new optional Kconfig (default preserves prior behavior). |\n| **PATCH** | Backward-compatible fixes only: bug fixes, documentation corrections, tests, or build/CI changes that do not widen the public API or break existing callers. |\n\nPre-**1.0.0** releases (`0.x.y` in the changelog) did not consistently apply this split; treat them as historical versioning. Use **1.x.y** and the rules above for current releases.\n"
  },
  {
    "path": "spi_nand_flash/host_test/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\n\nproject(nand_flash_host_test)\n"
  },
  {
    "path": "spi_nand_flash/host_test/README.md",
    "content": "| Supported Targets | Linux |\n| ----------------- | ----- |\n\n# Host Test for SPI NAND Flash Emulation\n\nLinux host tests use the mmap-backed NAND emulator (`nand_linux_mmap_emul`). Full field semantics (including how OOB is interleaved in the backing file and how that affects usable capacity) are documented on `nand_file_mmap_emul_config_t` in [`nand_linux_mmap_emul.h`](../include/nand_linux_mmap_emul.h).\n\n## NAND Flash Emulation Configuration\n\nThe NAND flash emulation can be configured using the `nand_file_mmap_emul_config_t` structure:\n\n```c\n#include \"nand_linux_mmap_emul.h\"\n\n// Configuration structure for NAND emulation\nnand_file_mmap_emul_config_t cfg = {\n    .flash_file_name = \"\",                  // Empty string for temporary file, or specify path\n    .flash_file_size = EMULATED_NAND_SIZE,  // Default is 128MB\n    .keep_dump = true                       // true to keep file after tests\n};\n```\n\n### Configuration Options:\n\n1. **flash_file_name**:\n   - Empty string (\"\") - Creates temporary file with pattern \"/tmp/idf-nand-XXXXXX\"\n   - Custom path - Creates file at specified location\n   - Maximum length: 256 characters\n\n2. **flash_file_size**:\n   - Default: `EMULATED_NAND_SIZE` (128MB)\n   - Must be a multiple of the chip's **user-visible** erase-block size (`page_size * pages_per_block`). The on-disk image is larger per page because OOB bytes are interleaved after each page; see the struct documentation in `nand_linux_mmap_emul.h`.\n\n3. **keep_dump**:\n   - true: Keeps the memory-mapped file on disk after testing (for debugging or data persistence)\n   - false: Removes the backing file on cleanup\n\n### Usage Example:\n\n#### Option 1: Direct Device API\n```c\n#include \"nand_linux_mmap_emul.h\"\n#include \"spi_nand_flash.h\"\n\n// Initialize with custom settings\nnand_file_mmap_emul_config_t cfg = {\n    .flash_file_name = \"/tmp/my_nand.bin\",\n    .flash_file_size = 50 * 1024 * 1024,  // 50MB\n    .keep_dump = false\n};\nspi_nand_flash_config_t nand_flash_config = {&cfg, 0, SPI_NAND_IO_MODE_SIO, 0};\n\n// Initialize NAND flash with emulation\nspi_nand_flash_device_t *handle;\nspi_nand_flash_init_device(&nand_flash_config, &handle);\n\n// Use direct NAND operations (page API preferred; sector API is also supported)\nuint32_t page_size;\nspi_nand_flash_get_page_size(handle, &page_size);\nuint8_t *buffer = malloc(page_size);\nuint32_t page_id = 0;\nspi_nand_flash_read_page(handle, buffer, page_id);\nspi_nand_flash_write_page(handle, buffer, page_id);\n\n// Cleanup\nspi_nand_flash_deinit_device(handle);\n```\n\n#### Option 2: Block Device API\n\nRequires **ESP-IDF 6.0+** with **`CONFIG_NAND_FLASH_ENABLE_BDL`** enabled (same as on-target BDL tests).\n\n```c\n#include \"nand_linux_mmap_emul.h\"\n#include \"spi_nand_flash.h\"\n#include \"esp_nand_blockdev.h\"\n\n// Initialize with block device interface\nnand_file_mmap_emul_config_t cfg = {\"\", 50 * 1024 * 1024, false};\nspi_nand_flash_config_t nand_flash_config = {&cfg, 0, SPI_NAND_IO_MODE_SIO, 0};\n\nesp_blockdev_handle_t nand_bdl;\n\n// Create Flash Block Device Layer\nnand_flash_get_blockdev(&nand_flash_config, &nand_bdl);\n\n// Use block device operations\nuint32_t page_size = nand_bdl->geometry.read_size;  // BDL geometry uses page size\nnand_bdl->ops->read(nand_bdl, buffer, page_size, offset, size);\nnand_bdl->ops->write(nand_bdl, buffer, offset, size);\n\n// Cleanup\nnand_bdl->ops->release(nand_bdl);\n```\n\n## Building and running\n\nFrom this directory (with ESP-IDF environment loaded):\n\n```bash\nidf.py --preview set-target linux\nidf.py build monitor\n```\n\nCatch2-based suites are selected from `test_app_main.cpp` according to Kconfig (see the **Linux Host Testing** section in [`layered_architecture.md`](../layered_architecture.md)): legacy raw/device tests vs BDL-enabled sources such as `test_nand_flash_bdl.cpp` and `test_nand_flash_ftl.cpp`.\n"
  },
  {
    "path": "spi_nand_flash/host_test/main/CMakeLists.txt",
    "content": "set(src \"test_app_main.cpp\")\n\nif(CONFIG_NAND_FLASH_ENABLE_BDL)\n    list(APPEND src \"test_nand_flash_bdl.cpp\")\nelse()\n    list(APPEND src  \"test_nand_flash.cpp\" \"test_nand_flash_ftl.cpp\")\nendif()\n\nidf_component_register(SRCS ${src}\n                       WHOLE_ARCHIVE\n                       )\n\ntarget_link_libraries(${COMPONENT_LIB} PRIVATE Catch2WithMain)\n"
  },
  {
    "path": "spi_nand_flash/host_test/main/idf_component.yml",
    "content": "dependencies:\n  espressif/catch2: \"^3.4.0\"\n  espressif/spi_nand_flash:\n    version: '*'\n    override_path: '../../'\n"
  },
  {
    "path": "spi_nand_flash/host_test/main/test_app_main.cpp",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <catch2/catch_session.hpp>\n#include <catch2/catch_test_macros.hpp>\n\n\nextern \"C\" void app_main(void)\n{\n    int argc = 1;\n    const char *argv[2] = {\n        \"target_test_main\",\n        NULL\n    };\n\n    auto result = Catch::Session().run(argc, argv);\n    if (result != 0) {\n        printf(\"Test failed with result %d\\n\", result);\n    } else {\n        printf(\"Test passed.\\n\");\n    }\n    fflush(stdout);\n    exit(result);\n}\n"
  },
  {
    "path": "spi_nand_flash/host_test/main/test_nand_flash.cpp",
    "content": "/*\n * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <string.h>\n\n#include \"spi_nand_flash.h\"\n#include \"spi_nand_flash_test_helpers.h\"\n#include \"nand_linux_mmap_emul.h\"\n#include \"nand_private/nand_impl_wrap.h\"\n\n#include <catch2/catch_test_macros.hpp>\n\nTEST_CASE(\"verify mark_bad_block works\", \"[spi_nand_flash]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 50 * 1024 * 1024, true};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    spi_nand_flash_device_t *device_handle;\n    REQUIRE(spi_nand_flash_init_device(&nand_flash_config, &device_handle) == ESP_OK);\n\n    uint32_t block_num;\n    REQUIRE(spi_nand_flash_get_block_num(device_handle, &block_num) == 0);\n\n    uint32_t test_block = 15;\n    REQUIRE((test_block < block_num) == true);\n\n    bool is_bad_status = false;\n    // Verify if test_block is not bad block\n    REQUIRE(nand_wrap_is_bad(device_handle, test_block, &is_bad_status) == 0);\n    REQUIRE(is_bad_status == false);\n    // mark test_block as a bad block\n    REQUIRE(nand_wrap_mark_bad(device_handle, test_block) == 0);\n    // Verify if test_block is marked as bad block\n    REQUIRE(nand_wrap_is_bad(device_handle, test_block, &is_bad_status) == 0);\n    REQUIRE(is_bad_status == true);\n\n    spi_nand_flash_deinit_device(device_handle);\n}\n\nTEST_CASE(\"verify nand_prog, nand_read, nand_copy, nand_is_free works\", \"[spi_nand_flash]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 50 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    spi_nand_flash_device_t *device_handle;\n    REQUIRE(spi_nand_flash_init_device(&nand_flash_config, &device_handle) == ESP_OK);\n\n    uint32_t sector_num, sector_size, block_size;\n    REQUIRE(spi_nand_flash_get_capacity(device_handle, &sector_num) == 0);\n    REQUIRE(spi_nand_flash_get_sector_size(device_handle, &sector_size) == 0);\n    REQUIRE(spi_nand_flash_get_block_size(device_handle, &block_size) == 0);\n\n    uint8_t *pattern_buf = (uint8_t *)malloc(sector_size);\n    REQUIRE(pattern_buf != NULL);\n    uint8_t *temp_buf = (uint8_t *)malloc(sector_size);\n    REQUIRE(temp_buf != NULL);\n\n    spi_nand_flash_fill_buffer(pattern_buf, sector_size / sizeof(uint32_t));\n\n    bool is_page_free = true;\n    uint32_t test_block = 20;\n    uint32_t test_page = test_block * (block_size / sector_size); //(block_num * pages_per_block)\n    uint32_t dst_page = test_page + 1;\n\n    REQUIRE((test_page < sector_num) == true);\n\n    // Verify if test_page is free\n    REQUIRE(nand_wrap_is_free(device_handle, test_page, &is_page_free) == 0);\n    REQUIRE(is_page_free == true);\n    // Write/program test_page\n    REQUIRE(nand_wrap_prog(device_handle, test_page, pattern_buf) == 0);\n    // Verify if test_page is used/programmed\n    REQUIRE(nand_wrap_is_free(device_handle, test_page, &is_page_free) == 0);\n    REQUIRE(is_page_free == false);\n\n    REQUIRE(nand_wrap_read(device_handle, test_page, 0, sector_size, temp_buf) == 0);\n    REQUIRE(spi_nand_flash_check_buffer(temp_buf, sector_size / sizeof(uint32_t)) == 0);\n\n    REQUIRE(nand_wrap_copy(device_handle, test_page, dst_page) == 0);\n\n    REQUIRE(nand_wrap_read(device_handle, dst_page, 0, sector_size, temp_buf) == 0);\n    REQUIRE(spi_nand_flash_check_buffer(temp_buf, sector_size / sizeof(uint32_t)) == 0);\n\n    free(pattern_buf);\n    free(temp_buf);\n    spi_nand_flash_deinit_device(device_handle);\n}\n"
  },
  {
    "path": "spi_nand_flash/host_test/main/test_nand_flash_bdl.cpp",
    "content": "/*\n * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <cstdlib>\n\n#include \"spi_nand_flash.h\"\n#include \"spi_nand_flash_test_helpers.h\"\n#include \"nand_linux_mmap_emul.h\"\n#include \"esp_blockdev.h\"\n#include \"esp_nand_blockdev.h\"\n\n#include <catch2/catch_test_macros.hpp>\n\n/* Linux mmap file: each page is k_page data + k_oob, so the file uses k_ppb * (k_page + k_oob)\n * bytes per erase block. chip.block_size is k_ppb * k_page (same as real chips); num_blocks\n * is file_size / (k_ppb * (k_page + k_oob)). BDL disk_size must be num_blocks * chip.block_size.\n * Regression: storing the file stride in chip.block_size broke BDL erase decode. */\nTEST_CASE(\"BDL geometry matches Linux mmap file and chip.block_size\", \"[spi_nand_flash][bdl]\")\n{\n    constexpr uint32_t k_file_bytes = 16u * 1024u * 1024u;\n    constexpr uint32_t k_page = 2048u;\n    constexpr uint32_t k_oob = 64u;\n    constexpr uint32_t k_ppb = 64u;\n    const uint32_t file_bytes_per_physical_block = k_ppb * (k_page + k_oob);\n    const uint32_t bdl_bytes_per_erase_block = k_ppb * k_page;\n    const uint32_t num_physical_blocks = k_file_bytes / file_bytes_per_physical_block;\n    const uint64_t expected_disk_size = (uint64_t)num_physical_blocks * bdl_bytes_per_erase_block;\n\n    nand_file_mmap_emul_config_t conf = {\"\", k_file_bytes, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &bdl) == ESP_OK);\n    REQUIRE(bdl->geometry.write_size == k_page);\n    REQUIRE(bdl->geometry.erase_size == bdl_bytes_per_erase_block);\n    REQUIRE(bdl->geometry.disk_size == expected_disk_size);\n    bdl->ops->release(bdl);\n}\n\nTEST_CASE(\"verify mark_bad_block works with bdl interface\", \"[spi_nand_flash][bdl]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 50 * 1024 * 1024, true};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t nand_bdl;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &nand_bdl) == 0);\n\n    uint32_t block_size = nand_bdl->geometry.erase_size;\n    uint32_t block_num = nand_bdl->geometry.disk_size / block_size;\n\n    uint32_t test_block = 15;\n    REQUIRE((test_block < block_num) == true);\n    REQUIRE(nand_bdl->ops->erase(nand_bdl, test_block * block_size, block_size) == 0);\n    // Verify if test_block is not bad block\n    esp_blockdev_cmd_arg_is_bad_block_t bad_block_status = {test_block, false};\n    REQUIRE(nand_bdl->ops->ioctl(nand_bdl, ESP_BLOCKDEV_CMD_IS_BAD_BLOCK, &bad_block_status) == 0);\n    REQUIRE(bad_block_status.status == false);\n    // mark test_block as a bad block\n    uint32_t block = test_block;\n    REQUIRE(nand_bdl->ops->ioctl(nand_bdl, ESP_BLOCKDEV_CMD_MARK_BAD_BLOCK, &block) == 0);\n    // Verify if test_block is marked as bad block\n    REQUIRE(nand_bdl->ops->ioctl(nand_bdl, ESP_BLOCKDEV_CMD_IS_BAD_BLOCK, &bad_block_status) == 0);\n    REQUIRE(bad_block_status.status == true);\n\n    nand_bdl->ops->release(nand_bdl);\n}\n\nTEST_CASE(\"verify nand_prog, nand_read, nand_copy, nand_is_free works with bdl interface\", \"[spi_nand_flash][bdl]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 50 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t nand_bdl;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &nand_bdl) == 0);\n\n    uint32_t block_size = nand_bdl->geometry.erase_size;\n    uint32_t sector_size = nand_bdl->geometry.write_size;\n    uint32_t sector_num = nand_bdl->geometry.disk_size / sector_size;\n\n    uint8_t *pattern_buf = (uint8_t *)malloc(sector_size);\n    REQUIRE(pattern_buf != NULL);\n    uint8_t *temp_buf = (uint8_t *)malloc(sector_size);\n    REQUIRE(temp_buf != NULL);\n\n    spi_nand_flash_fill_buffer(pattern_buf, sector_size / sizeof(uint32_t));\n\n    uint32_t test_block = 20;\n    uint32_t test_page = test_block * (block_size / sector_size); //(block_num * pages_per_block)\n\n    REQUIRE((test_page < sector_num) == true);\n    // Verify if test_page is free\n    esp_blockdev_cmd_arg_is_free_page_t page_free_status = {test_page, true};\n    REQUIRE(nand_bdl->ops->ioctl(nand_bdl, ESP_BLOCKDEV_CMD_IS_FREE_PAGE, &page_free_status) == 0);\n    REQUIRE(page_free_status.status == true);\n    // Write/program test_page\n    REQUIRE(nand_bdl->ops->write(nand_bdl, pattern_buf, test_page * sector_size, sector_size) == 0);\n    // Verify if test_page is used/programmed\n    REQUIRE(nand_bdl->ops->ioctl(nand_bdl, ESP_BLOCKDEV_CMD_IS_FREE_PAGE, &page_free_status) == 0);\n    REQUIRE(page_free_status.status == false);\n\n    REQUIRE(nand_bdl->ops->read(nand_bdl, temp_buf, sector_size, test_page * sector_size, sector_size) == 0);\n    REQUIRE(spi_nand_flash_check_buffer(temp_buf, sector_size / sizeof(uint32_t)) == 0);\n\n    free(pattern_buf);\n    free(temp_buf);\n    nand_bdl->ops->release(nand_bdl);\n}\n\nTEST_CASE(\"WL BDL on host: create, geometry, write/read, release\", \"[spi_nand_flash][bdl]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 50 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t flash_bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &flash_bdl) == ESP_OK);\n    REQUIRE(flash_bdl != nullptr);\n\n    esp_blockdev_handle_t wl_bdl = nullptr;\n    REQUIRE(spi_nand_flash_wl_get_blockdev(flash_bdl, &wl_bdl) == ESP_OK);\n    REQUIRE(wl_bdl != nullptr);\n\n    REQUIRE(wl_bdl->geometry.disk_size > 0);\n    REQUIRE(wl_bdl->geometry.read_size > 0);\n    REQUIRE(wl_bdl->geometry.write_size > 0);\n    REQUIRE(wl_bdl->geometry.erase_size > 0);\n\n    uint32_t page_size = wl_bdl->geometry.write_size;\n    REQUIRE(page_size > 0);\n    uint32_t num_pages = (uint32_t)(wl_bdl->geometry.disk_size / page_size);\n    REQUIRE(num_pages > 0);\n\n    uint8_t *pattern_buf = (uint8_t *)malloc(page_size);\n    uint8_t *read_buf = (uint8_t *)malloc(page_size);\n    REQUIRE(pattern_buf != nullptr);\n    REQUIRE(read_buf != nullptr);\n    spi_nand_flash_fill_buffer(pattern_buf, page_size / sizeof(uint32_t));\n\n    REQUIRE(wl_bdl->ops->write(wl_bdl, pattern_buf, 0, page_size) == ESP_OK);\n    memset(read_buf, 0, page_size);\n    REQUIRE(wl_bdl->ops->read(wl_bdl, read_buf, page_size, 0, page_size) == ESP_OK);\n    REQUIRE(spi_nand_flash_check_buffer(read_buf, page_size / sizeof(uint32_t)) == 0);\n\n    free(pattern_buf);\n    free(read_buf);\n    wl_bdl->ops->release(wl_bdl);\n}\n\nTEST_CASE(\"Flash BDL geometry and ops on host\", \"[spi_nand_flash][bdl]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 20 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &bdl) == ESP_OK);\n    REQUIRE(bdl != nullptr);\n\n    uint32_t block_size = bdl->geometry.erase_size;\n    uint32_t num_blocks = (uint32_t)(bdl->geometry.disk_size / block_size);\n    REQUIRE(bdl->geometry.disk_size == (uint64_t)num_blocks * block_size);\n    REQUIRE(bdl->geometry.read_size == bdl->geometry.write_size);\n    REQUIRE(bdl->geometry.read_size > 0);\n    REQUIRE(bdl->geometry.erase_size > 0);\n\n    REQUIRE(bdl->ops != nullptr);\n    REQUIRE(bdl->ops->read != nullptr);\n    REQUIRE(bdl->ops->write != nullptr);\n    REQUIRE(bdl->ops->erase != nullptr);\n    REQUIRE(bdl->ops->ioctl != nullptr);\n    REQUIRE(bdl->ops->release != nullptr);\n\n    bdl->ops->release(bdl);\n}\n\nTEST_CASE(\"Flash BDL COPY_PAGE ioctl on host\", \"[spi_nand_flash][bdl]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 50 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t nand_bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &nand_bdl) == ESP_OK);\n    REQUIRE(nand_bdl != nullptr);\n\n    uint32_t block_size = nand_bdl->geometry.erase_size;\n    uint32_t page_size = nand_bdl->geometry.write_size;\n    uint32_t pages_per_block = block_size / page_size;\n    uint32_t src_page = 5 * pages_per_block;\n    uint32_t dst_page = 6 * pages_per_block;\n\n    REQUIRE(nand_bdl->ops->erase(nand_bdl, src_page * (uint64_t)page_size, block_size) == ESP_OK);\n\n    uint8_t *pattern_buf = (uint8_t *)malloc(page_size);\n    uint8_t *read_buf = (uint8_t *)malloc(page_size);\n    REQUIRE(pattern_buf != nullptr);\n    REQUIRE(read_buf != nullptr);\n    spi_nand_flash_fill_buffer(pattern_buf, page_size / sizeof(uint32_t));\n\n    REQUIRE(nand_bdl->ops->write(nand_bdl, pattern_buf, src_page * (uint64_t)page_size, page_size) == ESP_OK);\n\n    esp_blockdev_cmd_arg_copy_page_t copy_cmd = { .src_page = src_page, .dst_page = dst_page };\n    REQUIRE(nand_bdl->ops->ioctl(nand_bdl, ESP_BLOCKDEV_CMD_COPY_PAGE, &copy_cmd) == ESP_OK);\n\n    memset(read_buf, 0, page_size);\n    REQUIRE(nand_bdl->ops->read(nand_bdl, read_buf, page_size, dst_page * (uint64_t)page_size, page_size) == ESP_OK);\n    REQUIRE(spi_nand_flash_check_buffer(read_buf, page_size / sizeof(uint32_t)) == 0);\n\n    free(pattern_buf);\n    free(read_buf);\n    nand_bdl->ops->release(nand_bdl);\n}\n\nTEST_CASE(\"Flash BDL GET_NAND_FLASH_INFO and GET_BAD_BLOCKS_COUNT on host\", \"[spi_nand_flash][bdl]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 50 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t nand_bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &nand_bdl) == ESP_OK);\n    REQUIRE(nand_bdl != nullptr);\n\n    esp_blockdev_cmd_arg_nand_flash_info_t flash_info;\n    memset(&flash_info, 0, sizeof(flash_info));\n    REQUIRE(nand_bdl->ops->ioctl(nand_bdl, ESP_BLOCKDEV_CMD_GET_NAND_FLASH_INFO, &flash_info) == ESP_OK);\n    REQUIRE(strnlen((const char *)flash_info.device_info.chip_name, sizeof(flash_info.device_info.chip_name)) > 0);\n    uint32_t total_blocks = nand_bdl->geometry.disk_size / nand_bdl->geometry.erase_size;\n    REQUIRE(flash_info.geometry.num_blocks == total_blocks);\n\n    uint32_t bad_block_count = 0xFFFF;\n    REQUIRE(nand_bdl->ops->ioctl(nand_bdl, ESP_BLOCKDEV_CMD_GET_BAD_BLOCKS_COUNT, &bad_block_count) == ESP_OK);\n    REQUIRE(bad_block_count <= total_blocks);\n\n    nand_bdl->ops->release(nand_bdl);\n}\n\nTEST_CASE(\"Error path: nand_flash_get_blockdev NULL/invalid args\", \"[spi_nand_flash][bdl]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 50 * 1024 * 1024, false};\n    spi_nand_flash_config_t config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t out = nullptr;\n\n    REQUIRE(nand_flash_get_blockdev(nullptr, &out) == ESP_ERR_INVALID_ARG);\n    REQUIRE(out == nullptr);\n    REQUIRE(nand_flash_get_blockdev(&config, nullptr) == ESP_ERR_INVALID_ARG);\n}\n\nTEST_CASE(\"Release and no use-after-free: create, release, create again, minimal r/w\", \"[spi_nand_flash][bdl]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 20 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n\n    esp_blockdev_handle_t bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &bdl) == ESP_OK);\n    REQUIRE(bdl != nullptr);\n    bdl->ops->release(bdl);\n\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &bdl) == ESP_OK);\n    REQUIRE(bdl != nullptr);\n\n    uint32_t page_size = bdl->geometry.write_size;\n    uint8_t *buf = (uint8_t *)malloc(page_size);\n    REQUIRE(buf != nullptr);\n    spi_nand_flash_fill_buffer(buf, page_size / sizeof(uint32_t));\n    REQUIRE(bdl->ops->write(bdl, buf, 0, page_size) == ESP_OK);\n    memset(buf, 0, page_size);\n    REQUIRE(bdl->ops->read(bdl, buf, page_size, 0, page_size) == ESP_OK);\n    REQUIRE(spi_nand_flash_check_buffer(buf, page_size / sizeof(uint32_t)) == 0);\n\n    free(buf);\n    bdl->ops->release(bdl);\n}\n\nTEST_CASE(\"Flash BDL last physical page write/read\", \"[spi_nand_flash][bdl][raw]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 16 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &bdl) == ESP_OK);\n\n    const uint32_t page_size = bdl->geometry.write_size;\n    const uint32_t block_size = bdl->geometry.erase_size;\n    const uint64_t disk_size = bdl->geometry.disk_size;\n    const uint32_t num_pages = (uint32_t)(disk_size / page_size);\n    const uint32_t pages_per_block = block_size / page_size;\n    const uint32_t last_page = num_pages - 1u;\n    const uint32_t last_block = last_page / pages_per_block;\n    const uint64_t block_addr = (uint64_t)last_block * block_size;\n\n    REQUIRE(bdl->ops->erase(bdl, block_addr, block_size) == ESP_OK);\n\n    uint8_t *w = (uint8_t *)malloc(page_size);\n    uint8_t *r = (uint8_t *)malloc(page_size);\n    REQUIRE(w != nullptr);\n    REQUIRE(r != nullptr);\n\n    spi_nand_flash_fill_buffer(w, page_size / sizeof(uint32_t));\n    const uint64_t last_off = (uint64_t)last_page * page_size;\n    REQUIRE(bdl->ops->write(bdl, w, last_off, page_size) == ESP_OK);\n    memset(r, 0, page_size);\n    REQUIRE(bdl->ops->read(bdl, r, page_size, last_off, page_size) == ESP_OK);\n    REQUIRE(spi_nand_flash_check_buffer(r, page_size / sizeof(uint32_t)) == 0);\n\n    free(w);\n    free(r);\n    bdl->ops->release(bdl);\n}\n\nTEST_CASE(\"Flash BDL 16 MiB full erase+program sweep then read-back all pages\", \"[spi_nand_flash][bdl][raw][sequential]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 16 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &bdl) == ESP_OK);\n\n    const uint32_t page_size = bdl->geometry.write_size;\n    const uint32_t block_size = bdl->geometry.erase_size;\n    const uint64_t disk_size = bdl->geometry.disk_size;\n    const uint32_t num_blocks = (uint32_t)(disk_size / block_size);\n    const uint32_t pages_per_block = block_size / page_size;\n\n    for (uint32_t b = 0; b < num_blocks; b++) {\n        const uint64_t ba = (uint64_t)b * block_size;\n        REQUIRE(bdl->ops->erase(bdl, ba, block_size) == ESP_OK);\n        for (uint32_t i = 0; i < pages_per_block; i++) {\n            const uint32_t page = b * pages_per_block + i;\n            uint8_t *w = (uint8_t *)malloc(page_size);\n            REQUIRE(w != nullptr);\n            spi_nand_flash_fill_buffer(w, page_size / sizeof(uint32_t));\n            REQUIRE(bdl->ops->write(bdl, w, (uint64_t)page * page_size, page_size) == ESP_OK);\n            free(w);\n        }\n    }\n\n    const uint32_t num_pages = (uint32_t)(disk_size / page_size);\n    uint8_t *r = (uint8_t *)malloc(page_size);\n    REQUIRE(r != nullptr);\n    for (uint32_t page = 0; page < num_pages; page++) {\n        memset(r, 0, page_size);\n        REQUIRE(bdl->ops->read(bdl, r, page_size, (uint64_t)page * page_size, page_size) == ESP_OK);\n        REQUIRE(spi_nand_flash_check_buffer(r, page_size / sizeof(uint32_t)) == 0);\n    }\n    free(r);\n    bdl->ops->release(bdl);\n}\n\nTEST_CASE(\"Flash BDL overwrite same physical page many times\", \"[spi_nand_flash][bdl][raw][stress]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 20 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &bdl) == ESP_OK);\n\n    const uint32_t page_size = bdl->geometry.write_size;\n    const uint32_t block_size = bdl->geometry.erase_size;\n    REQUIRE(bdl->ops->erase(bdl, 0, block_size) == ESP_OK);\n\n    uint8_t *w = (uint8_t *)malloc(page_size);\n    uint8_t *r = (uint8_t *)malloc(page_size);\n    REQUIRE(w != nullptr);\n    REQUIRE(r != nullptr);\n\n    constexpr int kRounds = 150;\n    for (int i = 0; i < kRounds; i++) {\n        spi_nand_flash_fill_buffer(w, page_size / sizeof(uint32_t));\n        REQUIRE(bdl->ops->write(bdl, w, 0, page_size) == ESP_OK);\n    }\n    spi_nand_flash_fill_buffer(w, page_size / sizeof(uint32_t));\n    REQUIRE(bdl->ops->read(bdl, r, page_size, 0, page_size) == ESP_OK);\n    REQUIRE(spi_nand_flash_check_buffer(r, page_size / sizeof(uint32_t)) == 0);\n\n    free(w);\n    free(r);\n    bdl->ops->release(bdl);\n}\n\nTEST_CASE(\"Flash BDL multi-page write in one call\", \"[spi_nand_flash][bdl][raw]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 20 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &bdl) == ESP_OK);\n\n    const uint32_t page_size = bdl->geometry.write_size;\n    const uint32_t block_size = bdl->geometry.erase_size;\n    const uint32_t n = 4;\n    REQUIRE(block_size >= n * page_size);\n\n    REQUIRE(bdl->ops->erase(bdl, 0, block_size) == ESP_OK);\n\n    const size_t total = (size_t)n * page_size;\n    uint8_t *w = (uint8_t *)malloc(total);\n    uint8_t *r = (uint8_t *)malloc(page_size);\n    REQUIRE(w != nullptr);\n    REQUIRE(r != nullptr);\n\n    for (uint32_t p = 0; p < n; p++) {\n        spi_nand_flash_fill_buffer(w + (size_t)p * page_size, page_size / sizeof(uint32_t));\n    }\n    REQUIRE(bdl->ops->write(bdl, w, 0, total) == ESP_OK);\n\n    for (uint32_t p = 0; p < n; p++) {\n        memset(r, 0, page_size);\n        REQUIRE(bdl->ops->read(bdl, r, page_size, (uint64_t)p * page_size, page_size) == ESP_OK);\n        REQUIRE(spi_nand_flash_check_buffer(r, page_size / sizeof(uint32_t)) == 0);\n    }\n\n    free(w);\n    free(r);\n    bdl->ops->release(bdl);\n}\n\nTEST_CASE(\"Flash BDL sub-page read and misaligned write rejected\", \"[spi_nand_flash][bdl][raw]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 20 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &bdl) == ESP_OK);\n\n    const uint32_t page_size = bdl->geometry.write_size;\n    const uint32_t block_size = bdl->geometry.erase_size;\n    REQUIRE(bdl->ops->erase(bdl, 0, block_size) == ESP_OK);\n\n    uint8_t *full = (uint8_t *)malloc(page_size);\n    uint8_t *slice = (uint8_t *)malloc(page_size);\n    REQUIRE(full != nullptr);\n    REQUIRE(slice != nullptr);\n    spi_nand_flash_fill_buffer(full, page_size / sizeof(uint32_t));\n    REQUIRE(bdl->ops->write(bdl, full, 0, page_size) == ESP_OK);\n\n    const size_t off = 64;\n    const size_t len = page_size - 128;\n    REQUIRE(off + len <= page_size);\n    memset(slice, 0, len);\n    REQUIRE(bdl->ops->read(bdl, slice, len, off, len) == ESP_OK);\n    REQUIRE(memcmp(slice, full + off, len) == 0);\n\n    REQUIRE(bdl->ops->write(bdl, full, 1, page_size) == ESP_ERR_INVALID_SIZE);\n\n    free(full);\n    free(slice);\n    bdl->ops->release(bdl);\n}\n\nTEST_CASE(\"Flash BDL COPY_PAGE same page is idempotent\", \"[spi_nand_flash][bdl][raw][copy]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 20 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &bdl) == ESP_OK);\n\n    const uint32_t page_size = bdl->geometry.write_size;\n    const uint32_t block_size = bdl->geometry.erase_size;\n    const uint32_t page = 3 * (block_size / page_size);\n\n    REQUIRE(bdl->ops->erase(bdl, (page / (block_size / page_size)) * (uint64_t)block_size, block_size) == ESP_OK);\n\n    uint8_t *w = (uint8_t *)malloc(page_size);\n    uint8_t *r = (uint8_t *)malloc(page_size);\n    REQUIRE(w != nullptr);\n    REQUIRE(r != nullptr);\n    spi_nand_flash_fill_buffer(w, page_size / sizeof(uint32_t));\n    const uint64_t addr = (uint64_t)page * page_size;\n    REQUIRE(bdl->ops->write(bdl, w, addr, page_size) == ESP_OK);\n\n    esp_blockdev_cmd_arg_copy_page_t copy_cmd = {.src_page = page, .dst_page = page};\n    REQUIRE(bdl->ops->ioctl(bdl, ESP_BLOCKDEV_CMD_COPY_PAGE, &copy_cmd) == ESP_OK);\n\n    memset(r, 0, page_size);\n    REQUIRE(bdl->ops->read(bdl, r, page_size, addr, page_size) == ESP_OK);\n    REQUIRE(spi_nand_flash_check_buffer(r, page_size / sizeof(uint32_t)) == 0);\n\n    free(w);\n    free(r);\n    bdl->ops->release(bdl);\n}\n\nTEST_CASE(\"Flash BDL COPY_PAGE does not alter source page\", \"[spi_nand_flash][bdl][raw][copy]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 20 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &bdl) == ESP_OK);\n\n    const uint32_t page_size = bdl->geometry.write_size;\n    const uint32_t block_size = bdl->geometry.erase_size;\n    const uint32_t ppb = block_size / page_size;\n    const uint32_t src_page = 2u * ppb;\n    const uint32_t dst_page = 2u * ppb + 1u;\n\n    REQUIRE(bdl->ops->erase(bdl, 2u * (uint64_t)block_size, block_size) == ESP_OK);\n\n    uint8_t *w = (uint8_t *)malloc(page_size);\n    uint8_t *r = (uint8_t *)malloc(page_size);\n    REQUIRE(w != nullptr);\n    REQUIRE(r != nullptr);\n    spi_nand_flash_fill_buffer(w, page_size / sizeof(uint32_t));\n    REQUIRE(bdl->ops->write(bdl, w, (uint64_t)src_page * page_size, page_size) == ESP_OK);\n\n    esp_blockdev_cmd_arg_copy_page_t copy_cmd = {.src_page = src_page, .dst_page = dst_page};\n    REQUIRE(bdl->ops->ioctl(bdl, ESP_BLOCKDEV_CMD_COPY_PAGE, &copy_cmd) == ESP_OK);\n\n    memset(r, 0, page_size);\n    REQUIRE(bdl->ops->read(bdl, r, page_size, (uint64_t)src_page * page_size, page_size) == ESP_OK);\n    REQUIRE(memcmp(w, r, page_size) == 0);\n\n    free(w);\n    free(r);\n    bdl->ops->release(bdl);\n}\n\nTEST_CASE(\"Flash BDL invalid write/read geometry returns error\", \"[spi_nand_flash][bdl][raw]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 20 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &bdl) == ESP_OK);\n\n    const uint32_t page_size = bdl->geometry.write_size;\n    const uint64_t disk = bdl->geometry.disk_size;\n    uint8_t *buf = (uint8_t *)malloc(page_size * 2);\n    REQUIRE(buf != nullptr);\n    spi_nand_flash_fill_buffer(buf, page_size / sizeof(uint32_t));\n\n    REQUIRE(bdl->ops->write(bdl, buf, page_size / 2u, page_size) == ESP_ERR_INVALID_SIZE);\n    if (page_size >= 512u) {\n        REQUIRE(bdl->ops->write(bdl, buf, 0, page_size / 2u) == ESP_ERR_INVALID_SIZE);\n    }\n\n    memset(buf, 0, page_size);\n    REQUIRE(bdl->ops->read(bdl, buf, page_size, disk, page_size) == ESP_ERR_INVALID_SIZE);\n    REQUIRE(bdl->ops->write(bdl, buf, disk, page_size) == ESP_ERR_INVALID_SIZE);\n\n    free(buf);\n    bdl->ops->release(bdl);\n}\n\nTEST_CASE(\"Flash BDL GET_PAGE_ECC_STATUS and GET_ECC_STATS (small image)\", \"[spi_nand_flash][bdl][raw]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 4 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &bdl) == ESP_OK);\n\n    const uint32_t page_size = bdl->geometry.write_size;\n    const uint32_t block_size = bdl->geometry.erase_size;\n    REQUIRE(bdl->ops->erase(bdl, 0, block_size) == ESP_OK);\n\n    uint8_t *buf = (uint8_t *)malloc(page_size);\n    REQUIRE(buf != nullptr);\n    spi_nand_flash_fill_buffer(buf, page_size / sizeof(uint32_t));\n    REQUIRE(bdl->ops->write(bdl, buf, 0, page_size) == ESP_OK);\n\n    esp_blockdev_cmd_arg_ecc_status_t ecc_page = {};\n    ecc_page.page_num = 0;\n    REQUIRE(bdl->ops->ioctl(bdl, ESP_BLOCKDEV_CMD_GET_PAGE_ECC_STATUS, &ecc_page) == ESP_OK);\n\n    esp_blockdev_cmd_arg_ecc_stats_t ecc_stats = {};\n    REQUIRE(bdl->ops->ioctl(bdl, ESP_BLOCKDEV_CMD_GET_ECC_STATS, &ecc_stats) == ESP_OK);\n\n    free(buf);\n    bdl->ops->release(bdl);\n}\n\nTEST_CASE(\"WL BDL sync after write preserves data\", \"[spi_nand_flash][bdl][wl]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 16 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t flash_bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &flash_bdl) == ESP_OK);\n    esp_blockdev_handle_t wl_bdl = nullptr;\n    REQUIRE(spi_nand_flash_wl_get_blockdev(flash_bdl, &wl_bdl) == ESP_OK);\n\n    const uint32_t page_size = wl_bdl->geometry.write_size;\n    uint8_t *w = (uint8_t *)malloc(page_size);\n    uint8_t *r = (uint8_t *)malloc(page_size);\n    REQUIRE(w != nullptr);\n    REQUIRE(r != nullptr);\n\n    spi_nand_flash_fill_buffer(w, page_size / sizeof(uint32_t));\n    REQUIRE(wl_bdl->ops->write(wl_bdl, w, page_size, page_size) == ESP_OK);\n    REQUIRE(wl_bdl->ops->sync(wl_bdl) == ESP_OK);\n    memset(r, 0, page_size);\n    REQUIRE(wl_bdl->ops->read(wl_bdl, r, page_size, page_size, page_size) == ESP_OK);\n    REQUIRE(spi_nand_flash_check_buffer(r, page_size / sizeof(uint32_t)) == 0);\n\n    free(w);\n    free(r);\n    wl_bdl->ops->release(wl_bdl);\n}\n\nTEST_CASE(\"WL BDL MARK_DELETED then rewrite same logical page\", \"[spi_nand_flash][bdl][wl]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 16 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t flash_bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &flash_bdl) == ESP_OK);\n    esp_blockdev_handle_t wl_bdl = nullptr;\n    REQUIRE(spi_nand_flash_wl_get_blockdev(flash_bdl, &wl_bdl) == ESP_OK);\n\n    const uint32_t page_size = wl_bdl->geometry.write_size;\n    const uint32_t page_index = 5;\n    const uint64_t off = (uint64_t)page_index * page_size;\n\n    uint8_t *w = (uint8_t *)malloc(page_size);\n    uint8_t *r = (uint8_t *)malloc(page_size);\n    REQUIRE(w != nullptr);\n    REQUIRE(r != nullptr);\n\n    memset(w, 0x22, page_size);\n    REQUIRE(wl_bdl->ops->write(wl_bdl, w, off, page_size) == ESP_OK);\n\n    esp_blockdev_cmd_arg_erase_t trim_arg = {.start_addr = off, .erase_len = page_size};\n    REQUIRE(wl_bdl->ops->ioctl(wl_bdl, ESP_BLOCKDEV_CMD_MARK_DELETED, &trim_arg) == ESP_OK);\n\n    spi_nand_flash_fill_buffer(w, page_size / sizeof(uint32_t));\n    REQUIRE(wl_bdl->ops->write(wl_bdl, w, off, page_size) == ESP_OK);\n    memset(r, 0, page_size);\n    REQUIRE(wl_bdl->ops->read(wl_bdl, r, page_size, off, page_size) == ESP_OK);\n    REQUIRE(spi_nand_flash_check_buffer(r, page_size / sizeof(uint32_t)) == 0);\n\n    free(w);\n    free(r);\n    wl_bdl->ops->release(wl_bdl);\n}\n\nTEST_CASE(\"WL BDL MARK_DELETED misaligned range returns ESP_ERR_INVALID_SIZE\", \"[spi_nand_flash][bdl][wl]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 20 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t flash_bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &flash_bdl) == ESP_OK);\n    esp_blockdev_handle_t wl_bdl = nullptr;\n    REQUIRE(spi_nand_flash_wl_get_blockdev(flash_bdl, &wl_bdl) == ESP_OK);\n\n    const uint32_t page_size = wl_bdl->geometry.write_size;\n    esp_blockdev_cmd_arg_erase_t bad = {.start_addr = 1, .erase_len = page_size};\n    REQUIRE(wl_bdl->ops->ioctl(wl_bdl, ESP_BLOCKDEV_CMD_MARK_DELETED, &bad) == ESP_ERR_INVALID_SIZE);\n\n    wl_bdl->ops->release(wl_bdl);\n}\n\nTEST_CASE(\"WL BDL 16 MiB sequential logical page fill and read-back\", \"[spi_nand_flash][bdl][wl][sequential]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 16 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t flash_bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &flash_bdl) == ESP_OK);\n    esp_blockdev_handle_t wl_bdl = nullptr;\n    REQUIRE(spi_nand_flash_wl_get_blockdev(flash_bdl, &wl_bdl) == ESP_OK);\n\n    const uint32_t page_size = wl_bdl->geometry.write_size;\n    const uint32_t num_pages = (uint32_t)(wl_bdl->geometry.disk_size / page_size);\n    REQUIRE(wl_bdl->geometry.disk_size == (uint64_t)num_pages * page_size);\n\n    uint8_t *w = (uint8_t *)malloc(page_size);\n    REQUIRE(w != nullptr);\n\n    for (uint32_t p = 0; p < num_pages; p++) {\n        spi_nand_flash_fill_buffer(w, page_size / sizeof(uint32_t));\n        REQUIRE(wl_bdl->ops->write(wl_bdl, w, (uint64_t)p * page_size, page_size) == ESP_OK);\n    }\n    REQUIRE(wl_bdl->ops->sync(wl_bdl) == ESP_OK);\n\n    uint8_t *r = (uint8_t *)malloc(page_size);\n    REQUIRE(r != nullptr);\n    for (uint32_t p = 0; p < num_pages; p++) {\n        memset(r, 0, page_size);\n        REQUIRE(wl_bdl->ops->read(wl_bdl, r, page_size, (uint64_t)p * page_size, page_size) == ESP_OK);\n        REQUIRE(spi_nand_flash_check_buffer(r, page_size / sizeof(uint32_t)) == 0);\n    }\n\n    free(w);\n    free(r);\n    wl_bdl->ops->release(wl_bdl);\n}\n\nTEST_CASE(\"WL BDL hot-set random writes then read-back\", \"[spi_nand_flash][bdl][wl][stress]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 16 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t flash_bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &flash_bdl) == ESP_OK);\n    esp_blockdev_handle_t wl_bdl = nullptr;\n    REQUIRE(spi_nand_flash_wl_get_blockdev(flash_bdl, &wl_bdl) == ESP_OK);\n\n    constexpr uint32_t kHotSetSize = 30u;\n    constexpr uint32_t kTotalWrites = 1200u;\n\n    const uint32_t page_size = wl_bdl->geometry.write_size;\n    const uint32_t num_pages = (uint32_t)(wl_bdl->geometry.disk_size / page_size);\n    REQUIRE(num_pages >= kHotSetSize);\n\n    uint8_t *w = (uint8_t *)malloc(page_size);\n    uint8_t *r = (uint8_t *)malloc(page_size);\n    REQUIRE(w != nullptr);\n    REQUIRE(r != nullptr);\n\n    bool written[kHotSetSize] = {};\n\n    std::srand(0xDEADBEEFu);\n    for (uint32_t op = 0; op < kTotalWrites; op++) {\n        const uint32_t lp = (uint32_t)((unsigned)std::rand() % kHotSetSize);\n        spi_nand_flash_fill_buffer(w, page_size / sizeof(uint32_t));\n        REQUIRE(wl_bdl->ops->write(wl_bdl, w, (uint64_t)lp * page_size, page_size) == ESP_OK);\n        written[lp] = true;\n    }\n\n    REQUIRE(wl_bdl->ops->sync(wl_bdl) == ESP_OK);\n\n    for (uint32_t s = 0; s < kHotSetSize; s++) {\n        if (!written[s]) {\n            continue;\n        }\n        REQUIRE(wl_bdl->ops->read(wl_bdl, r, page_size, (uint64_t)s * page_size, page_size) == ESP_OK);\n        REQUIRE(spi_nand_flash_check_buffer(r, page_size / sizeof(uint32_t)) == 0);\n    }\n\n    free(w);\n    free(r);\n    wl_bdl->ops->release(wl_bdl);\n}\n\nTEST_CASE(\"WL BDL hot-set with interleaved MARK_DELETED\", \"[spi_nand_flash][bdl][wl][stress][trim]\")\n{\n    nand_file_mmap_emul_config_t conf = {\"\", 16 * 1024 * 1024, false};\n    spi_nand_flash_config_t nand_flash_config = {&conf, 0, SPI_NAND_IO_MODE_SIO, 0};\n    esp_blockdev_handle_t flash_bdl = nullptr;\n    REQUIRE(nand_flash_get_blockdev(&nand_flash_config, &flash_bdl) == ESP_OK);\n    esp_blockdev_handle_t wl_bdl = nullptr;\n    REQUIRE(spi_nand_flash_wl_get_blockdev(flash_bdl, &wl_bdl) == ESP_OK);\n\n    constexpr uint32_t kHotSetSize = 30u;\n    constexpr uint32_t kTotalWrites = 1200u;\n\n    const uint32_t page_size = wl_bdl->geometry.write_size;\n    const uint32_t num_pages = (uint32_t)(wl_bdl->geometry.disk_size / page_size);\n    REQUIRE(num_pages >= kHotSetSize);\n\n    uint8_t *w = (uint8_t *)malloc(page_size);\n    uint8_t *r = (uint8_t *)malloc(page_size);\n    REQUIRE(w != nullptr);\n    REQUIRE(r != nullptr);\n\n    bool trimmed[kHotSetSize] = {};\n    bool written[kHotSetSize] = {};\n\n    std::srand(0xCAFEBABEu);\n    for (uint32_t op = 0; op < kTotalWrites; op++) {\n        const uint32_t lp = (uint32_t)((unsigned)std::rand() % kHotSetSize);\n\n        if (op % 100u == 99u) {\n            const uint32_t t = (uint32_t)((unsigned)std::rand() % kHotSetSize);\n            esp_blockdev_cmd_arg_erase_t trim_arg = {\n                .start_addr = (uint64_t)t * page_size,\n                .erase_len = page_size,\n            };\n            if (wl_bdl->ops->ioctl(wl_bdl, ESP_BLOCKDEV_CMD_MARK_DELETED, &trim_arg) == ESP_OK) {\n                trimmed[t] = true;\n            }\n        }\n\n        spi_nand_flash_fill_buffer(w, page_size / sizeof(uint32_t));\n        REQUIRE(wl_bdl->ops->write(wl_bdl, w, (uint64_t)lp * page_size, page_size) == ESP_OK);\n        trimmed[lp] = false;\n        written[lp] = true;\n    }\n\n    REQUIRE(wl_bdl->ops->sync(wl_bdl) == ESP_OK);\n\n    for (uint32_t s = 0; s < kHotSetSize; s++) {\n        if (trimmed[s] || !written[s]) {\n            continue;\n        }\n        REQUIRE(wl_bdl->ops->read(wl_bdl, r, page_size, (uint64_t)s * page_size, page_size) == ESP_OK);\n        REQUIRE(spi_nand_flash_check_buffer(r, page_size / sizeof(uint32_t)) == 0);\n    }\n\n    free(w);\n    free(r);\n    wl_bdl->ops->release(wl_bdl);\n}\n"
  },
  {
    "path": "spi_nand_flash/host_test/main/test_nand_flash_ftl.cpp",
    "content": "/*\n * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/*\n * FTL-level host tests for spi_nand_flash.\n *\n * All tests exercise the public logical-sector API exclusively:\n *   spi_nand_flash_write_sector / read_sector / copy_sector / trim /\n *   sync / get_capacity / get_sector_size / get_block_size /\n *   get_block_num / spi_nand_erase_chip\n *\n * Raw NAND page operations (nand_wrap_*) are intentionally NOT used here.\n * See test_nand_flash.cpp for raw-level coverage.\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <stdint.h>\n\n#include \"spi_nand_flash.h\"\n#include \"spi_nand_flash_test_helpers.h\"\n#include \"nand_linux_mmap_emul.h\"\n\n#include <catch2/catch_test_macros.hpp>\n\n/* -------------------------------------------------------------------------\n * Fixture helpers\n * ---------------------------------------------------------------------- */\n\n/** Default flash size used by most tests (16 MiB — fast init / GC pressure). */\n#define FTL_TEST_FLASH_SIZE  ((size_t)16u * 1024u * 1024u)\n\n/** Larger flash used for the full-capacity sequential sweep. */\n#define FTL_TEST_FLASH_LARGE ((size_t)32u * 1024u * 1024u)\n\n/**\n * Open a fresh emulated NAND device backed by an anonymous temp file.\n * gc_factor == 0 selects the driver default.\n */\nstatic spi_nand_flash_device_t *make_ftl_dev(size_t flash_size = FTL_TEST_FLASH_SIZE,\n        uint8_t gc_factor = 0)\n{\n    nand_file_mmap_emul_config_t emul = {\"\", flash_size, /*keep_dump=*/false};\n    spi_nand_flash_config_t cfg = {&emul, gc_factor, SPI_NAND_IO_MODE_SIO, 0};\n    spi_nand_flash_device_t *dev = nullptr;\n    REQUIRE(spi_nand_flash_init_device(&cfg, &dev) == ESP_OK);\n    REQUIRE(dev != nullptr);\n    return dev;\n}\n\nstatic void destroy_ftl_dev(spi_nand_flash_device_t *dev)\n{\n    REQUIRE(spi_nand_flash_deinit_device(dev) == ESP_OK);\n}\n\n/* -------------------------------------------------------------------------\n * Group 1: Device info / capacity API\n * ---------------------------------------------------------------------- */\n\nTEST_CASE(\"FTL get_capacity returns non-zero sector count\", \"[ftl][info]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sectors = 0;\n    REQUIRE(spi_nand_flash_get_capacity(dev, &sectors) == ESP_OK);\n    REQUIRE(sectors > 0);\n    destroy_ftl_dev(dev);\n}\n\nTEST_CASE(\"FTL get_sector_size returns a power-of-two >= 512\", \"[ftl][info]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sz = 0;\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n    REQUIRE(sz >= 512u);\n    /* Must be a power of two */\n    REQUIRE((sz & (sz - 1u)) == 0u);\n    destroy_ftl_dev(dev);\n}\n\nTEST_CASE(\"FTL get_block_size is a multiple of sector_size\", \"[ftl][info]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sector_size = 0, block_size = 0;\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sector_size) == ESP_OK);\n    REQUIRE(spi_nand_flash_get_block_size(dev, &block_size) == ESP_OK);\n    REQUIRE(block_size > 0);\n    REQUIRE(block_size % sector_size == 0);\n    destroy_ftl_dev(dev);\n}\n\nTEST_CASE(\"FTL get_block_num is consistent with capacity and block/sector sizes\",\n          \"[ftl][info]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sectors = 0, sector_size = 0, block_size = 0, blocks = 0;\n    REQUIRE(spi_nand_flash_get_capacity(dev, &sectors) == ESP_OK);\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sector_size) == ESP_OK);\n    REQUIRE(spi_nand_flash_get_block_size(dev, &block_size) == ESP_OK);\n    REQUIRE(spi_nand_flash_get_block_num(dev, &blocks) == ESP_OK);\n    REQUIRE(blocks > 0);\n    /* Total logical flash bytes derived from blocks must match capacity-derived bytes.\n     * Dhara reserves some blocks for GC, so the logical sector count is <= physical. */\n    uint32_t pages_per_block = block_size / sector_size;\n    REQUIRE(blocks * pages_per_block >= sectors);\n    destroy_ftl_dev(dev);\n}\n\n/* -------------------------------------------------------------------------\n * Group 2: Single-sector write / read round-trip\n * ---------------------------------------------------------------------- */\n\nTEST_CASE(\"FTL write then read back sector 0 produces correct data\", \"[ftl][rw]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sz = 0;\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    uint8_t *wbuf = (uint8_t *)malloc(sz);\n    uint8_t *rbuf = (uint8_t *)malloc(sz);\n    REQUIRE(wbuf != nullptr);\n    REQUIRE(rbuf != nullptr);\n\n    spi_nand_flash_fill_buffer(wbuf, sz / sizeof(uint32_t));\n    REQUIRE(spi_nand_flash_write_sector(dev, wbuf, 0) == ESP_OK);\n    REQUIRE(spi_nand_flash_read_sector(dev, rbuf, 0) == ESP_OK);\n    REQUIRE(memcmp(wbuf, rbuf, sz) == 0);\n\n    free(wbuf);\n    free(rbuf);\n    destroy_ftl_dev(dev);\n}\n\nTEST_CASE(\"FTL write then read back last valid sector\", \"[ftl][rw]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sectors = 0, sz = 0;\n    REQUIRE(spi_nand_flash_get_capacity(dev, &sectors) == ESP_OK);\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    uint8_t *wbuf = (uint8_t *)malloc(sz);\n    uint8_t *rbuf = (uint8_t *)malloc(sz);\n    REQUIRE(wbuf != nullptr);\n    REQUIRE(rbuf != nullptr);\n\n    uint32_t last = sectors - 1u;\n    spi_nand_flash_fill_buffer(wbuf, sz / sizeof(uint32_t));\n    REQUIRE(spi_nand_flash_write_sector(dev, wbuf, last) == ESP_OK);\n    REQUIRE(spi_nand_flash_read_sector(dev, rbuf, last) == ESP_OK);\n    REQUIRE(memcmp(wbuf, rbuf, sz) == 0);\n\n    free(wbuf);\n    free(rbuf);\n    destroy_ftl_dev(dev);\n}\n\nTEST_CASE(\"FTL overwrite same sector multiple times, each read-back is correct\",\n          \"[ftl][rw]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sz = 0;\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    uint8_t *wbuf = (uint8_t *)malloc(sz);\n    uint8_t *rbuf = (uint8_t *)malloc(sz);\n    REQUIRE(wbuf != nullptr);\n    REQUIRE(rbuf != nullptr);\n\n    const uint32_t TARGET_SECTOR = 7;\n    const int OVERWRITE_ROUNDS = 20;\n\n    for (int i = 0; i < OVERWRITE_ROUNDS; i++) {\n        /* Round-varying seed so each write is distinct; *0x1000 spreads seeds for remap checks. */\n        spi_nand_flash_fill_buffer_seeded(wbuf, sz / sizeof(uint32_t), (uint32_t)i * 0x1000u);\n        REQUIRE(spi_nand_flash_write_sector(dev, wbuf, TARGET_SECTOR) == ESP_OK);\n        REQUIRE(spi_nand_flash_read_sector(dev, rbuf, TARGET_SECTOR) == ESP_OK);\n        REQUIRE(memcmp(wbuf, rbuf, sz) == 0);\n    }\n\n    free(wbuf);\n    free(rbuf);\n    destroy_ftl_dev(dev);\n}\n\nTEST_CASE(\"FTL multiple sectors hold independent data after interleaved writes\",\n          \"[ftl][rw]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sz = 0;\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    const uint32_t N = 8;\n    uint8_t *wbuf = (uint8_t *)malloc(sz);\n    uint8_t *rbuf = (uint8_t *)malloc(sz);\n    REQUIRE(wbuf != nullptr);\n    REQUIRE(rbuf != nullptr);\n\n    /* Write each sector with the shared test pattern */\n    for (uint32_t s = 0; s < N; s++) {\n        spi_nand_flash_fill_buffer_seeded(wbuf, sz / sizeof(uint32_t), s);\n        REQUIRE(spi_nand_flash_write_sector(dev, wbuf, s) == ESP_OK);\n    }\n\n    /* Read them all back and verify the pattern */\n    for (uint32_t s = 0; s < N; s++) {\n        REQUIRE(spi_nand_flash_read_sector(dev, rbuf, s) == ESP_OK);\n        REQUIRE(spi_nand_flash_check_buffer_seeded(rbuf, sz / sizeof(uint32_t), s) == 0);\n    }\n\n    free(wbuf);\n    free(rbuf);\n    destroy_ftl_dev(dev);\n}\n\n/* -------------------------------------------------------------------------\n * Group 3: sync\n * ---------------------------------------------------------------------- */\n\nTEST_CASE(\"FTL sync returns ESP_OK on a freshly initialised device\", \"[ftl][sync]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    REQUIRE(spi_nand_flash_sync(dev) == ESP_OK);\n    destroy_ftl_dev(dev);\n}\n\nTEST_CASE(\"FTL sync after writes returns ESP_OK and data survives\", \"[ftl][sync]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sz = 0;\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    uint8_t *wbuf = (uint8_t *)malloc(sz);\n    uint8_t *rbuf = (uint8_t *)malloc(sz);\n    REQUIRE(wbuf != nullptr);\n    REQUIRE(rbuf != nullptr);\n\n    spi_nand_flash_fill_buffer(wbuf, sz / sizeof(uint32_t));\n    REQUIRE(spi_nand_flash_write_sector(dev, wbuf, 3) == ESP_OK);\n    REQUIRE(spi_nand_flash_sync(dev) == ESP_OK);\n    REQUIRE(spi_nand_flash_read_sector(dev, rbuf, 3) == ESP_OK);\n    REQUIRE(memcmp(wbuf, rbuf, sz) == 0);\n\n    free(wbuf);\n    free(rbuf);\n    destroy_ftl_dev(dev);\n}\n\n/* -------------------------------------------------------------------------\n * Group 4: copy_sector\n * ---------------------------------------------------------------------- */\n\nTEST_CASE(\"FTL copy_sector duplicates data to a different logical sector\",\n          \"[ftl][copy]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sz = 0;\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    uint8_t *wbuf = (uint8_t *)malloc(sz);\n    uint8_t *rbuf = (uint8_t *)malloc(sz);\n    REQUIRE(wbuf != nullptr);\n    REQUIRE(rbuf != nullptr);\n\n    spi_nand_flash_fill_buffer(wbuf, sz / sizeof(uint32_t));\n    REQUIRE(spi_nand_flash_write_sector(dev, wbuf, 10) == ESP_OK);\n    REQUIRE(spi_nand_flash_copy_sector(dev, 10, 20) == ESP_OK);\n    REQUIRE(spi_nand_flash_read_sector(dev, rbuf, 20) == ESP_OK);\n    REQUIRE(memcmp(wbuf, rbuf, sz) == 0);\n\n    free(wbuf);\n    free(rbuf);\n    destroy_ftl_dev(dev);\n}\n\nTEST_CASE(\"FTL copy_sector to same sector id is idempotent\", \"[ftl][copy]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sz = 0;\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    uint8_t *wbuf = (uint8_t *)malloc(sz);\n    uint8_t *rbuf = (uint8_t *)malloc(sz);\n    REQUIRE(wbuf != nullptr);\n    REQUIRE(rbuf != nullptr);\n\n    spi_nand_flash_fill_buffer(wbuf, sz / sizeof(uint32_t));\n    REQUIRE(spi_nand_flash_write_sector(dev, wbuf, 5) == ESP_OK);\n    /* Copying a sector onto itself should succeed (or at least not corrupt) */\n    esp_err_t rc = spi_nand_flash_copy_sector(dev, 5, 5);\n    /* Behaviour is either ESP_OK or a graceful error — must not crash */\n    if (rc == ESP_OK) {\n        REQUIRE(spi_nand_flash_read_sector(dev, rbuf, 5) == ESP_OK);\n        REQUIRE(memcmp(wbuf, rbuf, sz) == 0);\n    }\n    /* If it returned an error that is also acceptable — just must not corrupt data */\n\n    free(wbuf);\n    free(rbuf);\n    destroy_ftl_dev(dev);\n}\n\nTEST_CASE(\"FTL copy does not alter source sector data\", \"[ftl][copy]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sz = 0;\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    uint8_t *wbuf = (uint8_t *)malloc(sz);\n    uint8_t *rbuf = (uint8_t *)malloc(sz);\n    REQUIRE(wbuf != nullptr);\n    REQUIRE(rbuf != nullptr);\n\n    spi_nand_flash_fill_buffer(wbuf, sz / sizeof(uint32_t));\n    REQUIRE(spi_nand_flash_write_sector(dev, wbuf, 11) == ESP_OK);\n    REQUIRE(spi_nand_flash_copy_sector(dev, 11, 22) == ESP_OK);\n\n    /* Source must be unchanged */\n    REQUIRE(spi_nand_flash_read_sector(dev, rbuf, 11) == ESP_OK);\n    REQUIRE(memcmp(wbuf, rbuf, sz) == 0);\n\n    free(wbuf);\n    free(rbuf);\n    destroy_ftl_dev(dev);\n}\n\n/* -------------------------------------------------------------------------\n * Group 5: trim\n * ---------------------------------------------------------------------- */\n\nTEST_CASE(\"FTL trim returns ESP_OK on a written sector\", \"[ftl][trim]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sz = 0;\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    uint8_t *buf = (uint8_t *)malloc(sz);\n    REQUIRE(buf != nullptr);\n    memset(buf, 0xAB, sz);\n\n    REQUIRE(spi_nand_flash_write_sector(dev, buf, 4) == ESP_OK);\n    REQUIRE(spi_nand_flash_trim(dev, 4) == ESP_OK);\n\n    free(buf);\n    destroy_ftl_dev(dev);\n}\n\nTEST_CASE(\"FTL trim then write to the same sector succeeds\", \"[ftl][trim]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sz = 0;\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    uint8_t *wbuf = (uint8_t *)malloc(sz);\n    uint8_t *rbuf = (uint8_t *)malloc(sz);\n    REQUIRE(wbuf != nullptr);\n    REQUIRE(rbuf != nullptr);\n\n    memset(wbuf, 0x11, sz);\n    REQUIRE(spi_nand_flash_write_sector(dev, wbuf, 6) == ESP_OK);\n    REQUIRE(spi_nand_flash_trim(dev, 6) == ESP_OK);\n\n    spi_nand_flash_fill_buffer(wbuf, sz / sizeof(uint32_t));\n    REQUIRE(spi_nand_flash_write_sector(dev, wbuf, 6) == ESP_OK);\n    REQUIRE(spi_nand_flash_read_sector(dev, rbuf, 6) == ESP_OK);\n    REQUIRE(memcmp(wbuf, rbuf, sz) == 0);\n\n    free(wbuf);\n    free(rbuf);\n    destroy_ftl_dev(dev);\n}\n\nTEST_CASE(\"FTL trim on unwritten sector returns ESP_OK\", \"[ftl][trim]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    /* Sector 9 has never been written — trim should still succeed gracefully */\n    REQUIRE(spi_nand_flash_trim(dev, 9) == ESP_OK);\n    destroy_ftl_dev(dev);\n}\n\n/* -------------------------------------------------------------------------\n * Group 6: erase_chip\n * ---------------------------------------------------------------------- */\n\nTEST_CASE(\"FTL erase_chip succeeds and write/read works afterwards\",\n          \"[ftl][erase-chip]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sz = 0;\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    uint8_t *wbuf = (uint8_t *)malloc(sz);\n    uint8_t *rbuf = (uint8_t *)malloc(sz);\n    REQUIRE(wbuf != nullptr);\n    REQUIRE(rbuf != nullptr);\n\n    /* Write something before the chip erase */\n    spi_nand_flash_fill_buffer(wbuf, sz / sizeof(uint32_t));\n    REQUIRE(spi_nand_flash_write_sector(dev, wbuf, 0) == ESP_OK);\n\n    REQUIRE(spi_nand_erase_chip(dev) == ESP_OK);\n\n    /* After erase the FTL must accept new writes */\n    spi_nand_flash_fill_buffer(wbuf, sz / sizeof(uint32_t));\n    REQUIRE(spi_nand_flash_write_sector(dev, wbuf, 0) == ESP_OK);\n    REQUIRE(spi_nand_flash_read_sector(dev, rbuf, 0) == ESP_OK);\n    REQUIRE(memcmp(wbuf, rbuf, sz) == 0);\n\n    free(wbuf);\n    free(rbuf);\n    destroy_ftl_dev(dev);\n}\n\n/* -------------------------------------------------------------------------\n * Group 7: Logical sector IDs beyond capacity\n *\n * NOTE: Dhara does NOT bounds-check logical sector IDs at the FTL level.\n * Writing or reading beyond the reported capacity succeeds (returns ESP_OK)\n * rather than returning an error.  These tests document that observed\n * behaviour so that any future change in Dhara that adds bounds-checking\n * will be caught explicitly.\n * ---------------------------------------------------------------------- */\n\nTEST_CASE(\"FTL write to sector_id == capacity succeeds\",\n          \"[ftl][bounds]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sectors = 0, sz = 0;\n    REQUIRE(spi_nand_flash_get_capacity(dev, &sectors) == ESP_OK);\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    uint8_t *buf = (uint8_t *)calloc(1, sz);\n    REQUIRE(buf != nullptr);\n\n    /* Dhara does not validate the sector ID — expect success, not an error. */\n    esp_err_t rc = spi_nand_flash_write_sector(dev, buf, sectors);\n    REQUIRE(rc == ESP_OK);\n\n    free(buf);\n    destroy_ftl_dev(dev);\n}\n\nTEST_CASE(\"FTL read from sector_id == capacity succeeds\",\n          \"[ftl][bounds]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sectors = 0, sz = 0;\n    REQUIRE(spi_nand_flash_get_capacity(dev, &sectors) == ESP_OK);\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    uint8_t *buf = (uint8_t *)calloc(1, sz);\n    REQUIRE(buf != nullptr);\n\n    /* Dhara does not validate the sector ID — expect success, not an error. */\n    esp_err_t rc = spi_nand_flash_read_sector(dev, buf, sectors);\n    REQUIRE(rc == ESP_OK);\n\n    free(buf);\n    destroy_ftl_dev(dev);\n}\n\nTEST_CASE(\"FTL write to UINT32_MAX sector_id succeeds\",\n          \"[ftl][bounds]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sz = 0;\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    uint8_t *buf = (uint8_t *)calloc(1, sz);\n    REQUIRE(buf != nullptr);\n\n    /* Dhara does not validate the sector ID — expect success, not an error. */\n    esp_err_t rc = spi_nand_flash_write_sector(dev, buf, UINT32_MAX);\n    REQUIRE(rc == ESP_OK);\n\n    free(buf);\n    destroy_ftl_dev(dev);\n}\n\n/* -------------------------------------------------------------------------\n * Group 8: Sequential full-capacity write sweep\n * ---------------------------------------------------------------------- */\n\nTEST_CASE(\"FTL sequential write to every logical sector, then read-back all\",\n          \"[ftl][sequential]\")\n{\n    /* Use larger flash so we have a meaningful number of logical sectors */\n    spi_nand_flash_device_t *dev = make_ftl_dev(FTL_TEST_FLASH_LARGE);\n    uint32_t sectors = 0, sz = 0;\n    REQUIRE(spi_nand_flash_get_capacity(dev, &sectors) == ESP_OK);\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    uint8_t *wbuf = (uint8_t *)malloc(sz);\n    uint8_t *rbuf = (uint8_t *)malloc(sz);\n    REQUIRE(wbuf != nullptr);\n    REQUIRE(rbuf != nullptr);\n\n    /* Write pass */\n    for (uint32_t s = 0; s < sectors; s++) {\n        spi_nand_flash_fill_buffer_seeded(wbuf, sz / sizeof(uint32_t), s);\n        REQUIRE(spi_nand_flash_write_sector(dev, wbuf, s) == ESP_OK);\n    }\n\n    REQUIRE(spi_nand_flash_sync(dev) == ESP_OK);\n\n    /* Verify capacity has not changed */\n    uint32_t sectors_after = 0;\n    REQUIRE(spi_nand_flash_get_capacity(dev, &sectors_after) == ESP_OK);\n    REQUIRE(sectors_after == sectors);\n\n    /* Read-back pass */\n    for (uint32_t s = 0; s < sectors; s++) {\n        REQUIRE(spi_nand_flash_read_sector(dev, rbuf, s) == ESP_OK);\n        REQUIRE(spi_nand_flash_check_buffer_seeded(rbuf, sz / sizeof(uint32_t), s) == 0);\n    }\n\n    free(wbuf);\n    free(rbuf);\n    destroy_ftl_dev(dev);\n}\n\n/* -------------------------------------------------------------------------\n * Group 9: GC stability — hot-set repeated overwrites\n *\n * Write to a small set of logical sectors (HOT_SET_SIZE) many times\n * (TOTAL_WRITES).  This forces Dhara to perform garbage collection\n * repeatedly.  Asserts:\n *   1. Every write returns ESP_OK.\n *   2. After the run, get_capacity() still returns the original value.\n *   3. Each sector in the hot-set reads back the last value written.\n *   4. spi_nand_flash_sync() returns ESP_OK.\n * ---------------------------------------------------------------------- */\n\n#define HOT_SET_SIZE  50u\n#define TOTAL_WRITES  5000u\n\nTEST_CASE(\"FTL GC stability: 50-sector hot-set written 5000 times\",\n          \"[ftl][gc][stability]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n\n    uint32_t sectors = 0, sz = 0;\n    REQUIRE(spi_nand_flash_get_capacity(dev, &sectors) == ESP_OK);\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    /* The hot-set must fit within the device's logical address space */\n    REQUIRE(sectors >= HOT_SET_SIZE);\n\n    uint8_t *wbuf = (uint8_t *)malloc(sz);\n    uint8_t *rbuf = (uint8_t *)malloc(sz);\n    REQUIRE(wbuf != nullptr);\n    REQUIRE(rbuf != nullptr);\n\n    bool written[HOT_SET_SIZE] = {};\n    uint32_t last_seed[HOT_SET_SIZE] = {};\n\n    srand(0xDEADBEEFu); /* reproducible */\n\n    for (uint32_t op = 0; op < TOTAL_WRITES; op++) {\n        uint32_t lsector = (uint32_t)((unsigned)rand() % HOT_SET_SIZE);\n        spi_nand_flash_fill_buffer_seeded(wbuf, sz / sizeof(uint32_t), op);\n        REQUIRE(spi_nand_flash_write_sector(dev, wbuf, lsector) == ESP_OK);\n        written[lsector] = true;\n        last_seed[lsector] = op;\n    }\n\n    /* Capacity must be unchanged — the Dhara map must not have grown OOB */\n    uint32_t sectors_after = 0;\n    REQUIRE(spi_nand_flash_get_capacity(dev, &sectors_after) == ESP_OK);\n    REQUIRE(sectors_after == sectors);\n\n    /* Flush any in-memory state */\n    REQUIRE(spi_nand_flash_sync(dev) == ESP_OK);\n\n    /* Every hot sector must read back the last write's pattern */\n    for (uint32_t s = 0; s < HOT_SET_SIZE; s++) {\n        if (!written[s]) {\n            continue; /* rand() never selected this logical sector */\n        }\n        REQUIRE(spi_nand_flash_read_sector(dev, rbuf, s) == ESP_OK);\n        REQUIRE(spi_nand_flash_check_buffer_seeded(rbuf, sz / sizeof(uint32_t), last_seed[s]) == 0);\n    }\n\n    free(wbuf);\n    free(rbuf);\n    destroy_ftl_dev(dev);\n}\n\nTEST_CASE(\"FTL GC stability with trim: hot-set with interleaved trims\",\n          \"[ftl][gc][trim][stability]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n\n    uint32_t sectors = 0, sz = 0;\n    REQUIRE(spi_nand_flash_get_capacity(dev, &sectors) == ESP_OK);\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n    REQUIRE(sectors >= HOT_SET_SIZE);\n\n    uint8_t *wbuf = (uint8_t *)malloc(sz);\n    uint8_t *rbuf = (uint8_t *)malloc(sz);\n    REQUIRE(wbuf != nullptr);\n    REQUIRE(rbuf != nullptr);\n\n    bool trimmed[HOT_SET_SIZE] = {};\n    bool written[HOT_SET_SIZE] = {};\n    uint32_t last_seed[HOT_SET_SIZE] = {};\n\n    srand(0xCAFEBABEu);\n\n    for (uint32_t op = 0; op < TOTAL_WRITES; op++) {\n        uint32_t lsector = (uint32_t)((unsigned)rand() % HOT_SET_SIZE);\n\n        /* Every 100 ops trim a random sector in the hot-set */\n        if (op % 100 == 99) {\n            uint32_t t = (uint32_t)((unsigned)rand() % HOT_SET_SIZE);\n            if (spi_nand_flash_trim(dev, t) == ESP_OK) {\n                trimmed[t] = true;\n            }\n        }\n\n        spi_nand_flash_fill_buffer_seeded(wbuf, sz / sizeof(uint32_t), op);\n        REQUIRE(spi_nand_flash_write_sector(dev, wbuf, lsector) == ESP_OK);\n        trimmed[lsector] = false;\n        written[lsector] = true;\n        last_seed[lsector] = op;\n    }\n\n    uint32_t sectors_after = 0;\n    REQUIRE(spi_nand_flash_get_capacity(dev, &sectors_after) == ESP_OK);\n    REQUIRE(sectors_after == sectors);\n    REQUIRE(spi_nand_flash_sync(dev) == ESP_OK);\n\n    /* Verify untrimmed sectors */\n    for (uint32_t s = 0; s < HOT_SET_SIZE; s++) {\n        if (trimmed[s] || !written[s]) {\n            continue; /* skip trimmed or never-written */\n        }\n        REQUIRE(spi_nand_flash_read_sector(dev, rbuf, s) == ESP_OK);\n        REQUIRE(spi_nand_flash_check_buffer_seeded(rbuf, sz / sizeof(uint32_t), last_seed[s]) == 0);\n    }\n\n    free(wbuf);\n    free(rbuf);\n    destroy_ftl_dev(dev);\n}\n\n/* -------------------------------------------------------------------------\n * Group 10: Single-sector hammer — one sector written thousands of times\n * ---------------------------------------------------------------------- */\n\nTEST_CASE(\"FTL single sector written 2000 times stays readable and correct\",\n          \"[ftl][gc][hammer]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sz = 0;\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    uint8_t *wbuf = (uint8_t *)malloc(sz);\n    uint8_t *rbuf = (uint8_t *)malloc(sz);\n    REQUIRE(wbuf != nullptr);\n    REQUIRE(rbuf != nullptr);\n\n    const uint32_t TARGET = 0;\n    const uint32_t ROUNDS = 2000;\n\n    for (uint32_t i = 0; i < ROUNDS; i++) {\n        spi_nand_flash_fill_buffer_seeded(wbuf, sz / sizeof(uint32_t), i);\n        REQUIRE(spi_nand_flash_write_sector(dev, wbuf, TARGET) == ESP_OK);\n    }\n\n    /* Final read must reflect the last write (seed ROUNDS - 1). */\n    spi_nand_flash_fill_buffer_seeded(wbuf, sz / sizeof(uint32_t), ROUNDS - 1u);\n    REQUIRE(spi_nand_flash_read_sector(dev, rbuf, TARGET) == ESP_OK);\n    REQUIRE(memcmp(wbuf, rbuf, sz) == 0);\n\n    free(wbuf);\n    free(rbuf);\n    destroy_ftl_dev(dev);\n}\n\n/* -------------------------------------------------------------------------\n * Group 11: Alternating write / read pattern\n * ---------------------------------------------------------------------- */\n\nTEST_CASE(\"FTL alternating write-read on two sectors never corrupts either\",\n          \"[ftl][rw][alternating]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sz = 0;\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    uint8_t *wbuf = (uint8_t *)malloc(sz);\n    uint8_t *rbuf = (uint8_t *)malloc(sz);\n    REQUIRE(wbuf != nullptr);\n    REQUIRE(rbuf != nullptr);\n\n    const uint32_t ITERS = 500;\n\n    for (uint32_t i = 0; i < ITERS; i++) {\n        /* Write A, then read B, then write B, then read A */\n        spi_nand_flash_fill_buffer_seeded(wbuf, sz / sizeof(uint32_t), i);\n        REQUIRE(spi_nand_flash_write_sector(dev, wbuf, 1) == ESP_OK);\n\n        REQUIRE(spi_nand_flash_read_sector(dev, rbuf, 2) == ESP_OK);\n        if (i > 0) {\n            REQUIRE(spi_nand_flash_check_buffer_seeded(rbuf, sz / sizeof(uint32_t), i - 1u) == 0);\n        }\n\n        spi_nand_flash_fill_buffer_seeded(wbuf, sz / sizeof(uint32_t), i);\n        REQUIRE(spi_nand_flash_write_sector(dev, wbuf, 2) == ESP_OK);\n\n        REQUIRE(spi_nand_flash_read_sector(dev, rbuf, 1) == ESP_OK);\n        REQUIRE(spi_nand_flash_check_buffer_seeded(rbuf, sz / sizeof(uint32_t), i) == 0);\n    }\n\n    free(wbuf);\n    free(rbuf);\n    destroy_ftl_dev(dev);\n}\n\n/* -------------------------------------------------------------------------\n * Group 12: All-zeros and all-ones patterns (edge-case data values)\n * ---------------------------------------------------------------------- */\n\nTEST_CASE(\"FTL write/read all-zeros pattern\", \"[ftl][rw][patterns]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sz = 0;\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    uint8_t *buf = (uint8_t *)calloc(1, sz);\n    uint8_t *rbuf = (uint8_t *)malloc(sz);\n    REQUIRE(buf != nullptr);\n    REQUIRE(rbuf != nullptr);\n\n    REQUIRE(spi_nand_flash_write_sector(dev, buf, 0) == ESP_OK);\n    REQUIRE(spi_nand_flash_read_sector(dev, rbuf, 0) == ESP_OK);\n    REQUIRE(memcmp(buf, rbuf, sz) == 0);\n\n    free(buf);\n    free(rbuf);\n    destroy_ftl_dev(dev);\n}\n\nTEST_CASE(\"FTL write/read all-0xFF pattern\", \"[ftl][rw][patterns]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sz = 0;\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    uint8_t *buf  = (uint8_t *)malloc(sz);\n    uint8_t *rbuf = (uint8_t *)malloc(sz);\n    REQUIRE(buf != nullptr);\n    REQUIRE(rbuf != nullptr);\n    memset(buf, 0xFF, sz);\n\n    REQUIRE(spi_nand_flash_write_sector(dev, buf, 1) == ESP_OK);\n    REQUIRE(spi_nand_flash_read_sector(dev, rbuf, 1) == ESP_OK);\n    REQUIRE(memcmp(buf, rbuf, sz) == 0);\n\n    free(buf);\n    free(rbuf);\n    destroy_ftl_dev(dev);\n}\n\nTEST_CASE(\"FTL write/read alternating 0xAA/0x55 pattern\", \"[ftl][rw][patterns]\")\n{\n    spi_nand_flash_device_t *dev = make_ftl_dev();\n    uint32_t sz = 0;\n    REQUIRE(spi_nand_flash_get_sector_size(dev, &sz) == ESP_OK);\n\n    uint8_t *buf  = (uint8_t *)malloc(sz);\n    uint8_t *rbuf = (uint8_t *)malloc(sz);\n    REQUIRE(buf != nullptr);\n    REQUIRE(rbuf != nullptr);\n\n    for (size_t i = 0; i < sz; i++) {\n        buf[i] = (i & 1u) ? 0x55u : 0xAAu;\n    }\n\n    REQUIRE(spi_nand_flash_write_sector(dev, buf, 2) == ESP_OK);\n    REQUIRE(spi_nand_flash_read_sector(dev, rbuf, 2) == ESP_OK);\n    REQUIRE(memcmp(buf, rbuf, sz) == 0);\n\n    free(buf);\n    free(rbuf);\n    destroy_ftl_dev(dev);\n}\n"
  },
  {
    "path": "spi_nand_flash/host_test/pytest_nand_flash_linux.py",
    "content": "# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.utils import idf_parametrize\nimport glob\nfrom pathlib import Path\n\n\n@pytest.mark.host_test\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that not build\"\n)\n@idf_parametrize('target', ['linux'], indirect=['target'])\ndef test_nand_flash_linux(dut: Dut) -> None:\n    dut.expect_exact('All tests passed', timeout=120)\n"
  },
  {
    "path": "spi_nand_flash/host_test/sdkconfig.defaults",
    "content": "CONFIG_IDF_TARGET=\"linux\"\nCONFIG_COMPILER_CXX_EXCEPTIONS=y\nCONFIG_MMU_PAGE_SIZE=0X10000\nCONFIG_NAND_ENABLE_STATS=y\n"
  },
  {
    "path": "spi_nand_flash/idf_component.yml",
    "content": "version: \"1.0.2\"\ndescription: Driver for accessing SPI NAND Flash\nurl: https://github.com/espressif/idf-extra-components/tree/master/spi_nand_flash\nissues: https://github.com/espressif/idf-extra-components/issues\nrepository: https://github.com/espressif/idf-extra-components.git\ndocumentation: https://github.com/espressif/idf-extra-components/tree/main/spi_nand_flash/README.md\ndependencies:\n  idf:\n    version: \">=5.0\"\n    require: public\n  espressif/dhara:\n    version: \"0.1.*\"\n    override_path: \"../dhara\"\n    require: public\n"
  },
  {
    "path": "spi_nand_flash/include/esp_nand_blockdev.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * @file esp_nand_blockdev.h\n * @brief NAND Flash Block Device Interface\n *\n * This header provides the block device interface for SPI NAND Flash, including:\n * - Flash Block Device Layer (raw NAND flash access)\n * - Wear-Leveling Block Device Layer (logical sector access with wear leveling)\n * - NAND-specific ioctl commands and structures\n *\n * @note All block devices created by this interface use the standard esp_blockdev_t\n *       interface from ESP-IDF, making them compatible with filesystems and other\n *       block device consumers.\n */\n\n#pragma once\n\n#include <stdint.h>\n#include \"esp_err.h\"\n#include \"spi_nand_flash.h\"\n#include \"nand_device_types.h\"\n\n#ifdef CONFIG_NAND_FLASH_ENABLE_BDL\n#include \"esp_blockdev.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n//=============================================================================\n// NAND-SPECIFIC IOCTL COMMANDS\n//=============================================================================\n\n#define ESP_BLOCKDEV_CMD_NAND_BASE                  (ESP_BLOCKDEV_CMD_SYSTEM_BASE + 10) /*!< Base for NAND-specific ioctl codes (10 above @ref ESP_BLOCKDEV_CMD_SYSTEM_BASE) */\n\n/**\n * @defgroup esp_blockdev_nand_ioctl NAND flash block device ioctl commands\n * @brief NAND-specific ioctl commands for @ref esp_blockdev_ops_t::ioctl\n *\n * These extend the block device ioctl interface with bad-block handling, ECC status,\n * and other NAND-specific operations. Intended for raw NAND or FTL-backed block devices\n * that implement the corresponding cases in their ioctl handlers.\n *\n * @{\n */\n\n/** @brief Check if a block is marked as bad\n *\n * @code{c}\n * esp_blockdev_cmd_arg_status_t cmd = { .num = block_num };\n * esp_err_t ret = bdl->ops->ioctl(bdl, ESP_BLOCKDEV_CMD_IS_BAD_BLOCK, &cmd);\n * bool is_bad = cmd.status;\n * @endcode\n */\n#define ESP_BLOCKDEV_CMD_IS_BAD_BLOCK               (ESP_BLOCKDEV_CMD_NAND_BASE + 0)\n\n/** @brief Mark a block as bad\n *\n * @code{c}\n * uint32_t block = test_block_num;\n * esp_err_t ret = bdl->ops->ioctl(bdl, ESP_BLOCKDEV_CMD_MARK_BAD_BLOCK, &block);\n * @endcode\n */\n#define ESP_BLOCKDEV_CMD_MARK_BAD_BLOCK             (ESP_BLOCKDEV_CMD_NAND_BASE + 1)\n\n/** @brief Check if a page is free\n *\n * @code{c}\n * esp_blockdev_cmd_arg_status_t cmd = { .num = page_num };\n * esp_err_t ret = bdl->ops->ioctl(bdl, ESP_BLOCKDEV_CMD_IS_FREE_PAGE, &cmd);\n * bool is_free = cmd.status;\n * @endcode\n */\n#define ESP_BLOCKDEV_CMD_IS_FREE_PAGE               (ESP_BLOCKDEV_CMD_NAND_BASE + 2)\n\n/** @brief Get ECC status for a specific page\n *\n * @code{c}\n * esp_blockdev_cmd_arg_ecc_status_t cmd = { .page_num = page_num };\n * esp_err_t ret = bdl->ops->ioctl(bdl, ESP_BLOCKDEV_CMD_GET_PAGE_ECC_STATUS, &cmd);\n * nand_ecc_status_t ecc_status = cmd.ecc_status;\n * @endcode\n */\n#define ESP_BLOCKDEV_CMD_GET_PAGE_ECC_STATUS        (ESP_BLOCKDEV_CMD_NAND_BASE + 3)\n\n/** @brief Get the number of bad blocks in the flash\n *\n * @code{c}\n * uint32_t bad_block_count;\n * esp_err_t ret = flash_bdl->ops->ioctl(flash_bdl, ESP_BLOCKDEV_CMD_GET_BAD_BLOCKS_COUNT, &bad_block_count);\n * @endcode\n */\n#define ESP_BLOCKDEV_CMD_GET_BAD_BLOCKS_COUNT       (ESP_BLOCKDEV_CMD_NAND_BASE + 4)\n\n/** @brief Get ECC error statistics\n *\n * Scans the device for ECC status; can be slow on large devices. Intended for\n * diagnostics and debugging (for example flash health and degradation checks), not for use\n * in the normal I/O path. Do not call from an ISR. On large parts a full scan\n * may run long enough to risk the task watchdog; call from a suitable task\n * context or adjust WDT settings if needed.\n *\n * @code{c}\n * esp_blockdev_cmd_arg_ecc_stats_t ecc_stats;\n * esp_err_t ret = flash_bdl->ops->ioctl(flash_bdl, ESP_BLOCKDEV_CMD_GET_ECC_STATS, &ecc_stats);\n * @endcode\n */\n#define ESP_BLOCKDEV_CMD_GET_ECC_STATS              (ESP_BLOCKDEV_CMD_NAND_BASE + 5)\n\n/** @brief Get complete NAND flash information (device ID and geometry)\n *\n * @code{c}\n * esp_blockdev_cmd_arg_nand_flash_info_t flash_info;\n * esp_err_t ret = flash_bdl->ops->ioctl(flash_bdl, ESP_BLOCKDEV_CMD_GET_NAND_FLASH_INFO, &flash_info);\n * printf(\"Manufacturer: 0x%02X, Device: 0x%04X\\n\",\n *        flash_info.device_info.manufacturer_id,\n *        flash_info.device_info.device_id);\n * @endcode\n */\n#define ESP_BLOCKDEV_CMD_GET_NAND_FLASH_INFO        (ESP_BLOCKDEV_CMD_NAND_BASE + 6)\n\n/** @brief Copy a page from source to destination (raw flash block device)\n *\n * Performs a hardware-level page copy where supported, preserving copy optimizations\n * available on the NAND device. Often used internally by wear-leveling layers.\n *\n * @code{c}\n * esp_blockdev_cmd_arg_copy_page_t copy_cmd = { .src_page = 10, .dst_page = 20 };\n * esp_err_t ret = flash_bdl->ops->ioctl(flash_bdl, ESP_BLOCKDEV_CMD_COPY_PAGE, &copy_cmd);\n * @endcode\n */\n#define ESP_BLOCKDEV_CMD_COPY_PAGE                  (ESP_BLOCKDEV_CMD_NAND_BASE + 7)\n\n/** @} */\n\n//=============================================================================\n// IOCTL COMMAND ARGUMENT STRUCTURES\n//=============================================================================\n\n/**\n * @brief Argument structure for block/page status commands\n *\n * Used with @ref ESP_BLOCKDEV_CMD_IS_BAD_BLOCK and @ref ESP_BLOCKDEV_CMD_IS_FREE_PAGE.\n */\ntypedef struct {\n    uint32_t num;                                   /*!< IN: block or page number */\n    bool status;                                    /*!< OUT: bad-block status (true if bad) or page-free status (true if free) */\n} esp_blockdev_cmd_arg_status_t;\n\ntypedef esp_blockdev_cmd_arg_status_t esp_blockdev_cmd_arg_is_bad_block_t;\ntypedef esp_blockdev_cmd_arg_status_t esp_blockdev_cmd_arg_is_free_page_t;\n\n/**\n * @brief Argument structure for ECC status query\n *\n * Used with @ref ESP_BLOCKDEV_CMD_GET_PAGE_ECC_STATUS.\n */\ntypedef struct {\n    uint32_t page_num;                              /*!< IN: page number to check */\n    nand_ecc_status_t ecc_status;                   /*!< OUT: ECC status (@ref nand_ecc_status_t) */\n} esp_blockdev_cmd_arg_ecc_status_t;\n\n/**\n * @brief ECC error statistics\n *\n * Used with @ref ESP_BLOCKDEV_CMD_GET_ECC_STATS.\n */\ntypedef struct {\n    uint8_t ecc_threshold;                          /*!< Current ECC correction threshold */\n    uint32_t ecc_total_err_count;                   /*!< Total number of ECC errors encountered */\n    uint32_t ecc_uncorrected_err_count;             /*!< Number of uncorrectable ECC errors */\n    uint32_t ecc_exceeding_threshold_err_count;     /*!< Number of errors exceeding threshold (data refresh recommended) */\n} esp_blockdev_cmd_arg_ecc_stats_t;\n\n/**\n * @brief Complete NAND flash device information\n *\n * Used with @ref ESP_BLOCKDEV_CMD_GET_NAND_FLASH_INFO.\n */\ntypedef struct {\n    nand_device_info_t device_info;                 /*!< Device identification (manufacturer, device ID, chip name) */\n    nand_flash_geometry_t geometry;                 /*!< Flash geometry (page size, block size, timing, and so on) */\n} esp_blockdev_cmd_arg_nand_flash_info_t;\n\n/**\n * @brief Argument structure for page copy command\n *\n * Used with @ref ESP_BLOCKDEV_CMD_COPY_PAGE.\n */\ntypedef struct {\n    uint32_t src_page;                              /*!< IN: source page number */\n    uint32_t dst_page;                              /*!< IN: destination page number */\n} esp_blockdev_cmd_arg_copy_page_t;\n\n//=============================================================================\n// BLOCK DEVICE CREATION FUNCTIONS\n//=============================================================================\n\n/**\n * @brief Create Flash Block Device Layer (raw NAND flash access)\n *\n * This function initializes the NAND flash device and creates a block device\n * interface for direct physical access to the flash.\n *\n * @param[in]  config           Configuration for the SPI NAND flash device\n * @param[out] out_bdl_handle_ptr Pointer to store the Flash Block Device Layer handle\n *\n * @return\n *         - ESP_OK: Success\n *         - ESP_ERR_INVALID_ARG: Invalid configuration or NULL pointers\n *         - ESP_ERR_NO_MEM: Insufficient memory for device structures\n *         - ESP_ERR_NOT_FOUND: NAND device not detected on SPI bus\n *         - ESP_FAIL: Other initialization failure\n *\n * @note The returned block device handle must be released with bdl->ops->release(bdl)\n *       when no longer needed.\n *\n * @note This creates the FLASH layer. For filesystem use, you typically want\n *       the WEAR-LEVELING layer instead (see spi_nand_flash_wl_get_blockdev).\n *\n * @warning Raw flash access bypasses the Dhara FTL. For general read/write\n *          workloads and any standard filesystem use, prefer the wear-leveling\n *          BDL (`spi_nand_flash_wl_get_blockdev` / `spi_nand_flash_init_with_layers`)\n *\n * @warning @c erase on this handle performs a physical block erase only; it does not skip\n *          or validate bad blocks. If you must not erase blocks that are marked bad,\n *          query status with @ref ESP_BLOCKDEV_CMD_IS_BAD_BLOCK before erasing, or use the\n *          wear-leveling BDL, which manages bad blocks for you.\n */\nesp_err_t nand_flash_get_blockdev(spi_nand_flash_config_t *config,\n                                  esp_blockdev_handle_t *out_bdl_handle_ptr);\n\n/**\n * @brief Create Wear-Leveling Block Device Layer (logical sector access)\n *\n * This function creates a wear-leveling block device on top of a Flash Block\n * Device Layer. The WL layer provides:\n * - Logical-to-physical sector mapping\n * - Automatic wear leveling (via Dhara library)\n * - Bad block abstraction (bad blocks invisible to user)\n * - Garbage collection\n * - Filesystem-ready interface\n *\n * @param[in]  nand_bdl          Flash Block Device Layer handle (from nand_flash_get_blockdev)\n * @param[out] out_bdl_handle_ptr Pointer to store the Wear-Leveling Block Device Layer handle\n *\n * @return\n *         - ESP_OK: Success\n *         - ESP_ERR_INVALID_ARG: Invalid flash BDL handle or NULL pointer\n *         - ESP_ERR_NO_MEM: Insufficient memory for wear-leveling structures\n *         - ESP_FAIL: Wear-leveling initialization failure\n *\n * @note The returned block device handle must be released with bdl->ops->release(bdl)\n *       when no longer needed.\n *\n * @note This is the recommended layer for filesystem use. It provides wear leveling\n *       and bad block management automatically.\n */\nesp_err_t spi_nand_flash_wl_get_blockdev(esp_blockdev_handle_t nand_bdl,\n        esp_blockdev_handle_t *out_bdl_handle_ptr);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif // CONFIG_NAND_FLASH_ENABLE_BDL\n"
  },
  {
    "path": "spi_nand_flash/include/nand_device_types.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <stdbool.h>\n#include \"esp_err.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** @brief NAND Flash ECC status enumeration */\ntypedef enum {\n    NAND_ECC_OK = 0,                     /*!< No ECC errors detected */\n    NAND_ECC_1_TO_3_BITS_CORRECTED = 1, /*!< 1-3 bits corrected */\n    NAND_ECC_BITS_CORRECTED = NAND_ECC_1_TO_3_BITS_CORRECTED,\n    NAND_ECC_NOT_CORRECTED = 2,          /*!< ECC errors not correctable */\n    NAND_ECC_4_TO_6_BITS_CORRECTED = 3, /*!< 4-6 bits corrected */\n    NAND_ECC_MAX_BITS_CORRECTED = NAND_ECC_4_TO_6_BITS_CORRECTED,\n    NAND_ECC_7_8_BITS_CORRECTED = 5,    /*!< 7-8 bits corrected */\n    NAND_ECC_MAX\n} nand_ecc_status_t;\n\n/** @brief NAND Flash ECC configuration and status */\ntypedef struct {\n    uint8_t ecc_status_reg_len_in_bits;     /*!< Length of ECC status register in bits */\n    uint8_t ecc_data_refresh_threshold;     /*!< ECC error threshold for data refresh */\n    nand_ecc_status_t ecc_corrected_bits_status; /*!< Current ECC correction status */\n} nand_ecc_data_t;\n\n/** @brief NAND Flash chip geometry and characteristics */\ntypedef struct {\n    uint8_t log2_page_size;                 /*!< Page size as power of 2 (e.g., 11 for 2048 bytes) */\n    uint8_t log2_ppb;                       /*!< Pages per block as power of 2 (e.g., 6 for 64 pages) */\n    uint32_t block_size;                    /*!< Block size in bytes */\n    uint32_t page_size;                     /*!< Page size in bytes */\n    uint32_t num_blocks;                    /*!< Total number of blocks */\n    uint32_t read_page_delay_us;            /*!< Read page delay in microseconds */\n    uint32_t erase_block_delay_us;          /*!< Erase block delay in microseconds */\n    uint32_t program_page_delay_us;         /*!< Program page delay in microseconds */\n    uint32_t num_planes;                    /*!< Number of planes in the flash */\n    uint32_t flags;                         /*!< Chip-specific flags */\n    nand_ecc_data_t ecc_data;              /*!< ECC configuration and status */\n    uint8_t has_quad_enable_bit;           /*!< 1 if chip supports QIO/QOUT mode */\n    uint8_t quad_enable_bit_pos;           /*!< Position of quad enable bit */\n#ifdef CONFIG_IDF_TARGET_LINUX\n    uint32_t emulated_page_size;            /*!< Emulated page size for Linux */\n    uint32_t emulated_page_oob;             /*!< Emulated OOB size for Linux */\n#endif\n} nand_flash_geometry_t;\n\n/** @brief NAND Flash device identification information */\ntypedef struct {\n    uint8_t manufacturer_id;                /*!< Manufacturer ID */\n    uint16_t device_id;                     /*!< Device ID */\n    char chip_name[32];                     /*!< Chip name string */\n} nand_device_info_t;\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "spi_nand_flash/include/nand_diag_api.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include <stdint.h>\n#include \"esp_err.h\"\n#include \"spi_nand_flash.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// These API used for diagnostic purpose of SPI NAND Flash\n\n/** @brief Get bad block statistics for the NAND Flash.\n *\n * This function scans all the blocks in the NAND Flash and returns the total count of bad blocks.\n *\n * @param flash The handle to the SPI nand flash chip.\n * @param[out] bad_block_count A pointer of where to put the return value\n * @return ESP_OK on success, or a flash error code if it fails to get bad block statistics.\n */\nesp_err_t nand_get_bad_block_stats(spi_nand_flash_device_t *flash, uint32_t *bad_block_count);\n\n/** @brief Get ECC error statistics for the NAND Flash.\n *\n * This function displays the total ECC errors reported, ECC not corrected error count and ECC error count exceeding threshold.\n *\n * @param flash The handle to the SPI nand flash chip.\n * @return ESP_OK on success, or a flash error code if it failed to read the page.\n */\nesp_err_t nand_get_ecc_stats(spi_nand_flash_device_t *flash);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "spi_nand_flash/include/nand_linux_mmap_emul.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <stddef.h>\n#include <stdbool.h>\n#include \"esp_err.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// Control structure for NAND emulation\ntypedef struct {\n    char flash_file_name[256];\n    /**\n     * Size of the backing mmap file in bytes. Must be a multiple of the chip's\n     * user-visible block size (page_size * pages_per_block).\n     *\n     * Note: the file on disk is slightly larger than the user-visible NAND capacity\n     * because each page has OOB bytes interleaved after it. The actual number of\n     * usable blocks is derived internally as:\n     *   num_blocks = flash_file_size / (pages_per_block * (page_size + oob_size))\n     * and the effective user-visible capacity is num_blocks * block_size, which\n     * will be slightly less than flash_file_size due to the OOB overhead.\n     *\n     * Example: passing 8 MiB with 2 KiB pages, 64 B OOB, 64 pages/block gives\n     *   file_bytes_per_block = 64 * (2048 + 64) = 135168 B\n     *   num_blocks = 8388608 / 135168 = 62 blocks\n     *   effective capacity = 62 * 131072 = 7.75 MiB (user-visible)\n     */\n    size_t flash_file_size;\n    bool keep_dump;\n} nand_file_mmap_emul_config_t;\n\n// nand mmap emulator handle\ntypedef struct {\n    void *mem_file_buf;\n    int mem_file_fd;\n    nand_file_mmap_emul_config_t file_mmap_ctrl;\n#ifdef CONFIG_NAND_ENABLE_STATS\n    struct {\n        size_t read_ops;\n        size_t write_ops;\n        size_t erase_ops;\n        size_t read_bytes;\n        size_t write_bytes;\n    } stats;\n#endif\n} nand_mmap_emul_handle_t;\n\n// Emulated nand mmap file size\n#define EMULATED_NAND_SIZE        128 * 1024 * 1024\n\n#include \"spi_nand_flash.h\"\n\n/**\n * @brief Initialize NAND flash emulation\n *\n * @param handle spi_nand_flash_device_t handle for nand device\n * @param cfg mmap emulation configuration setting\n * @return ESP_OK on success\n *         ESP_ERR_INVALID_STATE if already initialized\n *         ESP_ERR_NOT_FOUND if backing file cannot be created or opened (named path or default temp file via mkstemp)\n *         ESP_ERR_INVALID_SIZE if file size setting fails\n *         ESP_ERR_NO_MEM if memory not available or mmap fails\n */\nesp_err_t nand_emul_init(spi_nand_flash_device_t *handle, nand_file_mmap_emul_config_t *cfg);\n\n/**\n * @brief Clean up NAND flash emulation\n *\n * @param handle spi_nand_flash_device_t handle for nand device\n * @return ESP_OK on success, or if @p handle is NULL or emulation was never initialized / already deinitialized (idempotent)\n *         ESP_ERR_INVALID_STATE if emulation handle exists but is not mapped (inconsistent state)\n *         ESP_ERR_INVALID_RESPONSE if cleanup operations fail\n */\nesp_err_t nand_emul_deinit(spi_nand_flash_device_t *handle);\n\n/**\n * @brief Read data from NAND flash\n *\n * @param handle spi_nand_flash_device_t handle for nand device\n * @param addr Source address in NAND flash\n * @param dst Destination buffer\n * @param size Number of bytes to read\n * @return ESP_OK on success\n *         ESP_ERR_INVALID_STATE if there is no emulation handle or the backing mmap is not ready\n *         ESP_ERR_INVALID_SIZE if read would exceed flash size\n */\nesp_err_t nand_emul_read(spi_nand_flash_device_t *handle, size_t addr, void *dst, size_t size);\n\n/**\n * @brief Write data to NAND flash\n *\n * @param handle spi_nand_flash_device_t handle for nand device\n * @param addr Destination address in NAND flash\n * @param src Source data buffer\n * @param size Number of bytes to write\n * @return ESP_OK on success\n *         ESP_ERR_INVALID_STATE if there is no emulation handle or the backing mmap is not ready\n *         ESP_ERR_INVALID_SIZE if write would exceed flash size\n */\nesp_err_t nand_emul_write(spi_nand_flash_device_t *handle, size_t addr, const void *src, size_t size);\n\n/**\n * @brief Erase a NAND block\n *\n * @param handle spi_nand_flash_device_t handle for nand device\n * @param offset Block Address offset to erase\n * @return ESP_OK on success\n *         ESP_ERR_INVALID_STATE if there is no emulation handle or the backing mmap is not ready\n *         ESP_ERR_INVALID_SIZE if erase range would exceed emulated flash size\n */\nesp_err_t nand_emul_erase_block(spi_nand_flash_device_t *handle, size_t offset);\n\n#ifdef CONFIG_NAND_ENABLE_STATS\n/**\n * @brief Get NAND operation statistics\n *\n * @param handle spi_nand_flash_device_t handle for nand device\n * @param[out] read_ops Number of read operations\n * @param[out] write_ops Number of write operations\n * @param[out] erase_ops Number of erase operations\n * @param[out] read_bytes Total bytes read\n * @param[out] write_bytes Total bytes written\n */\nvoid nand_emul_get_stats(spi_nand_flash_device_t *handle, size_t *read_ops, size_t *write_ops, size_t *erase_ops,\n                         size_t *read_bytes, size_t *write_bytes);\n\n/**\n * @brief Clear NAND operation statistics\n * @param handle spi_nand_flash_device_t handle for nand device\n */\nvoid nand_emul_clear_stats(spi_nand_flash_device_t *handle);\n#endif /* CONFIG_NAND_ENABLE_STATS */\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "spi_nand_flash/include/nand_private/nand_impl_wrap.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include <stdint.h>\n#include \"esp_err.h\"\n#include \"spi_nand_flash.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// These APIs provide direct access to lower-level NAND functions, bypassing the Dhara library.\n// These functions differ from the similarly named `nand_*` functions in that they also take the mutex for the duration of the call.\n\nesp_err_t nand_wrap_is_bad(spi_nand_flash_device_t *handle, uint32_t b, bool *is_bad_status);\nesp_err_t nand_wrap_mark_bad(spi_nand_flash_device_t *handle, uint32_t b);\nesp_err_t nand_wrap_erase_chip(spi_nand_flash_device_t *handle);\nesp_err_t nand_wrap_erase_block(spi_nand_flash_device_t *handle, uint32_t b);\nesp_err_t nand_wrap_prog(spi_nand_flash_device_t *handle, uint32_t p, const uint8_t *data);\nesp_err_t nand_wrap_is_free(spi_nand_flash_device_t *handle, uint32_t p, bool *is_free_status);\nesp_err_t nand_wrap_read(spi_nand_flash_device_t *handle, uint32_t p, size_t offset, size_t length, uint8_t *data);\nesp_err_t nand_wrap_copy(spi_nand_flash_device_t *handle, uint32_t src, uint32_t dst);\nesp_err_t nand_wrap_get_ecc_status(spi_nand_flash_device_t *handle, uint32_t page);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "spi_nand_flash/include/spi_nand_flash.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 mikkeldamsgaard project\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * SPDX-FileContributor: 2015-2025 Espressif Systems (Shanghai) CO LTD\n */\n\n#pragma once\n\n#include <stdint.h>\n#include \"esp_err.h\"\n#include \"nand_device_types.h\"\n#ifndef CONFIG_IDF_TARGET_LINUX\n#include \"driver/spi_common.h\"\n#include \"driver/spi_master.h\"\n#endif\n\n#ifdef CONFIG_NAND_FLASH_ENABLE_BDL\n#include \"esp_blockdev.h\"\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct spi_nand_flash_device_t spi_nand_flash_device_t;\n\n\n#ifdef CONFIG_IDF_TARGET_LINUX\n#include \"nand_linux_mmap_emul.h\"\n#endif\n\n/** @brief SPI mode used for reading from SPI NAND Flash */\ntypedef enum {\n    SPI_NAND_IO_MODE_SIO = 0,\n    SPI_NAND_IO_MODE_DOUT,\n    SPI_NAND_IO_MODE_DIO,\n    SPI_NAND_IO_MODE_QOUT,\n    SPI_NAND_IO_MODE_QIO,\n} spi_nand_flash_io_mode_t;\n\n/** @brief Structure to describe how to configure the nand access layer.\n @note For DIO and DOUT mode The spi_device_handle_t must be initialized with the flag SPI_DEVICE_HALFDUPLEX\n SIO mode can be initialized with half-duplex or full-duplex mode\n*/\nstruct spi_nand_flash_config_t {\n#ifndef CONFIG_IDF_TARGET_LINUX\n    spi_device_handle_t device_handle;       ///< SPI Device for this nand chip.\n#else\n    nand_file_mmap_emul_config_t *emul_conf;\n#endif\n    uint8_t gc_factor;                       ///< The gc factor controls the number of blocks to spare block ratio.\n    ///< Lower values will reduce the available space but increase performance\n    spi_nand_flash_io_mode_t io_mode;        ///< set io mode for SPI NAND communication\n    uint8_t flags;                           ///< set flag with SPI_DEVICE_HALFDUPLEX for half duplex communication, 0 for full-duplex.\n    ///< This flag value must match the flag value in the spi_device_interface_config_t structure.\n};\n\ntypedef struct spi_nand_flash_config_t spi_nand_flash_config_t;\n\n/** @brief Initialise SPI nand flash chip interface.\n *\n * This function must be called before calling any other API functions for the nand flash.\n *\n * @param config Pointer to SPI nand flash config structure.\n * @param[out] handle The handle to the SPI nand flash chip is returned in this variable.\n * @return ESP_OK on success, or a flash error code if the initialisation failed.\n *\n * @note When CONFIG_NAND_FLASH_ENABLE_BDL is enabled, this function returns ESP_ERR_NOT_SUPPORTED.\n *       Use spi_nand_flash_init_with_layers() instead.\n */\nesp_err_t spi_nand_flash_init_device(spi_nand_flash_config_t *config, spi_nand_flash_device_t **handle);\n\n//-----------------------------------------------------------------------------\n// Page API (preferred terminology; NAND flash is page-based)\n//-----------------------------------------------------------------------------\n\n/** @brief Read a page from the nand flash.\n *\n * @param handle The handle to the SPI nand flash chip.\n * @param[out] buffer The output buffer to put the read data into (must hold at least page_size bytes).\n * @param page_id Logical page index to read.\n * @return ESP_OK on success, or a flash error code if the read failed.\n */\nesp_err_t spi_nand_flash_read_page(spi_nand_flash_device_t *handle, uint8_t *buffer, uint32_t page_id);\n\n/** @brief Write a page to the nand flash.\n *\n * @param handle The handle to the SPI nand flash chip.\n * @param buffer The input buffer containing the data to write (must hold at least page_size bytes).\n * @param page_id Logical page index to write.\n * @return ESP_OK on success, or a flash error code if the write failed.\n */\nesp_err_t spi_nand_flash_write_page(spi_nand_flash_device_t *handle, const uint8_t *buffer, uint32_t page_id);\n\n/** @brief Copy a page to another page within the nand flash.\n *\n * @param handle The handle to the SPI nand flash chip.\n * @param src_page Source logical page index.\n * @param dst_page Destination logical page index.\n * @return ESP_OK on success, or a flash error code if the copy failed.\n */\nesp_err_t spi_nand_flash_copy_page(spi_nand_flash_device_t *handle, uint32_t src_page, uint32_t dst_page);\n\n/** @brief Trim a page from the nand flash.\n *\n * Marks the specified logical page as free to optimize memory usage and support wear-leveling.\n * Typically invoked when files are deleted or resized.\n *\n * @param handle The handle to the SPI nand flash chip.\n * @param page_id Logical page index to trim.\n * @return ESP_OK on success, or a flash error code if the trim failed.\n */\nesp_err_t spi_nand_flash_trim(spi_nand_flash_device_t *handle, uint32_t page_id);\n\n/** @brief Get the number of logical pages (capacity).\n *\n * @param handle The handle to the SPI nand flash chip.\n * @param[out] number_of_pages Pointer to store the total number of logical pages.\n * @return ESP_OK on success, or a flash error code if the operation failed.\n */\nesp_err_t spi_nand_flash_get_page_count(spi_nand_flash_device_t *handle, uint32_t *number_of_pages);\n\n/** @brief Get the size of each logical page in bytes.\n *\n * @param handle The handle to the SPI nand flash chip.\n * @param[out] page_size Pointer to store the page size in bytes.\n * @return ESP_OK on success, or a flash error code if the operation failed.\n */\nesp_err_t spi_nand_flash_get_page_size(spi_nand_flash_device_t *handle, uint32_t *page_size);\n\n//-----------------------------------------------------------------------------\n// Sector API (backward-compatible aliases; equivalent to page API)\n//-----------------------------------------------------------------------------\n\n/** @brief Read a sector (alias for spi_nand_flash_read_page).\n * @deprecated Use spi_nand_flash_read_page() for new code. Sector and page are equivalent in this API.\n */\nesp_err_t spi_nand_flash_read_sector(spi_nand_flash_device_t *handle, uint8_t *buffer, uint32_t sector_id);\n\n/** @brief Copy a sector (alias for spi_nand_flash_copy_page).\n * @deprecated Use spi_nand_flash_copy_page() for new code.\n */\nesp_err_t spi_nand_flash_copy_sector(spi_nand_flash_device_t *handle, uint32_t src_sec, uint32_t dst_sec);\n\n/** @brief Write a sector (alias for spi_nand_flash_write_page).\n * @deprecated Use spi_nand_flash_write_page() for new code.\n */\nesp_err_t spi_nand_flash_write_sector(spi_nand_flash_device_t *handle, const uint8_t *buffer, uint32_t sector_id);\n\n/** @brief Get number of sectors (alias for spi_nand_flash_get_page_count).\n * @deprecated Use spi_nand_flash_get_page_count() for new code.\n */\nesp_err_t spi_nand_flash_get_capacity(spi_nand_flash_device_t *handle, uint32_t *number_of_sectors);\n\n/** @brief Get sector size (alias for spi_nand_flash_get_page_size).\n * @deprecated Use spi_nand_flash_get_page_size() for new code.\n */\nesp_err_t spi_nand_flash_get_sector_size(spi_nand_flash_device_t *handle, uint32_t *sector_size);\n\n/** @brief Synchronizes any cache to the device.\n *\n * After this method is called, the nand flash chip should be synchronized with the results of any previous read/writes.\n *\n * @param handle The handle to the SPI nand flash chip.\n * @return ESP_OK on success, or a flash error code if the synchronization failed.\n */\nesp_err_t spi_nand_flash_sync(spi_nand_flash_device_t *handle);\n\n/** @brief Retrieve the size of each block.\n *\n * @param handle The handle to the SPI nand flash chip.\n * @param[out] block_size A pointer of where to put the return value\n * @return ESP_OK on success, or a flash error code if the operation failed.\n */\nesp_err_t spi_nand_flash_get_block_size(spi_nand_flash_device_t *handle, uint32_t *block_size);\n\n/** @brief Erases the entire chip, invalidating any data on the chip.\n *\n * @param handle The handle to the SPI nand flash chip.\n * @return ESP_OK on success, or a flash error code if the erase failed.\n */\nesp_err_t spi_nand_erase_chip(spi_nand_flash_device_t *handle);\n\n/** @brief Retrieve the number of blocks available.\n *\n * @param handle The handle to the SPI nand flash chip.\n * @param[out] number_of_blocks A pointer of where to put the return value\n * @return ESP_OK on success, or a flash error code if the operation failed.\n */\nesp_err_t spi_nand_flash_get_block_num(spi_nand_flash_device_t *handle, uint32_t *number_of_blocks);\n\n/** @brief Perform explicit garbage collection step\n *\n * This function triggers one garbage collection step in the wear-leveling layer.\n * It reclaims blocks with garbage pages by copying valid data and erasing physical blocks.\n *\n * Note: Garbage collection happens automatically during write operations based on\n * the gc_factor setting. This function is useful when you want to proactively\n * reclaim space during idle time.\n *\n * @param handle The handle to the SPI nand flash chip.\n * @return ESP_OK on success, or a flash error code if the operation failed.\n */\nesp_err_t spi_nand_flash_gc(spi_nand_flash_device_t *handle);\n\n/** @brief De-initialize the handle, releasing any resources reserved.\n *\n * @param handle The handle to the SPI nand flash chip.\n * @return ESP_OK on success, or a flash error code if the de-initialization failed.\n */\nesp_err_t spi_nand_flash_deinit_device(spi_nand_flash_device_t *handle);\n\n//---------------------------------------------------------------------------------------------------------------------------------------------\n// NEW LAYERED ARCHITECTURE API\n//---------------------------------------------------------------------------------------------------------------------------------------------\n\n#ifdef CONFIG_NAND_FLASH_ENABLE_BDL\n\n/** @brief Initialize SPI NAND Flash with separate layer block devices\n *\n * This function provides direct access to the layered architecture, allowing\n * users to work with the flash and wear-leveling layers separately.\n * Both layers are exposed as standard esp_blockdev_t interfaces.\n *\n * @param config Configuration for the SPI NAND flash\n * @param[out] wl_bdl Pointer to store the Wear-Leveling Block Device Layer handle\n * @return\n *         - ESP_OK: Success\n *         - ESP_ERR_INVALID_ARG: Invalid configuration or NULL pointers\n *         - ESP_ERR_NO_MEM: Insufficient memory\n *         - ESP_ERR_NOT_FOUND: NAND device not detected\n */\nesp_err_t spi_nand_flash_init_with_layers(spi_nand_flash_config_t *config,\n        esp_blockdev_handle_t *wl_bdl);\n#endif // CONFIG_NAND_FLASH_ENABLE_BDL\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "spi_nand_flash/include/spi_nand_flash_test_helpers.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include <stddef.h>\n#include <stdint.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** Fill a buffer with a deterministic uint32_t pattern (for testing). */\nvoid spi_nand_flash_fill_buffer(uint8_t *dst, size_t count);\n\n/**\n * @brief Fill buffer with a deterministic pattern using a caller-supplied seed.\n *\n * Pattern: word[i] = seed + i (uint32_t words). Use a different seed per write\n * round to produce distinct data across multiple overwrites of the same sector.\n *\n * @param dst   Destination buffer (must be 4-byte aligned, count * 4 bytes)\n * @param count Number of uint32_t words to fill\n * @param seed  Pattern seed value\n */\nvoid spi_nand_flash_fill_buffer_seeded(uint8_t *dst, size_t count, uint32_t seed);\n\n/**\n * Check buffer against the same deterministic pattern.\n * @return 0 on match, 1-based index of first mismatch on failure.\n */\nint spi_nand_flash_check_buffer(const uint8_t *src, size_t count);\n\n/**\n * Check buffer against spi_nand_flash_fill_buffer_seeded(@p seed).\n * @return 0 on match, 1-based index of first mismatch on failure.\n */\nint spi_nand_flash_check_buffer_seeded(const uint8_t *src, size_t count, uint32_t seed);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "spi_nand_flash/layered_architecture.md",
    "content": "# SPI NAND Flash Layered Architecture\n\nThis document describes the layered architecture implemented in the spi_nand_flash component, designed to provide cleaner separation of concerns, better maintainability, and enhanced extensibility while maintaining full backward compatibility.\n\n## Feature Configuration\n\nThe component supports two modes of operation controlled by Kconfig:\n\n- **Legacy Mode** (default): Traditional API only, minimal memory footprint\n- **BDL Mode** (`CONFIG_NAND_FLASH_ENABLE_BDL=y`): Includes Block Device Layer support with advanced features\n\n### Kconfig Options\n\n#### `CONFIG_NAND_FLASH_ENABLE_BDL`\n**Type:** `bool`\n**Default:** `n`\n**Description:** Enable Block Device Layer (BDL) support for SPI NAND Flash\n\nWhen enabled, provides:\n- Standard `esp_blockdev_t` interface for layered architecture\n- Flash Block Device Layer (raw NAND flash access)\n- Wear-Leveling Block Device Layer (logical page access with wear leveling)\n- Advanced layered API (`spi_nand_flash_init_with_layers`)\n\nWhen disabled, only the legacy API is available.\n\n**Enable via menuconfig:**\n```\nComponent config → SPI NAND Flash configuration → [*] Enable Block Device Layer (BDL) support\n```\n\n**Note:** BDL support requires ESP-IDF 6.0 or later (for the `esp_blockdev` component). The option is not available on older IDF versions.\n\n## Architecture Overview\n\n### Layered Structure\n\n#### Legacy Mode (Default)\n```\nApplication\n     ↓\n┌────────────────────────────────────────┐\n│ spi_nand_flash.h (Public API)         │ ← Legacy Interface\n│ - spi_nand_flash_init_device()        │\n│ - spi_nand_flash_read_page()          │\n│ - spi_nand_flash_write_page()         │\n│ - spi_nand_flash_trim()                │\n│ - spi_nand_flash_sync()                │\n│ - spi_nand_flash_gc()                  │\n│ (+ sector-named aliases for compat)   │\n└────────────────────────────────────────┘\n     ↓\n┌────────────────────────────────────────┐\n│ NAND Wear-Leveling Layer               │ ← Logical Sector Management\n│ (dhara_glue.c)                         │\n│ - Logical-to-physical mapping          │\n│ - Wear leveling (Dhara integration)    │\n│ - Bad block management                 │\n│ - Garbage collection                   │\n└────────────────────────────────────────┘\n     ↓\n┌────────────────────────────────────────┐\n│ NAND Flash Implementation              │ ← Physical Flash Operations\n│ (nand_impl.c)                          │\n│ - Physical page/block operations       │\n│ - Device-specific implementations      │\n│ - ECC error handling                   │\n│ - Direct hardware access               │\n└────────────────────────────────────────┘\n     ↓\n┌────────────────────────────────────────┐\n│ SPI NAND Operations / Emulation        │ ← Hardware Abstraction\n│ (spi_nand_oper.c / nand_linux_mmap_   │\n│  emul.c)                               │\n│ - SPI transaction handling (ESP)       │\n│ - Memory-mapped file emulation (Linux) │\n│ - Command execution                    │\n│ - Register access                      │\n└────────────────────────────────────────┘\n```\n\n#### BDL Mode (CONFIG_NAND_FLASH_ENABLE_BDL=y)\n```\nApplication / Filesystem\n     ↓\n┌────────────────────────────────────────┐\n│ spi_nand_flash.h (Public API)         │ ← Legacy + BDL Interface\n│ Legacy API + BDL API:                  │\n│ - spi_nand_flash_init_with_layers()   │\n└────────────────────────────────────────┘\n     ↓\n┌────────────────────────────────────────┐\n│ Direct BDL Access                      │ ← esp_blockdev_t interface\n│ (Application / Filesystem)             │\n│ - Read/Write/Erase via                 │\n│   esp_blockdev_t interface             │\n│ - nand_flash_get_blockdev()            │\n│ - spi_nand_flash_wl_get_blockdev()    │\n└────────────────────────────────────────┘\n     ↓\n┌──────────────────────────────────────────────────────────────┐\n│ NAND Wear-Leveling BDL (esp_blockdev_t interface)           │\n│ (dhara_glue.c, nand_wl_blockdev.c)                          │\n│ - Logical-to-physical mapping                                │\n│ - Wear leveling (Dhara integration)                          │\n│ - Bad block management                                       │\n│ - Garbage collection                                         │\n│ - TRIM support                                               │\n└──────────────────────────────────────────────────────────────┘\n     ↓\n┌──────────────────────────────────────────────────────────────┐\n│ NAND Flash BDL (esp_blockdev_t interface)                   │\n│ (nand_flash_blockdev.c, nand_impl.c)                        │\n│ - Physical page/block operations                             │\n│ - Device-specific implementations                            │\n│ - ECC error handling and statistics                          │\n│ - Bad block detection and marking                            │\n│ - Direct hardware access                                     │\n│ - IOCTL commands for advanced operations                     │\n└──────────────────────────────────────────────────────────────┘\n     ↓\n┌──────────────────────────────────────────────────────────────┐\n│ SPI NAND Operations / Emulation                              │\n│ (spi_nand_oper.c / nand_linux_mmap_emul.c)                  │\n│ - SPI transaction handling (ESP)                             │\n│ - Memory-mapped file emulation (Linux)                       │\n│ - Command execution                                          │\n│ - Register access                                            │\n└──────────────────────────────────────────────────────────────┘\n```\n\n### Key Improvements\n\n1. **Clear Separation of Concerns**\n   - **Wear-Leveling Layer**: Handles logical-to-physical address mapping, wear leveling, and high-level bad block management\n   - **Flash Layer**: Manages physical flash operations, device detection, and low-level error handling\n   - **SPI Layer**: Handles SPI communication and command execution\n\n2. **Better Maintainability**\n   - Each layer has well-defined interfaces\n   - Reduced coupling between components\n   - Easier to test individual layers (Linux emulation support)\n   - Clear header organization\n\n3. **Enhanced Extensibility**\n   - Easy to add new wear-leveling algorithms\n   - Support for different NAND flash types\n   - Better error handling and recovery\n\n## Header File Organization\n\n### Public Headers (`include/`)\n\n- **`spi_nand_flash.h`** - Main public API\n  - **Page API** (Always available, preferred):\n    - `spi_nand_flash_init_device()` - Initialize NAND flash device\n    - `spi_nand_flash_read_page()` - Read logical page\n    - `spi_nand_flash_write_page()` - Write logical page\n    - `spi_nand_flash_copy_page()` - Copy page\n    - `spi_nand_flash_trim()` - Trim/discard logical page\n    - `spi_nand_flash_get_page_count()` - Get number of logical pages\n    - `spi_nand_flash_get_page_size()` - Get page size in bytes\n    - `spi_nand_flash_sync()` - Synchronize cache to device\n    - `spi_nand_flash_gc()` - Explicit garbage collection\n    - `spi_nand_flash_get_block_size()` - Get block size\n    - `spi_nand_flash_get_block_num()` - Get number of blocks\n    - `spi_nand_erase_chip()` - Erase entire chip\n    - `spi_nand_flash_deinit_device()` - De-initialize device\n  - **Sector API** (Backward-compatible aliases; equivalent to page API):\n    - `spi_nand_flash_read_sector()` → `spi_nand_flash_read_page()`\n    - `spi_nand_flash_write_sector()` → `spi_nand_flash_write_page()`\n    - `spi_nand_flash_copy_sector()` → `spi_nand_flash_copy_page()`\n    - `spi_nand_flash_get_capacity()` → `spi_nand_flash_get_page_count()`\n    - `spi_nand_flash_get_sector_size()` → `spi_nand_flash_get_page_size()`\n  - **BDL API** (Conditional - requires `CONFIG_NAND_FLASH_ENABLE_BDL`):\n    - `spi_nand_flash_init_with_layers()` - Initialize with BDL handles\n\n- **`nand_device_types.h`** - Common types and definitions\n  - `nand_ecc_status_t` - ECC status enumeration\n  - `nand_ecc_data_t` - ECC configuration and status\n  - `nand_flash_geometry_t` - Flash geometry (page size, block size, timing, planes, ECC data)\n  - `nand_device_info_t` - Device identification (manufacturer ID, device ID, chip name)\n\n- **`esp_nand_blockdev.h`** - Block device interface (Conditional - requires `CONFIG_NAND_FLASH_ENABLE_BDL`)\n  - `nand_flash_get_blockdev()` - Create Flash BDL\n  - `spi_nand_flash_wl_get_blockdev()` - Create Wear-Leveling BDL\n  - NAND-specific IOCTL commands\n  - Argument structures for IOCTL operations\n\n- **`nand_diag_api.h`** - Diagnostic and statistics API\n  - `nand_get_bad_block_stats()` - Get bad block count across the flash\n  - `nand_get_ecc_stats()` - Display ECC error statistics\n\n- **`nand_linux_mmap_emul.h`** - Linux emulation configuration\n  - `nand_file_mmap_emul_config_t` - Configuration for memory-mapped file emulation\n\n- **`spi_nand_flash_test_helpers.h`** - Helpers for test applications (e.g. emulation config, test fixtures)\n\n- **`nand_private/nand_impl_wrap.h`** - Wrapper API for implementation operations\n\n### Private Headers (`priv_include/`)\n\n- **`nand.h`** - Internal device structure and operations\n  - `spi_nand_flash_device_t` - Main device handle\n  - `nand_wl_attach_ops()` / `nand_wl_detach_ops()` - Dhara integration\n\n- **`nand_impl.h`** - Low-level flash operations\n  - `nand_init_device()` - Internal device initialization\n  - Page read/write/erase functions\n  - Bad block management\n  - ECC status handling\n\n- **`nand_flash_devices.h`** - Device identification and initialization\n  - Manufacturer IDs and device IDs\n  - Device-specific initialization functions\n\n- **`spi_nand_oper.h`** - SPI operations (ESP targets only)\n  - SPI transaction functions\n  - Register read/write operations\n\n## Source File Organization\n\n### Core Implementation (`src/`)\n\n```\nsrc/\n├── nand.c                      # Public API implementation (Always compiled)\n│                               # - spi_nand_flash_init_device()\n│                               # - spi_nand_flash_read_page() / write_page() / copy_page()\n│                               # - spi_nand_flash_get_page_count() / get_page_size()\n│                               # - spi_nand_flash_trim() / sync() / gc()\n│                               # - Sector-named aliases (backward compatible)\n│                               # - spi_nand_flash_init_with_layers() [BDL only]\n│\n├── dhara_glue.c                # Wear-Leveling implementation (Always compiled)\n│                               # - Dhara library integration\n│                               # - nand_wl_attach_ops() / nand_wl_detach_ops()\n│                               # - Logical-to-physical mapping\n│                               # - Conditional BDL handle support\n│\n├── nand_impl_wrap.c            # Wrapper for nand_impl operations (Always compiled)\n│                               # - Mutex-protected wrappers\n│\n├── nand_impl.c                 # Flash layer implementation\n│                               # - Device detection and initialization\n│                               # - nand_read(), nand_prog(), nand_erase()\n│                               # - nand_is_bad(), nand_mark_bad()\n│                               # - nand_is_free()\n│                               # - ECC error detection and handling\n│                               # - Plane selection support\n│\n├── nand_impl_linux.c           # Flash layer implementation (Linux target only)\n│                               # - Memory-mapped file emulation backend\n│\n├── nand_linux_mmap_emul.c      # Linux emulation (Linux target only)\n│                               # - Memory-mapped file I/O\n│\n├── nand_flash_blockdev.c       # Flash BDL adapter [BDL only]\n│                               # - nand_flash_get_blockdev()\n│                               # - esp_blockdev_t interface implementation\n│                               # - IOCTL command handling\n│                               # - Boundary checks for operations\n│\n├── nand_wl_blockdev.c          # WL BDL adapter [BDL only]\n│                               # - spi_nand_flash_wl_get_blockdev()\n│                               # - esp_blockdev_t interface implementation\n│                               # - Wear-leveling operations\n│                               # - Page read/write/trim\n│                               # - Function pointer validation\n│\n├── nand_diag_api.c             # Diagnostic and statistics API\n│                               # - Bad block statistics\n│                               # - ECC error statistics\n│\n├── spi_nand_flash_test_helpers.c  # Test helpers (shared by test_app and host_test)\n│\n├── spi_nand_oper.c             # SPI operations (ESP targets only)\n│                               # - SPI transaction handling\n│                               # - Multi-mode support (SIO/DOUT/DIO/QOUT/QIO)\n│\n└── devices/                    # Device-specific implementations (ESP targets only)\n    ├── nand_winbond.c          # Winbond NAND flash support\n    ├── nand_gigadevice.c       # GigaDevice NAND flash support\n    ├── nand_alliance.c         # Alliance NAND flash support\n    ├── nand_micron.c           # Micron NAND flash support\n    ├── nand_zetta.c            # Zetta NAND flash support\n    └── nand_xtx.c              # XTX NAND flash support\n```\n\n## API Usage\n\n### Page API (Always Available, Preferred)\n\nThe public API uses **page** terminology to align with NAND flash (logical pages with wear-leveling). This API is always available regardless of Kconfig settings. Sector-named functions remain available as backward-compatible aliases.\n\n```c\n#include \"spi_nand_flash.h\"\n\n// Configure SPI NAND flash\nspi_nand_flash_config_t config = {\n    .device_handle = spi_handle,\n    .io_mode = SPI_NAND_IO_MODE_QIO,\n    .flags = SPI_DEVICE_HALFDUPLEX,\n};\n\nspi_nand_flash_device_t *handle;\n\n// Initialize device\nesp_err_t ret = spi_nand_flash_init_device(&config, &handle);\nif (ret != ESP_OK) {\n    ESP_LOGE(TAG, \"Failed to initialize NAND flash\");\n    return ret;\n}\n\n// Read/write pages\nuint32_t page_size;\nspi_nand_flash_get_page_size(handle, &page_size);\nuint8_t *buffer = malloc(page_size);\nuint32_t page_id = 0;\n\nret = spi_nand_flash_read_page(handle, buffer, page_id);\nret = spi_nand_flash_write_page(handle, buffer, page_id);\n\n// TRIM (mark page as free for garbage collection)\nret = spi_nand_flash_trim(handle, page_id);\n\n// Explicit garbage collection (optional - happens automatically)\nret = spi_nand_flash_gc(handle);\n\n// Synchronize cache to device\nret = spi_nand_flash_sync(handle);\n\n// Get capacity information\nuint32_t num_pages;\nspi_nand_flash_get_page_count(handle, &num_pages);\nspi_nand_flash_get_page_size(handle, &page_size);\nESP_LOGI(TAG, \"Capacity: %u pages of %u bytes\", num_pages, page_size);\n\n// Cleanup\nspi_nand_flash_deinit_device(handle);\n```\n\n**Backward compatibility:** The sector-named API (`spi_nand_flash_read_sector`, `spi_nand_flash_write_sector`, `spi_nand_flash_get_capacity`, `spi_nand_flash_get_sector_size`, etc.) is still supported and behaves identically to the page API.\n\n### BDL API (Requires CONFIG_NAND_FLASH_ENABLE_BDL=y)\n\nThe BDL API provides direct access to block device layers, enabling advanced features like raw flash access, detailed ECC statistics, and custom filesystem integration.\n\n#### Method 1: Direct Layer Creation\n\n```c\n#include \"spi_nand_flash.h\"\n#include \"esp_nand_blockdev.h\"\n\n// Configure SPI NAND flash\nspi_nand_flash_config_t config = {\n    .device_handle = spi_handle,\n    .io_mode = SPI_NAND_IO_MODE_QIO,\n    .flags = SPI_DEVICE_HALFDUPLEX,\n};\n\nesp_blockdev_handle_t flash_bdl;\nesp_blockdev_handle_t wl_bdl;\n\n// Step 1: Create Flash Block Device Layer (raw NAND access)\nesp_err_t ret = nand_flash_get_blockdev(&config, &flash_bdl);\nif (ret != ESP_OK) {\n    ESP_LOGE(TAG, \"Failed to create Flash BDL\");\n    return ret;\n}\n\n// Optional: Access raw flash operations directly\nuint8_t page_buffer[2048];\nuint32_t page_addr = 0;\nflash_bdl->ops->read(flash_bdl, page_buffer, sizeof(page_buffer), page_addr, sizeof(page_buffer));\n\n// Check if a block is bad\nesp_blockdev_cmd_arg_status_t bad_block_cmd = { .num = 10 };\nflash_bdl->ops->ioctl(flash_bdl, ESP_BLOCKDEV_CMD_IS_BAD_BLOCK, &bad_block_cmd);\nif (bad_block_cmd.status) {\n    ESP_LOGW(TAG, \"Block 10 is marked as bad\");\n}\n\n// Get detailed flash information\nesp_blockdev_cmd_arg_nand_flash_info_t flash_info;\nflash_bdl->ops->ioctl(flash_bdl, ESP_BLOCKDEV_CMD_GET_NAND_FLASH_INFO, &flash_info);\nESP_LOGI(TAG, \"Chip: %s, Manufacturer: 0x%02x, Device: 0x%04x\",\n         flash_info.device_info.chip_name,\n         flash_info.device_info.manufacturer_id,\n         flash_info.device_info.device_id);\nESP_LOGI(TAG, \"Geometry: %u blocks, %u bytes/page\",\n         flash_info.geometry.num_blocks,\n         flash_info.geometry.page_size);\n\n// Get ECC statistics\nesp_blockdev_cmd_arg_ecc_stats_t ecc_stats;\nflash_bdl->ops->ioctl(flash_bdl, ESP_BLOCKDEV_CMD_GET_ECC_STATS, &ecc_stats);\nESP_LOGI(TAG, \"ECC: %u total errors, %u exceeding threshold, %u uncorrected\",\n         ecc_stats.ecc_total_err_count,\n         ecc_stats.ecc_exceeding_threshold_err_count,\n         ecc_stats.ecc_uncorrected_err_count);\n\n// Step 2: Create Wear-Leveling Block Device Layer\nret = spi_nand_flash_wl_get_blockdev(flash_bdl, &wl_bdl);\nif (ret != ESP_OK) {\n    ESP_LOGE(TAG, \"Failed to create WL BDL\");\n    flash_bdl->ops->release(flash_bdl);\n    return ret;\n}\n\n// Use wear-leveling layer for page-based operations (BDL reports these as \"sectors\")\nuint8_t page_buffer[2048];\nuint32_t page_id = 0;\nwl_bdl->ops->read(wl_bdl, page_buffer, sizeof(page_buffer), page_id, sizeof(page_buffer));\nwl_bdl->ops->write(wl_bdl, page_buffer, page_id, sizeof(page_buffer));\n\n// Cleanup (releases both WL and Flash layers)\nwl_bdl->ops->release(wl_bdl);\n```\n\n#### Method 2: Simplified Initialization\n\n```c\n#include \"spi_nand_flash.h\"\n#include \"esp_nand_blockdev.h\"\n\n// Configure SPI NAND flash\nspi_nand_flash_config_t config = {\n    .device_handle = spi_handle,\n    .io_mode = SPI_NAND_IO_MODE_QIO,\n    .flags = SPI_DEVICE_HALFDUPLEX,\n};\n\nesp_blockdev_handle_t wl_bdl;\n\n// Initialize both layers at once (simplified)\nesp_err_t ret = spi_nand_flash_init_with_layers(&config, &wl_bdl);\nif (ret != ESP_OK) {\n    ESP_LOGE(TAG, \"Failed to initialize NAND flash with layers\");\n    return ret;\n}\n\n// Use wear-leveling BDL for page-based operations\nuint8_t buffer[2048];\nwl_bdl->ops->read(wl_bdl, buffer, sizeof(buffer), 0, sizeof(buffer));\nwl_bdl->ops->write(wl_bdl, buffer, 0, sizeof(buffer));\n\n// Cleanup\nwl_bdl->ops->release(wl_bdl);\n```\n\n## Block Device IOCTL Commands\n\nIOCTL commands provide advanced operations and diagnostics for block devices. These commands are only available when using the BDL API (`CONFIG_NAND_FLASH_ENABLE_BDL=y`).\n\n### Flash BDL Commands\n\nThese commands operate on the Flash Block Device Layer for low-level hardware access:\n\n| Command | Description | Argument Type | Example |\n|---------|-------------|---------------|---------|\n| `ESP_BLOCKDEV_CMD_IS_BAD_BLOCK` | Check if a physical block is marked bad | `esp_blockdev_cmd_arg_status_t*` | Check block health before raw access |\n| `ESP_BLOCKDEV_CMD_MARK_BAD_BLOCK` | Mark a physical block as bad | `uint32_t*` (block number) | Mark block after repeated failures |\n| `ESP_BLOCKDEV_CMD_IS_FREE_PAGE` | Check if a page is erased (0xFF) | `esp_blockdev_cmd_arg_status_t*` | Verify erase operation |\n| `ESP_BLOCKDEV_CMD_GET_PAGE_ECC_STATUS` | Get ECC correction status for a page | `esp_blockdev_cmd_arg_ecc_status_t*` | Monitor bit error rates |\n| `ESP_BLOCKDEV_CMD_GET_BAD_BLOCKS_COUNT` | Get total count of bad blocks | `uint32_t*` | Flash health monitoring |\n| `ESP_BLOCKDEV_CMD_GET_ECC_STATS` | Get comprehensive ECC statistics | `esp_blockdev_cmd_arg_ecc_stats_t*` | Detect flash degradation |\n| `ESP_BLOCKDEV_CMD_GET_NAND_FLASH_INFO` | Get complete device info and geometry | `esp_blockdev_cmd_arg_nand_flash_info_t*` | Query chip details |\n| `ESP_BLOCKDEV_CMD_COPY_PAGE` | Copy a page from source to destination | `esp_blockdev_cmd_arg_copy_page_t*` | Hardware-level page copy |\n\n### WL BDL Commands\n\nThese commands operate on the Wear-Leveling Block Device Layer for logical page management (BDL API uses \"sector\" in command names; each unit is one logical page):\n\n| Command | Description | Argument Type | Example |\n|---------|-------------|---------------|---------|\n| `ESP_BLOCKDEV_CMD_MARK_DELETED` | Mark range as unused (TRIM/discard) | `esp_blockdev_cmd_arg_erase_t*` (start_addr, erase_len; aligned to page size) | Optimize after file deletion |\n\n### Example: Using IOCTL Commands\n\n```c\nesp_blockdev_handle_t flash_bdl;\nnand_flash_get_blockdev(&config, &flash_bdl);\n\n// Check if block 10 is bad\nesp_blockdev_cmd_arg_status_t status_cmd = { .num = 10 };\nflash_bdl->ops->ioctl(flash_bdl, ESP_BLOCKDEV_CMD_IS_BAD_BLOCK, &status_cmd);\nif (status_cmd.status) {\n    ESP_LOGW(TAG, \"Block 10 is bad\");\n}\n\n// Get ECC statistics\nesp_blockdev_cmd_arg_ecc_stats_t ecc_stats;\nflash_bdl->ops->ioctl(flash_bdl, ESP_BLOCKDEV_CMD_GET_ECC_STATS, &ecc_stats);\nESP_LOGI(TAG, \"Total ECC errors: %u\", ecc_stats.ecc_total_err_count);\nESP_LOGI(TAG, \"ECC errors exceeding threshold: %u\", ecc_stats.ecc_exceeding_threshold_err_count);\nESP_LOGI(TAG, \"Uncorrectable ECC errors: %u\", ecc_stats.ecc_uncorrected_err_count);\n\n// Get flash information\nesp_blockdev_cmd_arg_nand_flash_info_t info;\nflash_bdl->ops->ioctl(flash_bdl, ESP_BLOCKDEV_CMD_GET_NAND_FLASH_INFO, &info);\nESP_LOGI(TAG, \"Chip: %s\", info.device_info.chip_name);\nESP_LOGI(TAG, \"Capacity: %u blocks × %u bytes/page\",\n         info.geometry.num_blocks,\n         info.geometry.page_size);\n\n// Copy a page\nesp_blockdev_cmd_arg_copy_page_t copy_cmd = { .src_page = 10, .dst_page = 20 };\nflash_bdl->ops->ioctl(flash_bdl, ESP_BLOCKDEV_CMD_COPY_PAGE, &copy_cmd);\n```\n\n## Testing and Validation\n\n### Target Testing\n\nThe component includes a comprehensive test application in `test_app/`:\n\n```bash\ncd test_app\nidf.py build flash monitor\n```\n\nTests are automatically selected based on Kconfig (main entry is `test_app_main.c`):\n- **Legacy tests** (`test_spi_nand_flash.c`): Run when `CONFIG_NAND_FLASH_ENABLE_BDL=n`\n- **BDL tests** (`test_spi_nand_flash_bdl.c`): Run when `CONFIG_NAND_FLASH_ENABLE_BDL=y`\n\n### Linux Host Testing\n\nThe component supports host-based testing on Linux using memory-mapped file emulation:\n\n```c\n#ifdef CONFIG_IDF_TARGET_LINUX\n#include \"nand_linux_mmap_emul.h\"\n\n// Configure emulation\nnand_file_mmap_emul_config_t emul_cfg = {\n    .flash_file_name = \"\",              // Empty = auto-generate temp file\n    .flash_file_size = 50 * 1024 * 1024, // 50MB\n    .keep_dump = false                   // Delete file on cleanup\n};\n\nspi_nand_flash_config_t config = {\n    .emul_conf = &emul_cfg,\n    // ... other config ...\n};\n\n// Use normally - will emulate NAND flash\nspi_nand_flash_device_t *handle;\nspi_nand_flash_init_device(&config, &handle);\n#endif\n```\n\n**Build and run host tests:**\n```bash\ncd host_test\nidf.py --preview set-target linux\nidf.py build monitor\n```\n\nHost tests also conditionally compile based on Kconfig (main entry is `test_app_main.cpp`):\n- **Legacy tests** (`test_nand_flash.cpp`): Compiled when `CONFIG_NAND_FLASH_ENABLE_BDL=n`\n- **BDL tests** (`test_nand_flash_bdl.cpp`): Compiled when `CONFIG_NAND_FLASH_ENABLE_BDL=y`\n\nSee `host_test/README.md` for more details.\n\n## Safety Improvements\n\nThe component includes comprehensive safety checks to prevent common programming errors:\n\n### Boundary Checks\n\nAll division and modulo operations include zero-divisor checks:\n\n```c\n// Example from nand_wl_blockdev.c\nif (page_size == 0) {\n    ESP_LOGE(TAG, \"Invalid page size (0)\");\n    return ESP_ERR_INVALID_SIZE;\n}\nuint32_t page_count = erase_len / page_size;\n```\n\n**Protected operations:**\n- Page size calculations\n- Block size calculations\n- Page count calculations\n- Plane selection (modulo operations)\n\n### Alignment Validation\n\nRead, write, and erase operations validate address and length alignment:\n\n```c\n// Example: Erase alignment check\nif ((start_addr % page_size) != 0) {\n    ESP_LOGE(TAG, \"Start address not aligned to page size\");\n    return ESP_ERR_INVALID_ARG;\n}\n\nif ((erase_len % page_size) != 0) {\n    ESP_LOGE(TAG, \"Erase length not aligned to page size\");\n    return ESP_ERR_INVALID_ARG;\n}\n```\n\n### Function Pointer Validation\n\nBDL creation validates all required operations are available:\n\n```c\n// Example from spi_nand_flash_wl_get_blockdev()\nESP_RETURN_ON_FALSE(nand_bdl != NULL, ESP_ERR_INVALID_ARG, TAG, \"nand_bdl cannot be NULL\");\nESP_RETURN_ON_FALSE(nand_bdl->ops != NULL, ESP_ERR_INVALID_STATE, TAG, \"Flash BDL ops cannot be NULL\");\nESP_RETURN_ON_FALSE(nand_bdl->ops->read != NULL, ESP_ERR_INVALID_STATE, TAG, \"Flash BDL read operation is required\");\nESP_RETURN_ON_FALSE(nand_bdl->ops->write != NULL, ESP_ERR_INVALID_STATE, TAG, \"Flash BDL write operation is required\");\n// ... more validation\n```\n\n## Migration Guide (0.x → 1.0.0)\n\n### FATFS Integration Separated\n\nFATFS support has been moved to a separate `spi_nand_flash_fatfs` component. If your project\nuses FATFS with NAND flash:\n1. Add `spi_nand_flash_fatfs` as a dependency in your `idf_component.yml`.\n2. Include headers from `spi_nand_flash_fatfs` instead of the old unified headers.\n3. Use **`spi_nand_flash_init_device()`** and keep **`CONFIG_NAND_FLASH_ENABLE_BDL` disabled**.\n   When BDL is enabled, `spi_nand_flash_init_device()` returns `ESP_ERR_NOT_SUPPORTED`. **This release does not\n   provide FatFs on top of the wear-leveling BDL** (`esp_blockdev_t`); that will be added in a\n   future component update.\n4. Aside from the component split and the BDL constraint above, FatFs usage matches 0.x\n   (same mount helpers and diskio behavior).\n\n### For Existing Projects (Legacy API)\n\nThe existing legacy API (`spi_nand_flash_init_device`, `read_sector`, `write_sector`, etc.)\ncontinues to work **as long as `CONFIG_NAND_FLASH_ENABLE_BDL` is not enabled**.\n\n> **Important:** When `CONFIG_NAND_FLASH_ENABLE_BDL` is enabled via Kconfig,\n> `spi_nand_flash_init_device()` returns `ESP_ERR_NOT_SUPPORTED`.\n> You must use `spi_nand_flash_init_with_layers()` instead.\n\nThe \"sector\" API functions are now deprecated aliases for the equivalent \"page\" functions.\nConsider migrating to the page terminology (`read_page`, `write_page`, `get_page_count`,\n`get_page_size`) for clarity.\n\n### For New Projects (BDL API)\n\nNew projects are encouraged to use the Block Device Layer API, which provides:\n- Direct flash access (raw page/block operations) — see **`nand_flash_get_blockdev()`**;\n  for most workloads prefer the **wear-leveling** BDL (Dhara FTL: wear leveling, bad-block\n  management, logical sectors). Raw flash BDL is mainly for diagnostics, bring-up etc.\n- Advanced diagnostics operations (ECC stats, bad block tracking)\n- Integration with consumers of **`esp_blockdev_t`** (this release does **not** include\n  FatFs-on-BDL for SPI NAND; use **`spi_nand_flash_fatfs`** with BDL off for FatFs)\n- Fine-grained control over layers\n\n### Enabling BDL Support\n\nTo enable BDL support in your project:\n\n1. **Via menuconfig:**\n   ```\n   idf.py menuconfig\n   → Component config\n   → SPI NAND Flash configuration\n   → [*] Enable Block Device Layer (BDL) support\n   ```\n2. Use `spi_nand_flash_init_with_layers()` to initialize.\n3. Interact with the flash through `esp_blockdev_t` handles returned by initialization.\n\n## Error Handling\n\nThe layered architecture provides comprehensive error reporting at each level:\n\n### Hardware Layer Errors\n- **SPI Communication Failures**: `ESP_ERR_TIMEOUT`, `ESP_FAIL`\n- **ECC Errors**: `ESP_ERR_FLASH_BASE + DHARA_E_ECC`\n- **Bad Block Detection**: Automatic detection and remapping\n\n### Flash Layer Errors\n- **Bad Block**: `ESP_ERR_NOT_FINISHED` when programming to bad block\n- **ECC Failure**: `ESP_ERR_FLASH_BASE + DHARA_E_ECC` for uncorrectable errors\n- **Invalid Parameters**: `ESP_ERR_INVALID_ARG`, `ESP_ERR_INVALID_SIZE`\n- **Alignment Errors**: `ESP_ERR_INVALID_ARG` for misaligned addresses\n\n### Wear-Leveling Layer Errors\n- **Out of Space**: `ESP_ERR_FLASH_BASE + DHARA_E_NAND_FAILED`\n- **Mapping Errors**: `ESP_ERR_FLASH_BASE + DHARA_E_MAP_FAILED`\n- **Garbage Collection Issues**: Automatically retried or reported\n- **Too Many Bad Blocks**: `ESP_ERR_NO_MEM` when insufficient spare blocks\n\n\n## Build Configuration\n\n### CMakeLists.txt Integration\n\nThe component's `CMakeLists.txt` conditionally compiles sources based on target and Kconfig. BDL sources are only added when **ESP-IDF 6.0 or later** is in use (for `esp_blockdev`):\n\n```cmake\n# Base sources (always compiled for all targets)\nset(srcs \"src/nand.c\"\n         \"src/dhara_glue.c\"\n         \"src/nand_impl_wrap.c\")\n\n# BDL support (IDF >= 6.0 only)\nif(\"${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}\" GREATER_EQUAL \"6.0\")\n    list(APPEND reqs esp_blockdev)\n    if(CONFIG_NAND_FLASH_ENABLE_BDL)\n        list(APPEND srcs \"src/nand_flash_blockdev.c\"\n                         \"src/nand_wl_blockdev.c\")\n    endif()\nendif()\n\n# Target-specific sources\nif(${target} STREQUAL \"linux\")\n    list(APPEND srcs \"src/nand_impl_linux.c\"\n                     \"src/nand_linux_mmap_emul.c\"\n                     \"src/spi_nand_flash_test_helpers.c\")\nelse()\n    list(APPEND srcs \"src/devices/nand_winbond.c\"\n                     \"src/devices/nand_gigadevice.c\"\n                     \"src/devices/nand_alliance.c\"\n                     \"src/devices/nand_micron.c\"\n                     \"src/devices/nand_zetta.c\"\n                     \"src/devices/nand_xtx.c\"\n                     \"src/nand_impl.c\"\n                     \"src/nand_diag_api.c\"\n                     \"src/spi_nand_flash_test_helpers.c\"\n                     \"src/spi_nand_oper.c\")\nendif()\n```\n\n## Supported Manufacturers\n\nThe component supports NAND flash chips from multiple manufacturers:\n\n| Manufacturer | File | Example Chips |\n|--------------|------|---------------|\n| Winbond | `src/devices/nand_winbond.c` | W25N01GV, W25N02KV |\n| GigaDevice | `src/devices/nand_gigadevice.c` | GD5F1GQ5UExxG |\n| Alliance | `src/devices/nand_alliance.c` | AS5F31G04SND |\n| Micron | `src/devices/nand_micron.c` | MT29F1G01 |\n| Zetta | `src/devices/nand_zetta.c` | ZD35Q1GA |\n| XTX | `src/devices/nand_xtx.c` | XT26G01C |\n\nDevice detection is automatic based on JEDEC manufacturer and device IDs.\n\n## Summary\n\nThis layered architecture provides:\n\n**Backward Compatibility**: Existing code works without changes\n\n**Conditional Compilation**: Enable BDL only when needed\n\n**Safety**: Comprehensive boundary checks and validation\n\n**Flexibility**: Choose between simple legacy API or advanced BDL API\n\n**Testability**: Linux host testing support\n\n**Extensibility**: Easy to add new features and devices\n\n**Maintainability**: Clear separation of concerns\n\nThe modular design makes the component production-ready while remaining extensible for future development.\n"
  },
  {
    "path": "spi_nand_flash/priv_include/nand.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 mikkeldamsgaard project\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * SPDX-FileContributor: 2015-2024 Espressif Systems (Shanghai) CO LTD\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <stdbool.h>\n#include \"spi_nand_flash.h\"\n#ifdef CONFIG_IDF_TARGET_LINUX\n#include \"nand_linux_mmap_emul.h\"\n#endif\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/semphr.h\"\n#include \"nand_device_types.h\"\n\n#ifdef CONFIG_NAND_FLASH_ENABLE_BDL\n#include \"esp_blockdev.h\"\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define INVALID_PAGE 0xFFFF\n\n#define NAND_FLAG_HAS_PROG_PLANE_SELECT       BIT(0)\n#define NAND_FLAG_HAS_READ_PLANE_SELECT       BIT(1)\n\n// Legacy typedef for compatibility - now uses nand_flash_geometry_t internally\ntypedef nand_flash_geometry_t spi_nand_chip_t;\n\ntypedef struct {\n    esp_err_t (*init)(spi_nand_flash_device_t *handle, void *bdl_handle); //if CONFIG_NAND_FLASH_ENABLE_BDL disabled, bdl_handle should be NULL\n    esp_err_t (*deinit)(spi_nand_flash_device_t *handle);\n    esp_err_t (*read)(spi_nand_flash_device_t *handle, uint8_t *buffer, uint32_t sector_id);\n    esp_err_t (*write)(spi_nand_flash_device_t *handle, const uint8_t *buffer, uint32_t sector_id);\n    esp_err_t (*erase_chip)(spi_nand_flash_device_t *handle);\n    esp_err_t (*erase_block)(spi_nand_flash_device_t *handle, uint32_t block);\n    esp_err_t (*trim)(spi_nand_flash_device_t *handle, uint32_t sector_id);\n    esp_err_t (*sync)(spi_nand_flash_device_t *handle);\n    esp_err_t (*copy_sector)(spi_nand_flash_device_t *handle, uint32_t src_sec, uint32_t dst_sec);\n    esp_err_t (*get_capacity)(spi_nand_flash_device_t *handle, uint32_t *number_of_sectors);\n    esp_err_t (*gc)(spi_nand_flash_device_t *handle);\n} spi_nand_ops;\n\nstruct spi_nand_flash_device_t {\n    spi_nand_flash_config_t config;\n    spi_nand_chip_t chip;                  // Geometry (legacy typedef for nand_flash_geometry_t)\n    nand_device_info_t device_info;        // Device identification (manufacturer, device ID, chip name)\n    const spi_nand_ops *ops;\n    void *ops_priv_data;\n    uint8_t *work_buffer;\n    uint8_t *read_buffer;\n    uint8_t *temp_buffer;\n    SemaphoreHandle_t mutex;\n#ifdef CONFIG_IDF_TARGET_LINUX\n    nand_mmap_emul_handle_t *emul_handle;\n#endif\n};\n\n/** @return true if corrected-bit ECC class meets or exceeds the data-refresh threshold */\nstatic inline bool nand_ecc_exceeds_data_refresh_threshold(const spi_nand_flash_device_t *handle)\n{\n    uint8_t min_bits_corrected = 0;\n    if (handle->chip.ecc_data.ecc_corrected_bits_status == NAND_ECC_1_TO_3_BITS_CORRECTED) {\n        min_bits_corrected = 1;\n    } else if (handle->chip.ecc_data.ecc_corrected_bits_status == NAND_ECC_4_TO_6_BITS_CORRECTED) {\n        min_bits_corrected = 4;\n    } else if (handle->chip.ecc_data.ecc_corrected_bits_status == NAND_ECC_7_8_BITS_CORRECTED) {\n        min_bits_corrected = 7;\n    }\n    return min_bits_corrected >= handle->chip.ecc_data.ecc_data_refresh_threshold;\n}\n\n/**\n * @brief Attach wear-leveling operations to NAND device (internal use only)\n *\n * This function attaches the Dhara wear-leveling operation callbacks to the\n * device, enabling wear-leveling functionality.\n *\n * @param[in] handle  NAND device handle\n *\n * @return\n *         - ESP_OK: Success\n *         - ESP_ERR_INVALID_ARG: Invalid handle\n */\nesp_err_t nand_wl_attach_ops(spi_nand_flash_device_t *handle);\n\n/**\n * @brief Detach wear-leveling operations from NAND device (internal use only)\n *\n * This function detaches the wear-leveling operation callbacks and frees\n * associated private data.\n *\n * @param[in] handle  NAND device handle\n *\n * @return\n *         - ESP_OK: Success\n */\nesp_err_t nand_wl_detach_ops(spi_nand_flash_device_t *handle);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "spi_nand_flash/priv_include/nand_flash_devices.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include <stdint.h>\n#include \"esp_err.h\"\n#include \"spi_nand_flash.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n//=============================================================================\n// MANUFACTURER IDs\n//=============================================================================\n\n#define SPI_NAND_FLASH_GIGADEVICE_MI  0xC8\n#define SPI_NAND_FLASH_ALLIANCE_MI    0x52\n#define SPI_NAND_FLASH_WINBOND_MI     0xEF\n#define SPI_NAND_FLASH_MICRON_MI      0x2C\n#define SPI_NAND_FLASH_ZETTA_MI       0xBA\n#define SPI_NAND_FLASH_XTX_MI         0x0B\n\n//=============================================================================\n// DEVICE IDs\n//=============================================================================\n\n// GigaDevice\n#define GIGADEVICE_DI_51              0x51\n#define GIGADEVICE_DI_41              0x41\n#define GIGADEVICE_DI_31              0x31\n#define GIGADEVICE_DI_21              0x21\n#define GIGADEVICE_DI_52              0x52\n#define GIGADEVICE_DI_42              0x42\n#define GIGADEVICE_DI_32              0x32\n#define GIGADEVICE_DI_22              0x22\n#define GIGADEVICE_DI_55              0x55\n#define GIGADEVICE_DI_45              0x45\n#define GIGADEVICE_DI_35              0x35\n#define GIGADEVICE_DI_25              0x25\n#define GIGADEVICE_DI_95              0x95\n#define GIGADEVICE_DI_85              0x85\n#define GIGADEVICE_DI_92              0x92\n#define GIGADEVICE_DI_82              0x82\n#define GIGADEVICE_DI_91              0x91\n#define GIGADEVICE_DI_81              0x81\n\n// Alliance Memory\n#define ALLIANCE_DI_25                0x25   // AS5F31G04SND-08LIN\n#define ALLIANCE_DI_2E                0x2E   // AS5F32G04SND-08LIN\n#define ALLIANCE_DI_8E                0x8E   // AS5F12G04SND-10LIN\n#define ALLIANCE_DI_2F                0x2F   // AS5F34G04SND-08LIN\n#define ALLIANCE_DI_8F                0x8F   // AS5F14G04SND-10LIN\n#define ALLIANCE_DI_2D                0x2D   // AS5F38G04SND-08LIN\n#define ALLIANCE_DI_8D                0x8D   // AS5F18G04SND-10LIN\n\n// Winbond\n#define WINBOND_DI_AA20               0xAA20\n#define WINBOND_DI_BA20               0xBA20\n#define WINBOND_DI_AA21               0xAA21\n#define WINBOND_DI_BA21               0xBA21\n#define WINBOND_DI_BC21               0xBC21\n#define WINBOND_DI_AA22               0xAA22\n#define WINBOND_DI_AA23               0xAA23\n\n// Micron\n#define MICRON_DI_34                  0x34\n#define MICRON_DI_14                  0x14\n#define MICRON_DI_15                  0x15\n#define MICRON_DI_24                  0x24   // MT29F2G\n\n// Zetta\n#define ZETTA_DI_71                   0x71\n\n// XTX\n#define XTX_DI_37                     0x37\n\n//=============================================================================\n// DEVICE INITIALIZATION FUNCTIONS\n//=============================================================================\n\n/**\n * @brief Initialize GigaDevice NAND flash\n */\nesp_err_t spi_nand_gigadevice_init(spi_nand_flash_device_t *dev);\n\n/**\n * @brief Initialize Alliance Memory NAND flash\n */\nesp_err_t spi_nand_alliance_init(spi_nand_flash_device_t *dev);\n\n/**\n * @brief Initialize Winbond NAND flash\n */\nesp_err_t spi_nand_winbond_init(spi_nand_flash_device_t *dev);\n\n/**\n * @brief Initialize Micron NAND flash\n */\nesp_err_t spi_nand_micron_init(spi_nand_flash_device_t *dev);\n\n/**\n * @brief Initialize Zetta NAND flash\n */\nesp_err_t spi_nand_zetta_init(spi_nand_flash_device_t *dev);\n\n/**\n * @brief Initialize XTX NAND flash\n */\nesp_err_t spi_nand_xtx_init(spi_nand_flash_device_t *dev);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "spi_nand_flash/priv_include/nand_impl.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 mikkeldamsgaard project\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * SPDX-FileContributor: 2015-2023 Espressif Systems (Shanghai) CO LTD\n */\n\n#pragma once\n\n#include <stdint.h>\n#include \"esp_err.h\"\n#include \"nand.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief Initialize NAND flash device (internal use only)\n *\n * This is an internal function that initializes the NAND flash hardware,\n * detects the chip, and creates the device structure. It does NOT create\n * any block device interface.\n *\n * Used by:\n * - nand_flash_get_blockdev() - to create Flash BDL\n * - spi_nand_flash_init_device() - for legacy API\n *\n * @param[in]  config  Configuration for the SPI NAND flash device\n * @param[out] handle  Pointer to store the created NAND device handle\n *\n * @return\n *         - ESP_OK: Success\n *         - ESP_ERR_INVALID_ARG: Invalid configuration or NULL pointer\n *         - ESP_ERR_NO_MEM: Insufficient memory\n *         - ESP_ERR_NOT_FOUND: NAND device not detected\n *\n * @note This is INTERNAL API. Do not use directly in applications.\n */\nesp_err_t nand_init_device(spi_nand_flash_config_t *config,\n                           spi_nand_flash_device_t **handle);\n\nesp_err_t nand_is_bad(spi_nand_flash_device_t *handle, uint32_t b, bool *is_bad_status);\nesp_err_t nand_mark_bad(spi_nand_flash_device_t *handle, uint32_t b);\nesp_err_t nand_erase_chip(spi_nand_flash_device_t *handle);\nesp_err_t nand_erase_block(spi_nand_flash_device_t *handle, uint32_t b);\nesp_err_t nand_prog(spi_nand_flash_device_t *handle, uint32_t p, const uint8_t *data);\nesp_err_t nand_is_free(spi_nand_flash_device_t *handle, uint32_t p, bool *is_free_status);\nesp_err_t nand_read(spi_nand_flash_device_t *handle, uint32_t p, size_t offset, size_t length, uint8_t *data);\nesp_err_t nand_copy(spi_nand_flash_device_t *handle, uint32_t src, uint32_t dst);\nesp_err_t nand_get_ecc_status(spi_nand_flash_device_t *handle, uint32_t page);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "spi_nand_flash/priv_include/spi_nand_oper.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 mikkeldamsgaard project\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * SPDX-FileContributor: 2015-2023 Espressif Systems (Shanghai) CO LTD\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <esp_err.h>\n#include <driver/spi_master.h>\n#include \"nand.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct spi_nand_transaction_t {\n    uint8_t command;\n    uint8_t address_bytes;\n    uint32_t address;\n    uint32_t mosi_len;\n    const uint8_t *mosi_data;\n    uint32_t miso_len;\n    uint8_t *miso_data;\n    uint32_t dummy_bits;\n    uint32_t flags;\n};\n\ntypedef struct spi_nand_transaction_t spi_nand_transaction_t;\n\n#define CMD_SET_REGISTER    0x1F\n#define CMD_READ_REGISTER   0x0F\n#define CMD_WRITE_ENABLE    0x06\n#define CMD_READ_ID         0x9F\n#define CMD_PAGE_READ       0x13\n#define CMD_PROGRAM_EXECUTE 0x10\n#define CMD_PROGRAM_LOAD    0x84\n#define CMD_PROGRAM_LOAD_X4 0x34\n#define CMD_READ_FAST       0x0B\n#define CMD_READ_X2         0x3B\n#define CMD_READ_X4         0x6B\n#define CMD_ERASE_BLOCK     0xD8\n#define CMD_READ_DIO        0xBB\n#define CMD_READ_QIO        0xEB\n\n#define REG_PROTECT         0xA0\n#define REG_CONFIG          0xB0\n#define REG_STATUS          0xC0\n\n#define STAT_BUSY           1 << 0\n#define STAT_WRITE_ENABLED  1 << 1\n#define STAT_ERASE_FAILED   1 << 2\n#define STAT_PROGRAM_FAILED 1 << 3\n#define STAT_ECC0           1 << 4\n#define STAT_ECC1           1 << 5\n#define STAT_ECC2           1 << 6\n\nsize_t spi_nand_get_dma_alignment(void);\nesp_err_t spi_nand_execute_transaction(spi_nand_flash_device_t *handle, spi_nand_transaction_t *transaction);\n\nesp_err_t spi_nand_read_manufacturer_id(spi_nand_flash_device_t *handle, uint8_t *manufacturer_id);\nesp_err_t spi_nand_read_device_id(spi_nand_flash_device_t *handle, uint8_t *device_id, uint8_t length);\nesp_err_t spi_nand_read_register(spi_nand_flash_device_t *handle, uint8_t reg, uint8_t *val);\nesp_err_t spi_nand_write_register(spi_nand_flash_device_t *handle, uint8_t reg, uint8_t val);\nesp_err_t spi_nand_write_enable(spi_nand_flash_device_t *handle);\nesp_err_t spi_nand_read_page(spi_nand_flash_device_t *handle, uint32_t page);\nesp_err_t spi_nand_read(spi_nand_flash_device_t *handle, uint8_t *data, uint16_t column, uint16_t length);\nesp_err_t spi_nand_program_execute(spi_nand_flash_device_t *handle, uint32_t page);\nesp_err_t spi_nand_program_load(spi_nand_flash_device_t *handle, const uint8_t *data, uint16_t column, uint16_t length);\nesp_err_t spi_nand_erase_block(spi_nand_flash_device_t *handle, uint32_t page);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "spi_nand_flash/src/devices/nand_alliance.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <inttypes.h>\n#include \"esp_check.h\"\n#include \"nand.h\"\n#include \"spi_nand_oper.h\"\n#include \"nand_flash_devices.h\"\n\nstatic const char *TAG = \"nand_alliance\";\n\nesp_err_t spi_nand_alliance_init(spi_nand_flash_device_t *dev)\n{\n    esp_err_t ret = ESP_OK;\n    uint8_t device_id = 0;\n    ESP_RETURN_ON_ERROR(spi_nand_read_device_id(dev, &device_id, sizeof(device_id)), TAG, \"%s, Failed to get the device ID %d\", __func__, ret);\n    dev->device_info.device_id = device_id;\n    snprintf(dev->device_info.chip_name, sizeof(dev->device_info.chip_name),\n             \"alliance-0x%02\" PRIx8, device_id);\n    ESP_LOGD(TAG, \"%s: device_id: %x\\n\", __func__, device_id);\n\n    dev->chip.has_quad_enable_bit = 1;\n    dev->chip.quad_enable_bit_pos = 0;\n    dev->chip.erase_block_delay_us = 3000;\n    dev->chip.program_page_delay_us = 630;\n    switch (device_id) {\n    case ALLIANCE_DI_25: //AS5F31G04SND-08LIN\n        dev->chip.num_blocks = 1024;\n        dev->chip.read_page_delay_us = 60;\n        break;\n    case ALLIANCE_DI_2E: //AS5F32G04SND-08LIN\n    case ALLIANCE_DI_8E: //AS5F12G04SND-10LIN\n        dev->chip.num_blocks = 2048;\n        dev->chip.read_page_delay_us = 60;\n        break;\n    case ALLIANCE_DI_2F: //AS5F34G04SND-08LIN\n    case ALLIANCE_DI_8F: //AS5F14G04SND-10LIN\n        dev->chip.num_blocks = 4096;\n        dev->chip.read_page_delay_us = 60;\n        break;\n    case ALLIANCE_DI_2D: //AS5F38G04SND-08LIN\n    case ALLIANCE_DI_8D: //AS5F18G04SND-10LIN\n        dev->chip.log2_page_size = 12; // 4k pages\n        dev->chip.num_blocks = 4096;\n        dev->chip.read_page_delay_us = 130; // somewhat slower reads\n        break;\n    default:\n        return ESP_ERR_INVALID_RESPONSE;\n    }\n    return ESP_OK;\n}\n"
  },
  {
    "path": "spi_nand_flash/src/devices/nand_gigadevice.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <inttypes.h>\n#include \"esp_check.h\"\n#include \"nand.h\"\n#include \"spi_nand_oper.h\"\n#include \"nand_flash_devices.h\"\n\nstatic const char *TAG = \"nand_gigadevice\";\n\nesp_err_t spi_nand_gigadevice_init(spi_nand_flash_device_t *dev)\n{\n    esp_err_t ret = ESP_OK;\n    uint8_t device_id = 0;\n    ESP_RETURN_ON_ERROR(spi_nand_read_device_id(dev, &device_id, sizeof(device_id)), TAG, \"%s, Failed to get the device ID %d\", __func__, ret);\n    dev->device_info.device_id = device_id;\n    snprintf(dev->device_info.chip_name, sizeof(dev->device_info.chip_name),\n             \"gigadevice-0x%02\" PRIx8, device_id);\n    ESP_LOGD(TAG, \"%s: device_id: %x\\n\", __func__, device_id);\n\n    dev->chip.has_quad_enable_bit = 1;\n    dev->chip.quad_enable_bit_pos = 0;\n    dev->chip.read_page_delay_us = 25;\n    dev->chip.erase_block_delay_us = 3200;\n    dev->chip.program_page_delay_us = 380;\n    switch (device_id) {\n    case GIGADEVICE_DI_51:\n    case GIGADEVICE_DI_41:\n    case GIGADEVICE_DI_31:\n    case GIGADEVICE_DI_21:\n    case GIGADEVICE_DI_81:\n    case GIGADEVICE_DI_91:\n        dev->chip.num_blocks = 1024;\n        break;\n    case GIGADEVICE_DI_52:\n    case GIGADEVICE_DI_42:\n    case GIGADEVICE_DI_32:\n    case GIGADEVICE_DI_22:\n    case GIGADEVICE_DI_92:\n    case GIGADEVICE_DI_82:\n        dev->chip.num_blocks = 2048;\n        break;\n    case GIGADEVICE_DI_55:\n    case GIGADEVICE_DI_45:\n    case GIGADEVICE_DI_35:\n    case GIGADEVICE_DI_25:\n        dev->chip.num_blocks = 4096;\n        break;\n    case GIGADEVICE_DI_95:\n    case GIGADEVICE_DI_85:\n        dev->chip.num_blocks = 4096;\n        dev->chip.flags = NAND_FLAG_HAS_PROG_PLANE_SELECT | NAND_FLAG_HAS_READ_PLANE_SELECT;\n        dev->chip.num_planes = 2;\n        break;\n    default:\n        return ESP_ERR_INVALID_RESPONSE;\n    }\n    return ESP_OK;\n}\n"
  },
  {
    "path": "spi_nand_flash/src/devices/nand_micron.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <inttypes.h>\n#include \"esp_check.h\"\n#include \"nand.h\"\n#include \"spi_nand_oper.h\"\n#include \"nand_flash_devices.h\"\n\nstatic const char *TAG = \"nand_micron\";\n\nesp_err_t spi_nand_micron_init(spi_nand_flash_device_t *dev)\n{\n    esp_err_t ret = ESP_OK;\n    uint8_t device_id = 0;\n    ESP_RETURN_ON_ERROR(spi_nand_read_device_id(dev, &device_id, sizeof(device_id)), TAG, \"%s, Failed to get the device ID %d\", __func__, ret);\n    dev->device_info.device_id = device_id;\n    snprintf(dev->device_info.chip_name, sizeof(dev->device_info.chip_name),\n             \"micron-0x%02\" PRIx8, device_id);\n    ESP_LOGD(TAG, \"%s: device_id: %x\\n\", __func__, device_id);\n\n    dev->chip.has_quad_enable_bit = 0;\n    dev->chip.quad_enable_bit_pos = 0;\n    dev->chip.ecc_data.ecc_status_reg_len_in_bits = 3;\n    dev->chip.erase_block_delay_us = 2000;\n    switch (device_id) {\n    case MICRON_DI_34:\n        dev->chip.read_page_delay_us = 115;\n        dev->chip.program_page_delay_us = 240;\n        dev->chip.num_blocks = 2048;\n        dev->chip.log2_ppb = 6;        // 64 pages per block\n        dev->chip.log2_page_size = 12; // 4096 bytes per page\n        break;\n    case MICRON_DI_14:\n    case MICRON_DI_15:\n        dev->chip.read_page_delay_us = 46;\n        dev->chip.program_page_delay_us = 220;\n        dev->chip.num_blocks = 1024;\n        dev->chip.log2_ppb = 6;          // 64 pages per block\n        dev->chip.log2_page_size = 11;   // 2048 bytes per page\n        break;\n    case MICRON_DI_24:\n        dev->chip.read_page_delay_us = 55;\n        dev->chip.program_page_delay_us = 220;\n        dev->chip.num_blocks = 2048;\n        dev->chip.log2_ppb = 6;        // 64 pages per block\n        dev->chip.log2_page_size = 11; // 2048 bytes per page\n        dev->chip.flags = NAND_FLAG_HAS_PROG_PLANE_SELECT | NAND_FLAG_HAS_READ_PLANE_SELECT;\n        dev->chip.num_planes = 2;\n        break;\n    default:\n        return ESP_ERR_INVALID_RESPONSE;\n    }\n    return ESP_OK;\n}\n"
  },
  {
    "path": "spi_nand_flash/src/devices/nand_winbond.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <inttypes.h>\n#include \"esp_check.h\"\n#include \"nand.h\"\n#include \"spi_nand_oper.h\"\n#include \"nand_flash_devices.h\"\n\nstatic const char *TAG = \"nand_winbond\";\n\n#define SWAP_BYTES(x)  (uint16_t)((((x) & 0xFF) << 8) | (((x) >> 8) & 0xFF))\n\nesp_err_t spi_nand_winbond_init(spi_nand_flash_device_t *dev)\n{\n    esp_err_t ret = ESP_OK;\n    uint16_t device_id;\n    ESP_RETURN_ON_ERROR(spi_nand_read_device_id(dev, (uint8_t *)&device_id, sizeof(device_id)), TAG, \"%s, Failed to get the device ID %d\", __func__, ret);\n    device_id = SWAP_BYTES(device_id);\n    dev->device_info.device_id = device_id;\n    snprintf(dev->device_info.chip_name, sizeof(dev->device_info.chip_name),\n             \"winbond-0x%04\" PRIx16, device_id);\n    ESP_LOGD(TAG, \"%s: device_id: %x\\n\", __func__, device_id);\n\n    dev->chip.has_quad_enable_bit = 0;\n    dev->chip.quad_enable_bit_pos = 0;\n    dev->chip.read_page_delay_us = 10;\n    dev->chip.erase_block_delay_us = 2500;\n    dev->chip.program_page_delay_us = 320;\n    switch (device_id) {\n    case WINBOND_DI_AA20:\n    case WINBOND_DI_BA20:\n        dev->chip.num_blocks = 512;\n        break;\n    case WINBOND_DI_AA21:\n    case WINBOND_DI_BA21:\n    case WINBOND_DI_BC21:\n        dev->chip.num_blocks = 1024;\n        break;\n    case WINBOND_DI_AA22:\n        dev->chip.num_blocks = 2048;\n        break;\n    case WINBOND_DI_AA23:\n        dev->chip.num_blocks = 4096;\n        break;\n    default:\n        return ESP_ERR_INVALID_RESPONSE;\n    }\n    return ESP_OK;\n}\n"
  },
  {
    "path": "spi_nand_flash/src/devices/nand_xtx.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <inttypes.h>\n#include \"esp_check.h\"\n#include \"nand.h\"\n#include \"spi_nand_oper.h\"\n#include \"nand_flash_devices.h\"\n\nstatic const char *TAG = \"nand_xtx\";\n\nesp_err_t spi_nand_xtx_init(spi_nand_flash_device_t *dev)\n{\n    esp_err_t ret = ESP_OK;\n    uint8_t device_id = 0;\n    ESP_RETURN_ON_ERROR(spi_nand_read_device_id(dev, &device_id, sizeof(device_id)), TAG, \"%s, Failed to get the device ID %d\", __func__, ret);\n    dev->device_info.device_id = device_id;\n    snprintf(dev->device_info.chip_name, sizeof(dev->device_info.chip_name),\n             \"xtx-0x%02\" PRIx8, device_id);\n    ESP_LOGD(TAG, \"%s: device_id: %x\\n\", __func__, device_id);\n\n    dev->chip.has_quad_enable_bit = 1;\n    dev->chip.quad_enable_bit_pos = 0;\n    dev->chip.erase_block_delay_us = 3500;\n    dev->chip.program_page_delay_us = 650;\n    dev->chip.read_page_delay_us = 50;\n    switch (device_id) {\n    case XTX_DI_37: //XT26G08D\n        dev->chip.num_blocks = 4096;\n        dev->chip.log2_ppb = 6;        // 64 pages per block\n        dev->chip.log2_page_size = 12; // 4096 bytes per page\n        break;\n    default:\n        return ESP_ERR_INVALID_RESPONSE;\n    }\n    return ESP_OK;\n}\n"
  },
  {
    "path": "spi_nand_flash/src/devices/nand_zetta.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <inttypes.h>\n#include \"esp_check.h\"\n#include \"nand.h\"\n#include \"spi_nand_oper.h\"\n#include \"nand_flash_devices.h\"\n\nstatic const char *TAG = \"nand_zetta\";\n\nesp_err_t spi_nand_zetta_init(spi_nand_flash_device_t *dev)\n{\n    esp_err_t ret = ESP_OK;\n    uint8_t device_id = 0;\n    ESP_RETURN_ON_ERROR(spi_nand_read_device_id(dev, &device_id, sizeof(device_id)), TAG, \"%s, Failed to get the device ID %d\", __func__, ret);\n    dev->device_info.device_id = device_id;\n    snprintf(dev->device_info.chip_name, sizeof(dev->device_info.chip_name),\n             \"zetta-0x%02\" PRIx8, device_id);\n    ESP_LOGD(TAG, \"%s: device_id: %x\\n\", __func__, device_id);\n\n    dev->chip.has_quad_enable_bit = 1;\n    dev->chip.quad_enable_bit_pos = 0;\n    dev->chip.erase_block_delay_us = 2000;\n    dev->chip.program_page_delay_us = 400;\n    switch (device_id) {\n    case ZETTA_DI_71:\n        dev->chip.num_blocks = 1024;\n        dev->chip.read_page_delay_us = 250;\n        break;\n    default:\n        return ESP_ERR_INVALID_RESPONSE;\n    }\n    return ESP_OK;\n}\n"
  },
  {
    "path": "spi_nand_flash/src/dhara_glue.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 mikkeldamsgaard project\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * SPDX-FileContributor: 2015-2024 Espressif Systems (Shanghai) CO LTD\n */\n\n#include <string.h>\n#include <sys/lock.h>\n#include \"dhara/nand.h\"\n#include \"dhara/map.h\"\n#include \"dhara/error.h\"\n#include \"esp_check.h\"\n#include \"esp_err.h\"\n#ifndef CONFIG_IDF_TARGET_LINUX\n#include \"spi_nand_oper.h\"\n#endif\n#include \"nand_impl.h\"\n#include \"nand.h\"\n#include \"nand_device_types.h\"\n\n#ifdef CONFIG_NAND_FLASH_ENABLE_BDL\n#include \"esp_nand_blockdev.h\"\n#endif\n\ntypedef struct {\n    struct dhara_nand dhara_nand;\n    struct dhara_map dhara_map;\n#ifdef CONFIG_NAND_FLASH_ENABLE_BDL\n    esp_blockdev_handle_t bdl_handle;\n#endif\n    spi_nand_flash_device_t *parent_handle;\n} spi_nand_flash_dhara_priv_data_t;\n\nstatic esp_err_t dhara_init(spi_nand_flash_device_t *handle, void *bdl_handle)\n{\n    // create a holder structure for dhara context\n    spi_nand_flash_dhara_priv_data_t *dhara_priv_data = heap_caps_calloc(1, sizeof(spi_nand_flash_dhara_priv_data_t), MALLOC_CAP_DEFAULT);\n    if (dhara_priv_data == NULL) {\n        return ESP_ERR_NO_MEM;\n    }\n    handle->ops_priv_data = dhara_priv_data;\n    // store the pointer back to device structure in the holder structure\n    dhara_priv_data->parent_handle = handle;\n#ifdef CONFIG_NAND_FLASH_ENABLE_BDL\n    dhara_priv_data->bdl_handle = (esp_blockdev_handle_t)bdl_handle;\n#endif\n\n    dhara_priv_data->dhara_nand.log2_page_size = handle->chip.log2_page_size;\n    dhara_priv_data->dhara_nand.log2_ppb = handle->chip.log2_ppb;\n    dhara_priv_data->dhara_nand.num_blocks = handle->chip.num_blocks;\n\n    dhara_map_init(&dhara_priv_data->dhara_map, &dhara_priv_data->dhara_nand, handle->work_buffer, handle->config.gc_factor);\n    dhara_error_t ignored;\n    dhara_map_resume(&dhara_priv_data->dhara_map, &ignored);\n\n    return ESP_OK;\n}\n\nstatic esp_err_t dhara_deinit(spi_nand_flash_device_t *handle)\n{\n    spi_nand_flash_dhara_priv_data_t *dhara_priv_data = (spi_nand_flash_dhara_priv_data_t *)handle->ops_priv_data;\n    // clear dhara map\n    dhara_map_init(&dhara_priv_data->dhara_map, &dhara_priv_data->dhara_nand, handle->work_buffer, handle->config.gc_factor);\n    dhara_map_clear(&dhara_priv_data->dhara_map);\n    return ESP_OK;\n}\n\nstatic esp_err_t dhara_read(spi_nand_flash_device_t *handle, uint8_t *buffer, dhara_sector_t sector_id)\n{\n    spi_nand_flash_dhara_priv_data_t *dhara_priv_data = (spi_nand_flash_dhara_priv_data_t *)handle->ops_priv_data;\n    dhara_error_t err;\n    if (dhara_map_read(&dhara_priv_data->dhara_map, sector_id, handle->read_buffer, &err)) {\n        return ESP_ERR_FLASH_BASE + err;\n    }\n    memcpy(buffer, handle->read_buffer, handle->chip.page_size);\n    return ESP_OK;\n}\n\nstatic esp_err_t dhara_write(spi_nand_flash_device_t *handle, const uint8_t *buffer, dhara_sector_t sector_id)\n{\n    spi_nand_flash_dhara_priv_data_t *dhara_priv_data = (spi_nand_flash_dhara_priv_data_t *)handle->ops_priv_data;\n    dhara_error_t err;\n    if (dhara_map_write(&dhara_priv_data->dhara_map, sector_id, buffer, &err)) {\n        return ESP_ERR_FLASH_BASE + err;\n    }\n    return ESP_OK;\n}\n\nstatic esp_err_t dhara_copy_sector(spi_nand_flash_device_t *handle, dhara_sector_t src_sec, dhara_sector_t dst_sec)\n{\n    spi_nand_flash_dhara_priv_data_t *dhara_priv_data = (spi_nand_flash_dhara_priv_data_t *)handle->ops_priv_data;\n    dhara_error_t err;\n    if (dhara_map_copy_sector(&dhara_priv_data->dhara_map, src_sec, dst_sec, &err)) {\n        return ESP_ERR_FLASH_BASE + err;\n    }\n    return ESP_OK;\n}\n\nstatic esp_err_t dhara_trim(spi_nand_flash_device_t *handle, dhara_sector_t sector_id)\n{\n    spi_nand_flash_dhara_priv_data_t *dhara_priv_data = (spi_nand_flash_dhara_priv_data_t *)handle->ops_priv_data;\n    dhara_error_t err;\n    if (dhara_map_trim(&dhara_priv_data->dhara_map, sector_id, &err)) {\n        return ESP_ERR_FLASH_BASE + err;\n    }\n    return ESP_OK;\n}\n\nstatic esp_err_t dhara_sync(spi_nand_flash_device_t *handle)\n{\n    spi_nand_flash_dhara_priv_data_t *dhara_priv_data = (spi_nand_flash_dhara_priv_data_t *)handle->ops_priv_data;\n    dhara_error_t err;\n    if (dhara_map_sync(&dhara_priv_data->dhara_map, &err)) {\n        return ESP_ERR_FLASH_BASE + err;\n    }\n    return ESP_OK;\n}\n\nstatic esp_err_t dhara_get_capacity(spi_nand_flash_device_t *handle, dhara_sector_t *number_of_sectors)\n{\n    spi_nand_flash_dhara_priv_data_t *dhara_priv_data = (spi_nand_flash_dhara_priv_data_t *)handle->ops_priv_data;\n    *number_of_sectors = dhara_map_capacity(&dhara_priv_data->dhara_map);\n    return ESP_OK;\n}\n\nstatic esp_err_t dhara_gc(spi_nand_flash_device_t *handle)\n{\n    spi_nand_flash_dhara_priv_data_t *dhara_priv_data = (spi_nand_flash_dhara_priv_data_t *)handle->ops_priv_data;\n    dhara_error_t err;\n    if (dhara_map_gc(&dhara_priv_data->dhara_map, &err)) {\n        return ESP_ERR_FLASH_BASE + err;\n    }\n    return ESP_OK;\n}\n\nstatic esp_err_t dhara_erase_chip(spi_nand_flash_device_t *handle)\n{\n    return nand_erase_chip(handle);\n}\n\nstatic esp_err_t dhara_erase_block(spi_nand_flash_device_t *handle, uint32_t block)\n{\n    return nand_erase_block(handle, block);\n}\n\n\nconst spi_nand_ops dhara_nand_ops = {\n    .init = &dhara_init,\n    .deinit = &dhara_deinit,\n    .read = &dhara_read,\n    .write = &dhara_write,\n    .erase_chip = &dhara_erase_chip,\n    .erase_block = &dhara_erase_block,\n    .trim = &dhara_trim,\n    .sync = &dhara_sync,\n    .copy_sector = &dhara_copy_sector,\n    .get_capacity = &dhara_get_capacity,\n    .gc = &dhara_gc,\n};\n\nesp_err_t nand_wl_attach_ops(spi_nand_flash_device_t *handle)\n{\n    if (handle == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    handle->ops = &dhara_nand_ops;\n    return ESP_OK;\n}\n\nesp_err_t nand_wl_detach_ops(spi_nand_flash_device_t *handle)\n{\n    free(handle->ops_priv_data);\n    handle->ops = NULL;\n    return ESP_OK;\n}\n\n/*------------------------------------------------------------------------------------------------------*/\n\n\n// The following APIs are implementations required by the Dhara library.\n// Please refer to the header file dhara/nand.h for details.\n\nint dhara_nand_read(const struct dhara_nand *n, dhara_page_t p, size_t offset, size_t length,\n                    uint8_t *data, dhara_error_t *err)\n{\n    spi_nand_flash_dhara_priv_data_t *dhara_priv_data = __containerof(n, spi_nand_flash_dhara_priv_data_t, dhara_nand);\n    spi_nand_flash_device_t *dev_handle = NULL;\n    esp_err_t ret = ESP_OK;\n#ifdef CONFIG_NAND_FLASH_ENABLE_BDL\n    assert(dhara_priv_data->bdl_handle != NULL);\n    esp_blockdev_handle_t bdl_handle = dhara_priv_data->bdl_handle;\n    dev_handle = (spi_nand_flash_device_t *)bdl_handle->ctx;\n    ret = bdl_handle->ops->read(bdl_handle, data, length,\n                                (p * bdl_handle->geometry.read_size) + offset, length);\n#else\n    dev_handle = dhara_priv_data->parent_handle;\n    ret = nand_read(dev_handle, p, offset, length, data);\n#endif\n    if (ret != ESP_OK) {\n        if (dev_handle->chip.ecc_data.ecc_corrected_bits_status == NAND_ECC_NOT_CORRECTED) {\n            dhara_set_error(err, DHARA_E_ECC);\n        }\n        return -1;\n    }\n    return 0;\n}\n\nint dhara_nand_prog(const struct dhara_nand *n, dhara_page_t p, const uint8_t *data, dhara_error_t *err)\n{\n    spi_nand_flash_dhara_priv_data_t *dhara_priv_data = __containerof(n, spi_nand_flash_dhara_priv_data_t, dhara_nand);\n    esp_err_t ret = ESP_OK;\n#ifdef CONFIG_NAND_FLASH_ENABLE_BDL\n    assert(dhara_priv_data->bdl_handle != NULL);\n    esp_blockdev_handle_t bdl_handle = dhara_priv_data->bdl_handle;\n    ret = bdl_handle->ops->write(bdl_handle, data, (p * bdl_handle->geometry.write_size),\n                                 bdl_handle->geometry.write_size);\n#else\n    spi_nand_flash_device_t *dev_handle = dhara_priv_data->parent_handle;\n    ret = nand_prog(dev_handle, p, data);\n#endif\n    if (ret) {\n        if (ret == ESP_ERR_NOT_FINISHED) {\n            dhara_set_error(err, DHARA_E_BAD_BLOCK);\n        }\n        return -1;\n    }\n    return 0;\n}\n\nint dhara_nand_erase(const struct dhara_nand *n, dhara_block_t b, dhara_error_t *err)\n{\n    spi_nand_flash_dhara_priv_data_t *dhara_priv_data = __containerof(n, spi_nand_flash_dhara_priv_data_t, dhara_nand);\n    esp_err_t ret = ESP_OK;\n#ifdef CONFIG_NAND_FLASH_ENABLE_BDL\n    assert(dhara_priv_data->bdl_handle != NULL);\n    esp_blockdev_handle_t bdl_handle = dhara_priv_data->bdl_handle;\n    ret = bdl_handle->ops->erase(bdl_handle, b * bdl_handle->geometry.erase_size,\n                                 bdl_handle->geometry.erase_size);\n#else\n    spi_nand_flash_device_t *dev_handle = dhara_priv_data->parent_handle;\n    ret = nand_erase_block(dev_handle, b);\n#endif\n    if (ret) {\n        if (ret == ESP_ERR_NOT_FINISHED) {\n            dhara_set_error(err, DHARA_E_BAD_BLOCK);\n        }\n        return -1;\n    }\n    return 0;\n}\n\nint dhara_nand_is_bad(const struct dhara_nand *n, dhara_block_t b)\n{\n    spi_nand_flash_dhara_priv_data_t *dhara_priv_data = __containerof(n, spi_nand_flash_dhara_priv_data_t, dhara_nand);\n    bool is_bad_status = false;\n    esp_err_t ret = ESP_OK;\n#ifdef CONFIG_NAND_FLASH_ENABLE_BDL\n    assert(dhara_priv_data->bdl_handle != NULL);\n    esp_blockdev_handle_t bdl_handle = dhara_priv_data->bdl_handle;\n    esp_blockdev_cmd_arg_is_bad_block_t bad_block_status = {b, false};\n    ret = bdl_handle->ops->ioctl(bdl_handle, ESP_BLOCKDEV_CMD_IS_BAD_BLOCK, &bad_block_status);\n    is_bad_status = bad_block_status.status;\n#else\n    spi_nand_flash_device_t *dev_handle = dhara_priv_data->parent_handle;\n    ret = nand_is_bad(dev_handle, b, &is_bad_status);\n#endif\n    if (ret || is_bad_status == true) {\n        return 1;\n    }\n    return 0;\n}\n\nvoid dhara_nand_mark_bad(const struct dhara_nand *n, dhara_block_t b)\n{\n    spi_nand_flash_dhara_priv_data_t *dhara_priv_data = __containerof(n, spi_nand_flash_dhara_priv_data_t, dhara_nand);\n#ifdef CONFIG_NAND_FLASH_ENABLE_BDL\n    assert(dhara_priv_data->bdl_handle != NULL);\n    esp_blockdev_handle_t bdl_handle = dhara_priv_data->bdl_handle;\n    uint32_t block = b;\n    bdl_handle->ops->ioctl(bdl_handle, ESP_BLOCKDEV_CMD_MARK_BAD_BLOCK, &block);\n#else\n    spi_nand_flash_device_t *dev_handle = dhara_priv_data->parent_handle;\n    nand_mark_bad(dev_handle, b);\n#endif\n    return;\n}\n\nint dhara_nand_is_free(const struct dhara_nand *n, dhara_page_t p)\n{\n    spi_nand_flash_dhara_priv_data_t *dhara_priv_data = __containerof(n, spi_nand_flash_dhara_priv_data_t, dhara_nand);\n    bool is_free_status = true;\n    esp_err_t ret = ESP_OK;\n#ifdef CONFIG_NAND_FLASH_ENABLE_BDL\n    assert(dhara_priv_data->bdl_handle != NULL);\n    esp_blockdev_handle_t bdl_handle = dhara_priv_data->bdl_handle;\n    esp_blockdev_cmd_arg_is_free_page_t page_free_status = {p, true};\n    ret = bdl_handle->ops->ioctl(bdl_handle, ESP_BLOCKDEV_CMD_IS_FREE_PAGE, &page_free_status);\n    is_free_status = page_free_status.status;\n#else\n    spi_nand_flash_device_t *dev_handle = dhara_priv_data->parent_handle;\n    ret = nand_is_free(dev_handle, p, &is_free_status);\n#endif\n\n    if (ret != ESP_OK) {\n        return 0;\n    }\n    if (is_free_status == true) {\n        return 1;\n    }\n    return 0;\n}\n\nint dhara_nand_copy(const struct dhara_nand *n, dhara_page_t src, dhara_page_t dst, dhara_error_t *err)\n{\n    spi_nand_flash_dhara_priv_data_t *dhara_priv_data = __containerof(n, spi_nand_flash_dhara_priv_data_t, dhara_nand);\n    spi_nand_flash_device_t *dev_handle = NULL;\n    esp_err_t ret = ESP_OK;\n\n#ifdef CONFIG_NAND_FLASH_ENABLE_BDL\n    assert(dhara_priv_data->bdl_handle != NULL);\n    esp_blockdev_handle_t bdl_handle = dhara_priv_data->bdl_handle;\n    dev_handle = (spi_nand_flash_device_t *)bdl_handle->ctx;\n    esp_blockdev_cmd_arg_copy_page_t copy_arg = {\n        .src_page = src,\n        .dst_page = dst\n    };\n    ret = dhara_priv_data->bdl_handle->ops->ioctl(bdl_handle, ESP_BLOCKDEV_CMD_COPY_PAGE, &copy_arg);\n#else\n    dev_handle = dhara_priv_data->parent_handle;\n    ret = nand_copy(dev_handle, src, dst);\n#endif\n    if (ret) {\n        if (dev_handle->chip.ecc_data.ecc_corrected_bits_status == NAND_ECC_NOT_CORRECTED) {\n            dhara_set_error(err, DHARA_E_ECC);\n        }\n        if (ret == ESP_ERR_NOT_FINISHED) {\n            dhara_set_error(err, DHARA_E_BAD_BLOCK);\n        }\n        return -1;\n    }\n    return 0;\n}\n"
  },
  {
    "path": "spi_nand_flash/src/nand.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 mikkeldamsgaard project\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * SPDX-FileContributor: 2015-2024 Espressif Systems (Shanghai) CO LTD\n */\n\n#include <string.h>\n#include \"esp_check.h\"\n#include \"spi_nand_flash.h\"\n#include \"nand.h\"\n#include \"nand_impl.h\"\n#include \"nand_device_types.h\"\n\n#ifdef CONFIG_NAND_FLASH_ENABLE_BDL\n#include \"esp_blockdev.h\"\n#include \"esp_nand_blockdev.h\"\n#endif\n\nstatic const char *TAG = \"nand_api\";\n\nesp_err_t spi_nand_flash_init_device(spi_nand_flash_config_t *config, spi_nand_flash_device_t **handle)\n{\n#ifdef CONFIG_NAND_FLASH_ENABLE_BDL\n    ESP_LOGE(TAG, \"spi_nand_flash_init_device() is not supported when BDL is enabled. \"\n             \"Use spi_nand_flash_init_with_layers() instead\");\n    return ESP_ERR_NOT_SUPPORTED;\n#else\n    if (!config->gc_factor) {\n        config->gc_factor = 45;\n    }\n\n    esp_err_t ret = nand_init_device(config, handle);\n    if (ret != ESP_OK) {\n        return ret;\n    }\n\n    ret = nand_wl_attach_ops(*handle);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to attach wear-leveling operations\");\n    }\n\n    if ((*handle)->ops->init == NULL) {\n        ESP_LOGE(TAG, \"Failed to initialize spi_nand_ops\");\n        ret = ESP_FAIL;\n        return ret;\n    }\n    (*handle)->ops->init(*handle, NULL);\n\n    return ESP_OK;\n#endif // CONFIG_NAND_FLASH_ENABLE_BDL\n}\n\nesp_err_t spi_nand_erase_chip(spi_nand_flash_device_t *handle)\n{\n    ESP_LOGW(TAG, \"Entire chip is being erased\");\n    esp_err_t ret = ESP_OK;\n\n    if (handle->ops->erase_chip == NULL) {\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n\n    xSemaphoreTake(handle->mutex, portMAX_DELAY);\n    ret = handle->ops->erase_chip(handle);\n    if (ret) {\n        goto end;\n    }\n    handle->ops->deinit(handle);\n\nend:\n    xSemaphoreGive(handle->mutex);\n    return ret;\n}\n\nesp_err_t spi_nand_flash_read_page(spi_nand_flash_device_t *handle, uint8_t *buffer, uint32_t page_id)\n{\n    esp_err_t ret = ESP_OK;\n\n    if (handle->ops->read == NULL) {\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n\n    xSemaphoreTake(handle->mutex, portMAX_DELAY);\n    ret = handle->ops->read(handle, buffer, page_id);\n    // After a successful read operation, check the ECC corrected bit status; if the read fails, return an error\n    if (ret == ESP_OK && handle->chip.ecc_data.ecc_corrected_bits_status) {\n        // This indicates a soft ECC error, we rewrite the page to recover if corrected bits are greater than refresh threshold\n        if (nand_ecc_exceeds_data_refresh_threshold(handle)) {\n            ret = handle->ops->write(handle, buffer, page_id);\n        }\n    }\n    xSemaphoreGive(handle->mutex);\n\n    return ret;\n}\n\nesp_err_t spi_nand_flash_read_sector(spi_nand_flash_device_t *handle, uint8_t *buffer, uint32_t sector_id)\n{\n    return spi_nand_flash_read_page(handle, buffer, sector_id);\n}\n\nesp_err_t spi_nand_flash_copy_page(spi_nand_flash_device_t *handle, uint32_t src_page, uint32_t dst_page)\n{\n    esp_err_t ret = ESP_OK;\n\n    if (handle->ops->copy_sector == NULL) {\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n\n    xSemaphoreTake(handle->mutex, portMAX_DELAY);\n    ret = handle->ops->copy_sector(handle, src_page, dst_page);\n    xSemaphoreGive(handle->mutex);\n\n    return ret;\n}\n\nesp_err_t spi_nand_flash_copy_sector(spi_nand_flash_device_t *handle, uint32_t src_sec, uint32_t dst_sec)\n{\n    return spi_nand_flash_copy_page(handle, src_sec, dst_sec);\n}\n\nesp_err_t spi_nand_flash_write_page(spi_nand_flash_device_t *handle, const uint8_t *buffer, uint32_t page_id)\n{\n    esp_err_t ret = ESP_OK;\n\n    if (handle->ops->write == NULL) {\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n\n    xSemaphoreTake(handle->mutex, portMAX_DELAY);\n    ret = handle->ops->write(handle, buffer, page_id);\n    xSemaphoreGive(handle->mutex);\n\n    return ret;\n}\n\nesp_err_t spi_nand_flash_write_sector(spi_nand_flash_device_t *handle, const uint8_t *buffer, uint32_t sector_id)\n{\n    return spi_nand_flash_write_page(handle, buffer, sector_id);\n}\n\nesp_err_t spi_nand_flash_trim(spi_nand_flash_device_t *handle, uint32_t page_id)\n{\n    esp_err_t ret = ESP_OK;\n\n    if (handle->ops->trim == NULL) {\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n\n    xSemaphoreTake(handle->mutex, portMAX_DELAY);\n    ret = handle->ops->trim(handle, page_id);\n    xSemaphoreGive(handle->mutex);\n\n    return ret;\n}\n\nesp_err_t spi_nand_flash_sync(spi_nand_flash_device_t *handle)\n{\n    esp_err_t ret = ESP_OK;\n\n    if (handle->ops->sync == NULL) {\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n\n    xSemaphoreTake(handle->mutex, portMAX_DELAY);\n    ret = handle->ops->sync(handle);\n    xSemaphoreGive(handle->mutex);\n\n    return ret;\n}\n\nesp_err_t spi_nand_flash_gc(spi_nand_flash_device_t *handle)\n{\n    esp_err_t ret = ESP_OK;\n\n    if (handle->ops->gc == NULL) {\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n\n    xSemaphoreTake(handle->mutex, portMAX_DELAY);\n    ret = handle->ops->gc(handle);\n    xSemaphoreGive(handle->mutex);\n\n    return ret;\n}\n\nesp_err_t spi_nand_flash_get_page_count(spi_nand_flash_device_t *handle, uint32_t *number_of_pages)\n{\n    if (handle->ops->get_capacity == NULL) {\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n\n    return handle->ops->get_capacity(handle, number_of_pages);\n}\n\nesp_err_t spi_nand_flash_get_capacity(spi_nand_flash_device_t *handle, uint32_t *number_of_sectors)\n{\n    return spi_nand_flash_get_page_count(handle, number_of_sectors);\n}\n\nesp_err_t spi_nand_flash_get_page_size(spi_nand_flash_device_t *handle, uint32_t *page_size)\n{\n    *page_size = handle->chip.page_size;\n    return ESP_OK;\n}\n\nesp_err_t spi_nand_flash_get_sector_size(spi_nand_flash_device_t *handle, uint32_t *sector_size)\n{\n    return spi_nand_flash_get_page_size(handle, sector_size);\n}\n\nesp_err_t spi_nand_flash_get_block_size(spi_nand_flash_device_t *handle, uint32_t *block_size)\n{\n    *block_size = handle->chip.block_size;\n    return ESP_OK;\n}\n\nesp_err_t spi_nand_flash_get_block_num(spi_nand_flash_device_t *handle, uint32_t *num_blocks)\n{\n    *num_blocks = handle->chip.num_blocks;\n    return ESP_OK;\n}\n\nesp_err_t spi_nand_flash_deinit_device(spi_nand_flash_device_t *handle)\n{\n    esp_err_t ret = ESP_OK;\n#ifdef CONFIG_IDF_TARGET_LINUX\n    ret = nand_emul_deinit(handle);\n#endif\n    nand_wl_detach_ops(handle);\n    free(handle->work_buffer);\n    free(handle->read_buffer);\n#ifndef CONFIG_IDF_TARGET_LINUX\n    free(handle->temp_buffer);\n#endif\n    if (handle->mutex) {\n        vSemaphoreDelete(handle->mutex);\n    }\n    free(handle);\n    return ret;\n}\n\n// NEW LAYERED ARCHITECTURE API IMPLEMENTATION\n//---------------------------------------------------------------------------------------------------------------------------------------------\n\n#ifdef CONFIG_NAND_FLASH_ENABLE_BDL\nesp_err_t spi_nand_flash_init_with_layers(spi_nand_flash_config_t *config,\n        esp_blockdev_handle_t *wl_bdl)\n{\n    ESP_RETURN_ON_FALSE(config && wl_bdl, ESP_ERR_INVALID_ARG, TAG, \"Invalid arguments\");\n\n    // Set default GC factor if not specified\n    if (!config->gc_factor) {\n        config->gc_factor = 45;\n    }\n\n    // Initialize device and create Flash BDL\n    esp_blockdev_handle_t flash_bdl;\n    esp_err_t ret = nand_flash_get_blockdev(config, &flash_bdl);\n    ESP_RETURN_ON_ERROR(ret, TAG, \"Failed to create Flash BDL\");\n\n    // Create WL BDL on top of Flash BDL (already a block device layer!)\n    ret = spi_nand_flash_wl_get_blockdev(flash_bdl, wl_bdl);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to create WL BDL\");\n        (flash_bdl)->ops->release(flash_bdl);\n        flash_bdl = NULL;\n        return ret;\n    }\n\n    ESP_LOGD(TAG, \"SPI NAND Flash initialized with layered block device architecture\");\n    return ESP_OK;\n}\n#endif // CONFIG_NAND_FLASH_ENABLE_BDL\n"
  },
  {
    "path": "spi_nand_flash/src/nand_diag_api.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"esp_system.h\"\n#include \"spi_nand_flash.h\"\n#include \"nand.h\"\n#include \"nand_private/nand_impl_wrap.h\"\n#include \"esp_log.h\"\n#include \"esp_check.h\"\n#include \"nand_device_types.h\"\n\nstatic const char *TAG = \"nand_diag\";\n\nesp_err_t nand_get_bad_block_stats(spi_nand_flash_device_t *flash, uint32_t *bad_block_count)\n{\n    esp_err_t ret = ESP_OK;\n    uint32_t bad_blocks = 0;\n    uint32_t num_blocks;\n    spi_nand_flash_get_block_num(flash, &num_blocks);\n    for (uint32_t blk = 0; blk < num_blocks; blk++) {\n        bool is_bad = false;\n        ret = nand_wrap_is_bad(flash, blk, &is_bad);\n        if (ret == ESP_OK && is_bad) {\n            bad_blocks++;\n            ESP_LOGD(TAG, \"bad block num=%\"PRIu32\"\", blk);\n        } else if (ret) {\n            ESP_LOGE(TAG, \"Failed to get bad block status for blk=%\"PRIu32\"\", blk);\n            return ret;\n        }\n    }\n    *bad_block_count = bad_blocks;\n    return ret;\n}\n\nesp_err_t nand_get_ecc_stats(spi_nand_flash_device_t *flash)\n{\n    esp_err_t ret = ESP_OK;\n    uint32_t page_size, block_size, num_blocks;\n    uint32_t ecc_err_total_count = 0;\n    uint32_t ecc_err_exceeding_threshold_count = 0;\n    uint32_t ecc_err_not_corrected_count = 0;\n\n    spi_nand_flash_get_page_size(flash, &page_size);\n    spi_nand_flash_get_block_size(flash, &block_size);\n    spi_nand_flash_get_block_num(flash, &num_blocks);\n\n    if (page_size == 0) {\n        ESP_LOGE(TAG, \"Invalid page size (0)\");\n        return ESP_ERR_INVALID_SIZE;\n    }\n\n    uint32_t pages_per_block = block_size / page_size;\n    uint32_t num_pages = num_blocks * pages_per_block;\n\n    bool is_free = true;\n    for (uint32_t page = 0; page < num_pages; page++) {\n        ret = nand_wrap_is_free(flash, page, &is_free);\n        if (!is_free) {\n            ret = nand_wrap_get_ecc_status(flash, page);\n            if (ret != ESP_OK) {\n                ESP_LOGE(TAG, \"Failed to read ecc error for page=%\" PRIu32 \"\", page);\n                return ret;\n            }\n            if (flash->chip.ecc_data.ecc_corrected_bits_status) {\n                ecc_err_total_count++;\n                if (flash->chip.ecc_data.ecc_corrected_bits_status == NAND_ECC_NOT_CORRECTED) {\n                    ecc_err_not_corrected_count++;\n                    ESP_LOGD(TAG, \"ecc error not corrected for page=%\" PRIu32 \"\", page);\n                } else if (nand_ecc_exceeds_data_refresh_threshold(flash)) {\n                    ecc_err_exceeding_threshold_count++;\n                }\n            }\n        }\n    }\n\n    ESP_LOGI(TAG, \"\\nTotal number of ECC errors: %\"PRIu32\"\\nECC not corrected count: %\"PRIu32\"\\nECC errors exceeding threshold (%d): %\"PRIu32\"\\n\",\n             ecc_err_total_count, ecc_err_not_corrected_count, flash->chip.ecc_data.ecc_data_refresh_threshold, ecc_err_exceeding_threshold_count);\n    return ret;\n}\n"
  },
  {
    "path": "spi_nand_flash/src/nand_flash_blockdev.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <inttypes.h>\n#include <string.h>\n#include \"esp_check.h\"\n#include \"esp_err.h\"\n#include \"esp_log.h\"\n#include \"esp_heap_caps.h\"\n#include \"nand.h\"\n#include \"nand_impl.h\"\n#include \"nand_flash_devices.h\"\n#include \"esp_nand_blockdev.h\"\n#include \"nand_device_types.h\"\n\n#ifndef CONFIG_IDF_TARGET_LINUX\n#include \"spi_nand_oper.h\"\n#endif\n\nstatic const char *TAG = \"nand_flash_blockdev\";\n\n/**************************************************************************************\n **************************************************************************************\n * Block Device Layer interface implementation\n **************************************************************************************\n */\n\nstatic esp_err_t nand_flash_blockdev_read(esp_blockdev_handle_t handle, uint8_t *dst_buf, size_t dst_buf_size, uint64_t src_addr, size_t data_read_len)\n{\n    uint32_t page_size = (uint32_t)handle->geometry.read_size;\n\n    if (page_size == 0) {\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n\n    if (dst_buf == NULL || dst_buf_size < data_read_len) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    spi_nand_flash_device_t *dev_handle = (spi_nand_flash_device_t *)handle->ctx;\n    uint32_t start_page = (uint32_t)(src_addr >> dev_handle->chip.log2_page_size);\n    uint32_t page_count = (uint32_t)(data_read_len >> dev_handle->chip.log2_page_size);\n    size_t offset = src_addr % page_size;\n\n    /* Single read: unaligned start or length not a multiple of page size */\n    if (offset != 0 || (data_read_len % page_size) != 0) {\n        if (offset + data_read_len > page_size) {\n            ESP_LOGE(TAG, \"Read crosses page boundary: offset=%zu + len=%zu > page_size=%\" PRIu32,\n                     offset, data_read_len, page_size);\n            return ESP_ERR_INVALID_ARG;\n        }\n        if (src_addr + data_read_len > handle->geometry.disk_size) {\n            ESP_LOGE(TAG, \"Read range exceeds device bounds\");\n            return ESP_ERR_INVALID_SIZE;\n        }\n        return nand_read(dev_handle, start_page, offset, data_read_len, dst_buf);\n    }\n\n    /* Multi-page read: page-aligned address and length */\n    if (src_addr + data_read_len > handle->geometry.disk_size) {\n        ESP_LOGE(TAG, \"Read range exceeds device bounds\");\n        return ESP_ERR_INVALID_SIZE;\n    }\n\n    esp_err_t res = ESP_OK;\n    for (uint32_t page_id = start_page; page_id < start_page + page_count; page_id++) {\n        res = nand_read(dev_handle, page_id, 0, page_size, dst_buf);\n        if (res != ESP_OK) {\n            ESP_LOGE(TAG, \"Failed to read page %\" PRIu32, page_id);\n            return res;\n        }\n        dst_buf += page_size;\n    }\n    ESP_LOGV(TAG, \"read - src_addr=0x%.16\" PRIx64 \", size=0x%08zx, result=0x%08x\", src_addr, data_read_len, res);\n    return res;\n}\n\nstatic esp_err_t nand_flash_blockdev_write(esp_blockdev_handle_t handle, const uint8_t *src_buf, uint64_t dst_addr, size_t data_write_len)\n{\n    uint32_t page_size = (uint32_t)handle->geometry.write_size;\n\n    if (handle->device_flags.read_only || page_size == 0) {\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n\n    if (src_buf == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    if ((dst_addr % handle->geometry.write_size) != 0) {\n        ESP_LOGE(TAG, \"Write address 0x%\" PRIx64 \" not aligned to page size %\" PRIu32, dst_addr,\n                 (uint32_t)handle->geometry.write_size);\n        return ESP_ERR_INVALID_SIZE;\n    }\n\n    if ((data_write_len % page_size) != 0) {\n        ESP_LOGE(TAG, \"Write length %zu not aligned to page size %\" PRIu32, data_write_len, page_size);\n        return ESP_ERR_INVALID_SIZE;\n    }\n\n    if (dst_addr + data_write_len > handle->geometry.disk_size) {\n        ESP_LOGE(TAG, \"Write range exceeds device bounds\");\n        return ESP_ERR_INVALID_SIZE;\n    }\n\n    spi_nand_flash_device_t *dev_handle = (spi_nand_flash_device_t *)handle->ctx;\n    uint32_t start_page = (uint32_t)(dst_addr >> dev_handle->chip.log2_page_size);\n    uint32_t page_count = (uint32_t)(data_write_len >> dev_handle->chip.log2_page_size);\n\n    esp_err_t res = ESP_OK;\n    for (uint32_t page_id = start_page; page_id < start_page + page_count; page_id++) {\n        res = nand_prog(dev_handle, page_id, src_buf);\n        if (res != ESP_OK) {\n            ESP_LOGE(TAG, \"Failed to write page %\" PRIu32, page_id);\n            return res;\n        }\n        src_buf += page_size;\n    }\n    ESP_LOGV(TAG, \"write - dst_addr=0x%.16\" PRIx64 \", size=0x%08zx, result=0x%08x\", dst_addr, data_write_len, res);\n    return res;\n}\n\nstatic esp_err_t nand_flash_blockdev_erase(esp_blockdev_handle_t handle, uint64_t start_addr, size_t erase_len)\n{\n    uint32_t erase_size = (uint32_t)handle->geometry.erase_size;\n    if (handle->device_flags.read_only || erase_size == 0) {\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n\n    if ((start_addr % erase_size) != 0) {\n        ESP_LOGE(TAG, \"Erase address 0x%\" PRIx64 \" not aligned to block size %\" PRIu32, start_addr, erase_size);\n        return ESP_ERR_INVALID_SIZE;\n    }\n\n    if (erase_len == 0 || (erase_len % erase_size) != 0) {\n        ESP_LOGE(TAG, \"Erase length %zu must be non-zero and a multiple of block size %\" PRIu32, erase_len, erase_size);\n        return ESP_ERR_INVALID_SIZE;\n    }\n\n    if (start_addr + erase_len > handle->geometry.disk_size) {\n        ESP_LOGE(TAG, \"Erase range exceeds device bounds\");\n        return ESP_ERR_INVALID_SIZE;\n    }\n\n    spi_nand_flash_device_t *dev_handle = (spi_nand_flash_device_t *)handle->ctx;\n    uint8_t log2_block_size = dev_handle->chip.log2_page_size + dev_handle->chip.log2_ppb;\n    uint32_t start_block = (uint32_t)(start_addr >> log2_block_size);\n    uint32_t num_blocks = (uint32_t)(erase_len >> log2_block_size);\n    esp_err_t ret = ESP_OK;\n    for (uint32_t block = start_block; block < (start_block + num_blocks); block++) {\n        ret = nand_erase_block(dev_handle, block);\n        if (ret) {\n            ESP_LOGE(TAG, \"failed to erase block = %\" PRIu32, block);\n            break;\n        }\n    }\n    ESP_LOGV(TAG, \"erase - start_addr=0x%.16\" PRIx64 \", size=0x%zx, result=0x%08x\", start_addr, erase_len, ret);\n    return ret;\n}\n\nstatic esp_err_t nand_flash_blockdev_sync_no_op(esp_blockdev_handle_t handle)\n{\n    return ESP_OK;\n}\n\nstatic esp_err_t nand_flash_blockdev_ioctl(esp_blockdev_handle_t handle, const uint8_t cmd, void *args)\n{\n    if (args == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    spi_nand_flash_device_t *dev = (spi_nand_flash_device_t *)handle->ctx;\n\n    switch (cmd) {\n    case ESP_BLOCKDEV_CMD_IS_BAD_BLOCK: {\n        esp_blockdev_cmd_arg_is_bad_block_t *bad_block_status = (esp_blockdev_cmd_arg_is_bad_block_t *) args;\n        esp_err_t ret = nand_is_bad(dev, bad_block_status->num, &bad_block_status->status);\n        return ret;\n    }\n\n    case ESP_BLOCKDEV_CMD_MARK_BAD_BLOCK: {\n        uint32_t *block = (uint32_t *) args;\n        esp_err_t ret = nand_mark_bad(dev, *block);\n        return ret;\n    }\n\n    case ESP_BLOCKDEV_CMD_IS_FREE_PAGE: {\n        esp_blockdev_cmd_arg_is_free_page_t *page_free_status = (esp_blockdev_cmd_arg_is_free_page_t *) args;\n        esp_err_t ret = nand_is_free(dev, page_free_status->num, &page_free_status->status);\n        return ret;\n    }\n\n    case ESP_BLOCKDEV_CMD_GET_PAGE_ECC_STATUS: {\n        esp_blockdev_cmd_arg_ecc_status_t *page_ecc_status = (esp_blockdev_cmd_arg_ecc_status_t *) args;\n        esp_err_t ret = nand_get_ecc_status(dev, page_ecc_status->page_num);\n        if (ret != ESP_OK) {\n            ESP_LOGE(TAG, \"Failed to get ECC status for page=%\"PRIu32\"\", page_ecc_status->page_num);\n            return ret;\n        }\n        page_ecc_status->ecc_status = dev->chip.ecc_data.ecc_corrected_bits_status;\n        return ret;\n    }\n\n    case ESP_BLOCKDEV_CMD_GET_NAND_FLASH_INFO: {\n        esp_blockdev_cmd_arg_nand_flash_info_t *flash_info = (esp_blockdev_cmd_arg_nand_flash_info_t *)args;\n        flash_info->device_info.manufacturer_id = dev->device_info.manufacturer_id;\n        flash_info->device_info.device_id = dev->device_info.device_id;\n        memcpy(flash_info->device_info.chip_name, dev->device_info.chip_name, sizeof(dev->device_info.chip_name));\n        memcpy(&flash_info->geometry, &dev->chip, sizeof(nand_flash_geometry_t));\n        return ESP_OK;\n    }\n\n    case ESP_BLOCKDEV_CMD_GET_BAD_BLOCKS_COUNT: {\n        uint32_t *bad_block_count = (uint32_t *)args;\n        uint32_t num_blocks = dev->chip.num_blocks;\n        uint32_t bad_blocks = 0;\n        esp_err_t ret = ESP_OK;\n        for (uint32_t blk = 0; blk < num_blocks; blk++) {\n            bool is_bad = false;\n            ret = nand_is_bad(dev, blk, &is_bad);\n            if (ret == ESP_OK && is_bad) {\n                bad_blocks++;\n                ESP_LOGD(TAG, \"bad block num=%\"PRIu32\"\", blk);\n            } else if (ret) {\n                ESP_LOGE(TAG, \"Failed to get bad block status for blk=%\"PRIu32\"\", blk);\n                return ret;\n            }\n        }\n        *bad_block_count = bad_blocks;\n        return ret;\n    }\n\n    case ESP_BLOCKDEV_CMD_COPY_PAGE: {\n        esp_blockdev_cmd_arg_copy_page_t *copy_cmd = (esp_blockdev_cmd_arg_copy_page_t *)args;\n        esp_err_t ret = nand_copy(dev, copy_cmd->src_page, copy_cmd->dst_page);\n        return ret;\n    }\n\n    /* Full device scan for diagnostics; can be slow on large devices. Intended for debug/health checks only. */\n    case ESP_BLOCKDEV_CMD_GET_ECC_STATS: {\n        esp_blockdev_cmd_arg_ecc_stats_t *ecc_stats = (esp_blockdev_cmd_arg_ecc_stats_t *)args;\n\n        if (handle->geometry.write_size == 0) {\n            return ESP_ERR_NOT_SUPPORTED;\n        }\n\n        uint32_t num_pages = (uint32_t)(handle->geometry.disk_size / handle->geometry.write_size);\n        bool is_free = true;\n        uint32_t ecc_err_total_count = 0;\n        uint32_t ecc_err_exceeding_threshold_count = 0;\n        uint32_t ecc_err_not_corrected_count = 0;\n        esp_err_t ret = ESP_OK;\n        for (uint32_t page = 0; page < num_pages; page++) {\n            ret = nand_is_free(dev, page, &is_free);\n            if (ret == ESP_OK && !is_free) {\n                ret = nand_get_ecc_status(dev, page);\n                if (ret != ESP_OK) {\n                    ESP_LOGE(TAG, \"Failed to read ecc error for page=%\" PRIu32, page);\n                    return ret;\n                }\n                if (dev->chip.ecc_data.ecc_corrected_bits_status) {\n                    ecc_err_total_count++;\n                    if (dev->chip.ecc_data.ecc_corrected_bits_status == NAND_ECC_NOT_CORRECTED) {\n                        ecc_err_not_corrected_count++;\n                        ESP_LOGD(TAG, \"ecc error not corrected for page=%\" PRIu32, page);\n                    } else if (nand_ecc_exceeds_data_refresh_threshold(dev)) {\n                        ecc_err_exceeding_threshold_count++;\n                    }\n                }\n            }\n        }\n        ecc_stats->ecc_threshold = dev->chip.ecc_data.ecc_data_refresh_threshold;\n        ecc_stats->ecc_total_err_count = ecc_err_total_count;\n        ecc_stats->ecc_uncorrected_err_count = ecc_err_not_corrected_count;\n        ecc_stats->ecc_exceeding_threshold_err_count = ecc_err_exceeding_threshold_count;\n        return ret;\n    }\n\n    default:\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n}\n\nstatic esp_err_t nand_flash_blockdev_release(esp_blockdev_handle_t handle)\n{\n    esp_err_t res = ESP_OK;\n    spi_nand_flash_device_t *dev_handle = (spi_nand_flash_device_t *)handle->ctx;\n#ifdef CONFIG_IDF_TARGET_LINUX\n    res = nand_emul_deinit(dev_handle);\n#endif\n    free(dev_handle->work_buffer);\n    free(dev_handle->read_buffer);\n    free(dev_handle->temp_buffer);\n    if (dev_handle->mutex) {\n        vSemaphoreDelete(dev_handle->mutex);\n    }\n    free(dev_handle);\n    free(handle);\n    return res;\n}\n\nstatic const esp_blockdev_ops_t nand_flash_blockdev_ops = {\n    .read = nand_flash_blockdev_read,\n    .write = nand_flash_blockdev_write,\n    .erase = nand_flash_blockdev_erase,\n    .ioctl = nand_flash_blockdev_ioctl,\n    .sync = nand_flash_blockdev_sync_no_op,\n    .release = nand_flash_blockdev_release,\n};\n\nesp_err_t nand_flash_get_blockdev(spi_nand_flash_config_t *config, esp_blockdev_handle_t *out_bdl_handle_ptr)\n{\n    if (config == NULL || out_bdl_handle_ptr == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    spi_nand_flash_device_t *handle = NULL;\n    esp_err_t ret = nand_init_device(config, &handle);\n    if (ret != ESP_OK) {\n        return ret;\n    }\n\n    esp_blockdev_t *blockdev = (esp_blockdev_t *) heap_caps_calloc(1, sizeof(esp_blockdev_t), MALLOC_CAP_DEFAULT);\n    if (blockdev == NULL) {\n        free(handle->work_buffer);\n        free(handle->read_buffer);\n        free(handle->temp_buffer);\n        if (handle->mutex) {\n            vSemaphoreDelete(handle->mutex);\n        }\n        free(handle);\n        return ESP_ERR_NO_MEM;\n    }\n    blockdev->ctx = (void *)handle;\n    *out_bdl_handle_ptr = blockdev;\n\n    blockdev->ops = &nand_flash_blockdev_ops;\n\n    blockdev->device_flags.read_only = 0;\n    blockdev->device_flags.encrypted = 0;\n    blockdev->device_flags.erase_before_write = 1;\n    blockdev->device_flags.and_type_write = 1;\n    blockdev->device_flags.default_val_after_erase = 1;\n    blockdev->device_flags.reserved = 0;\n\n    // Set up geometry information\n    uint32_t page_size = handle->chip.page_size;\n    uint32_t block_size = handle->chip.block_size;\n    uint32_t num_blocks = handle->chip.num_blocks;\n\n    blockdev->geometry.disk_size = num_blocks * block_size;\n    blockdev->geometry.write_size = page_size;\n    blockdev->geometry.read_size = page_size;\n    blockdev->geometry.erase_size = block_size;\n    blockdev->geometry.recommended_write_size = page_size;\n    blockdev->geometry.recommended_read_size = page_size;\n    blockdev->geometry.recommended_erase_size = block_size;\n\n    return ESP_OK;\n}\n"
  },
  {
    "path": "spi_nand_flash/src/nand_impl.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 mikkeldamsgaard project\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * SPDX-FileContributor: 2015-2024 Espressif Systems (Shanghai) CO LTD\n */\n\n#include <string.h>\n#include \"esp_check.h\"\n#include \"esp_err.h\"\n#include \"spi_nand_oper.h\"\n#include \"nand.h\"\n#include \"nand_flash_devices.h\"\n#include \"nand_device_types.h\"\n\n#define ROM_WAIT_THRESHOLD_US 1000\n\nstatic const char *TAG = \"nand_hal\";\n\nstatic esp_err_t detect_chip(spi_nand_flash_device_t *dev)\n{\n    uint8_t manufacturer_id = 0;\n    esp_err_t ret = ESP_OK;\n    ESP_RETURN_ON_ERROR(spi_nand_read_manufacturer_id(dev, &manufacturer_id), TAG, \"%s, Failed to get the manufacturer ID %d\", __func__, ret);\n    ESP_LOGD(TAG, \"%s: manufacturer_id: %x\\n\", __func__, manufacturer_id);\n    dev->device_info.manufacturer_id = manufacturer_id;\n\n    switch (manufacturer_id) {\n    case SPI_NAND_FLASH_ALLIANCE_MI: // Alliance\n        return spi_nand_alliance_init(dev);\n    case SPI_NAND_FLASH_WINBOND_MI: // Winbond\n        return spi_nand_winbond_init(dev);\n    case SPI_NAND_FLASH_GIGADEVICE_MI: // GigaDevice\n        return spi_nand_gigadevice_init(dev);\n    case SPI_NAND_FLASH_MICRON_MI: // Micron\n        return spi_nand_micron_init(dev);\n    case SPI_NAND_FLASH_ZETTA_MI: // Zetta\n        return spi_nand_zetta_init(dev);\n    case SPI_NAND_FLASH_XTX_MI: // XTX\n        return spi_nand_xtx_init(dev);\n    default:\n        return ESP_ERR_INVALID_RESPONSE;\n    }\n}\n\nstatic esp_err_t enable_quad_io_mode(spi_nand_flash_device_t *dev)\n{\n    uint8_t io_config;\n    esp_err_t ret = spi_nand_read_register(dev, REG_CONFIG, &io_config);\n    if (ret != ESP_OK) {\n        return ret;\n    }\n\n    io_config |= (1 << dev->chip.quad_enable_bit_pos);\n    ESP_LOGD(TAG, \"%s: quad config register value: 0x%x\", __func__, io_config);\n\n    if (io_config != 0x00) {\n        ret = spi_nand_write_register(dev, REG_CONFIG, io_config);\n    }\n\n    return ret;\n}\n\nstatic esp_err_t unprotect_chip(spi_nand_flash_device_t *dev)\n{\n    uint8_t status;\n    esp_err_t ret = spi_nand_read_register(dev, REG_PROTECT, &status);\n    if (ret != ESP_OK) {\n        return ret;\n    }\n\n    if (status != 0x00) {\n        ret = spi_nand_write_register(dev, REG_PROTECT, 0);\n    }\n\n    return ret;\n}\n\nesp_err_t nand_init_device(spi_nand_flash_config_t *config, spi_nand_flash_device_t **handle)\n{\n    esp_err_t ret = ESP_OK;\n    ESP_RETURN_ON_FALSE(config->device_handle != NULL, ESP_ERR_INVALID_ARG, TAG, \"Spi device pointer can not be NULL\");\n\n    *handle = heap_caps_calloc(1, sizeof(spi_nand_flash_device_t), MALLOC_CAP_DEFAULT);\n    if (*handle == NULL) {\n        return ESP_ERR_NO_MEM;\n    }\n\n    memcpy(&(*handle)->config, config, sizeof(spi_nand_flash_config_t));\n\n    (*handle)->chip.ecc_data.ecc_status_reg_len_in_bits = 2;\n    (*handle)->chip.ecc_data.ecc_data_refresh_threshold = 4;\n    (*handle)->chip.log2_ppb = 6;         // 64 pages per block is standard\n    (*handle)->chip.log2_page_size = 11;  // 2048 bytes per page is fairly standard\n    (*handle)->chip.num_planes = 1;\n    (*handle)->chip.flags = 0;\n\n    ESP_GOTO_ON_ERROR(detect_chip(*handle), fail, TAG, \"Failed to detect nand chip\");\n    ESP_GOTO_ON_ERROR(unprotect_chip(*handle), fail, TAG, \"Failed to clear protection register\");\n\n    if (((*handle)->config.io_mode ==  SPI_NAND_IO_MODE_QOUT || (*handle)->config.io_mode ==  SPI_NAND_IO_MODE_QIO)\n            && (*handle)->chip.has_quad_enable_bit) {\n        ESP_GOTO_ON_ERROR(enable_quad_io_mode(*handle), fail, TAG, \"Failed to enable quad mode\");\n    }\n\n    (*handle)->chip.page_size = 1 << (*handle)->chip.log2_page_size;\n    (*handle)->chip.block_size = (1 << (*handle)->chip.log2_ppb) * (*handle)->chip.page_size;\n\n    size_t dma_alignment = spi_nand_get_dma_alignment();\n    (*handle)->work_buffer = heap_caps_aligned_alloc(dma_alignment, (*handle)->chip.page_size, MALLOC_CAP_DMA | MALLOC_CAP_8BIT);\n    ESP_GOTO_ON_FALSE((*handle)->work_buffer != NULL, ESP_ERR_NO_MEM, fail, TAG, \"nomem\");\n\n    (*handle)->read_buffer = heap_caps_aligned_alloc(dma_alignment, (*handle)->chip.page_size, MALLOC_CAP_DMA | MALLOC_CAP_8BIT);\n    ESP_GOTO_ON_FALSE((*handle)->read_buffer != NULL, ESP_ERR_NO_MEM, fail, TAG, \"nomem\");\n\n    (*handle)->temp_buffer = heap_caps_aligned_alloc(dma_alignment, (*handle)->chip.page_size + dma_alignment, MALLOC_CAP_DMA | MALLOC_CAP_8BIT);\n    ESP_GOTO_ON_FALSE((*handle)->temp_buffer != NULL, ESP_ERR_NO_MEM, fail, TAG, \"nomem\");\n\n    (*handle)->mutex = xSemaphoreCreateMutex();\n    if (!(*handle)->mutex) {\n        ret = ESP_ERR_NO_MEM;\n        goto fail;\n    }\n    return ret;\n\nfail:\n    free((*handle)->work_buffer);\n    free((*handle)->read_buffer);\n    free((*handle)->temp_buffer);\n    if ((*handle)->mutex) {\n        vSemaphoreDelete((*handle)->mutex);\n    }\n    free(*handle);\n    return ret;\n}\n\n/***************************************************************************************/\n\n#if CONFIG_NAND_FLASH_VERIFY_WRITE\nstatic esp_err_t s_verify_write(spi_nand_flash_device_t *handle, const uint8_t *expected_buffer, uint16_t offset, uint16_t length)\n{\n    uint8_t *temp_buf = NULL;\n    temp_buf = heap_caps_malloc(length, MALLOC_CAP_DMA | MALLOC_CAP_8BIT);\n    ESP_RETURN_ON_FALSE(temp_buf != NULL, ESP_ERR_NO_MEM, TAG, \"nomem\");\n    if (spi_nand_read(handle, temp_buf, offset, length)) {\n        ESP_LOGE(TAG, \"%s: Failed to read nand flash to verify previous write\", __func__);\n        free(temp_buf);\n        return ESP_FAIL;\n    }\n\n    if (memcmp(temp_buf, expected_buffer, length)) {\n        ESP_LOGE(TAG, \"%s: Data mismatch detected. The previously written buffer does not match the read buffer.\", __func__);\n        free(temp_buf);\n        return ESP_FAIL;\n    }\n    free(temp_buf);\n    return ESP_OK;\n}\n#endif //CONFIG_NAND_FLASH_VERIFY_WRITE\n\nstatic esp_err_t wait_for_ready(spi_nand_flash_device_t *dev, uint32_t expected_operation_time_us, uint8_t *status_out)\n{\n    if (expected_operation_time_us < ROM_WAIT_THRESHOLD_US) {\n        esp_rom_delay_us(expected_operation_time_us);\n    }\n\n    while (true) {\n        uint8_t status;\n        ESP_RETURN_ON_ERROR(spi_nand_read_register(dev, REG_STATUS, &status), TAG, \"\");\n\n        if ((status & STAT_BUSY) == 0) {\n            if (status_out) {\n                *status_out = status;\n            }\n            break;\n        }\n\n        if (expected_operation_time_us >= ROM_WAIT_THRESHOLD_US) {\n            vTaskDelay(1);\n        }\n    }\n\n    return ESP_OK;\n}\n\nstatic esp_err_t read_page_and_wait(spi_nand_flash_device_t *dev, uint32_t page, uint8_t *status_out)\n{\n    ESP_RETURN_ON_ERROR(spi_nand_read_page(dev, page), TAG, \"\");\n\n    return wait_for_ready(dev, dev->chip.read_page_delay_us, status_out);\n}\n\nstatic esp_err_t program_execute_and_wait(spi_nand_flash_device_t *dev, uint32_t page, uint8_t *status_out)\n{\n    ESP_RETURN_ON_ERROR(spi_nand_program_execute(dev, page), TAG, \"\");\n\n    return wait_for_ready(dev, dev->chip.program_page_delay_us, status_out);\n}\n\nstatic uint16_t get_column_address(spi_nand_flash_device_t *handle, uint32_t block, uint32_t offset)\n{\n    uint16_t column_addr = offset;\n\n    if ((handle->chip.flags & NAND_FLAG_HAS_READ_PLANE_SELECT) || (handle->chip.flags & NAND_FLAG_HAS_PROG_PLANE_SELECT)) {\n        if (handle->chip.num_planes == 0) {\n            ESP_LOGE(TAG, \"Invalid number of planes (0)\");\n            return column_addr;  // Return offset without plane selection\n        }\n        uint32_t plane = block % handle->chip.num_planes;\n        // The plane index is the bit following the most significant bit (MSB) of the address.\n        // For a 2048-byte page (2^11), the plane select bit is the 12th bit, and\n        // for a 4096-byte page (2^12), it is the 13th bit.\n        column_addr += plane << (handle->chip.log2_page_size + 1);\n    }\n    return column_addr;\n}\n\nesp_err_t nand_is_bad(spi_nand_flash_device_t *handle, uint32_t block, bool *is_bad_status)\n{\n    uint32_t first_block_page = block * (1 << handle->chip.log2_ppb);\n    // Markers layout: [bad_block_marker (bytes 0-1)][page_used_marker (bytes 2-3)]\n    uint8_t markers[4];\n    esp_err_t ret = ESP_OK;\n\n    ESP_GOTO_ON_ERROR(read_page_and_wait(handle, first_block_page, NULL), fail, TAG, \"\");\n\n    uint16_t column_addr = get_column_address(handle, block, handle->chip.page_size);\n\n    // Read 4 bytes to include both bad block marker and page status\n    ESP_GOTO_ON_ERROR(spi_nand_read(handle, (uint8_t *) handle->read_buffer, column_addr, 4),\n                      fail, TAG, \"\");\n\n    memcpy(&markers, handle->read_buffer, sizeof(markers));\n    ESP_LOGD(TAG, \"is_bad, block=%\"PRIu32\", page=%\"PRIu32\",indicator = %02x,%02x\", block, first_block_page, markers[0], markers[1]);\n    *is_bad_status = (markers[0] != 0xFF || markers[1] != 0xFF);\n    return ret;\n\nfail:\n    ESP_LOGE(TAG, \"Error in nand_is_bad %d\", ret);\n    return ret;\n}\n\nesp_err_t nand_mark_bad(spi_nand_flash_device_t *handle, uint32_t block)\n{\n    esp_err_t ret = ESP_OK;\n\n    uint32_t first_block_page = block * (1 << handle->chip.log2_ppb);\n    // Markers layout: [bad_block_marker (bytes 0-1)][page_used_marker (bytes 2-3)]\n    const uint8_t markers[4] = { 0x00, 0x00, 0xFF, 0xFF }; //// 0x0000 (bad block), 0xFFFF (free)\n    uint8_t status;\n    ESP_LOGD(TAG, \"mark_bad, block=%\"PRIu32\", page=%\"PRIu32\"\", block, first_block_page);\n\n    ESP_GOTO_ON_ERROR(read_page_and_wait(handle, first_block_page, NULL), fail, TAG, \"\");\n    ESP_GOTO_ON_ERROR(spi_nand_write_enable(handle), fail, TAG, \"\");\n    ESP_GOTO_ON_ERROR(spi_nand_erase_block(handle, first_block_page),\n                      fail, TAG, \"\");\n    ESP_GOTO_ON_ERROR(wait_for_ready(handle, handle->chip.erase_block_delay_us, &status),\n                      fail, TAG, \"\");\n    if ((status & STAT_ERASE_FAILED) != 0) {\n        ret = ESP_ERR_NOT_FINISHED;\n        goto fail;\n    }\n\n    ESP_GOTO_ON_ERROR(spi_nand_write_enable(handle), fail, TAG, \"\");\n\n    uint16_t column_addr = get_column_address(handle, block, handle->chip.page_size);\n\n    // Write 4 bytes: bad block marker (0x0000) + page used marker (0xFFFF)\n    ESP_GOTO_ON_ERROR(spi_nand_program_load(handle, (const uint8_t *) &markers,\n                                            column_addr, 4), fail, TAG, \"\");\n    ESP_GOTO_ON_ERROR(program_execute_and_wait(handle, first_block_page, NULL), fail, TAG, \"\");\n\n#if CONFIG_NAND_FLASH_VERIFY_WRITE\n    ret = s_verify_write(handle, (uint8_t *)&markers, column_addr, 4);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"%s: mark_bad write verification failed for block=%\"PRIu32\" and page=%\"PRIu32\"\", __func__, block, first_block_page);\n    }\n#endif //CONFIG_NAND_FLASH_VERIFY_WRITE\n    return ret;\nfail:\n    ESP_LOGE(TAG, \"Error in nand_mark_bad %d\", ret);\n    return ret;\n}\n\nesp_err_t nand_erase_block(spi_nand_flash_device_t *handle, uint32_t block)\n{\n    ESP_LOGD(TAG, \"erase_block, block=%\"PRIu32\",\", block);\n    esp_err_t ret = ESP_OK;\n    uint8_t status;\n\n    uint32_t first_block_page = block * (1 << handle->chip.log2_ppb);\n\n    ESP_GOTO_ON_ERROR(spi_nand_write_enable(handle), fail, TAG, \"\");\n    ESP_GOTO_ON_ERROR(spi_nand_erase_block(handle, first_block_page),\n                      fail, TAG, \"\");\n    ESP_GOTO_ON_ERROR(wait_for_ready(handle,\n                                     handle->chip.erase_block_delay_us, &status),\n                      fail, TAG, \"\");\n\n    if ((status & STAT_ERASE_FAILED) != 0) {\n        ret = ESP_ERR_NOT_FINISHED;\n    }\n    return ret;\n\nfail:\n    ESP_LOGE(TAG, \"Error in nand_erase %d\", ret);\n    return ret;\n}\n\nstatic esp_err_t nand_erase_good_block(spi_nand_flash_device_t *handle, uint32_t block)\n{\n    ESP_LOGD(TAG, \"erase_block, block=%\"PRIu32\",\", block);\n    esp_err_t ret = ESP_OK;\n    bool is_bad = false;\n    ret = nand_is_bad(handle, block, &is_bad);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Error querying bad block status for block=%\"PRIu32\"\", block);\n        return ret;\n    }\n    if (is_bad) {\n        ESP_LOGD(TAG, \"skip erase of bad block=%\"PRIu32\"\", block);\n        return ESP_OK;\n    }\n    ret = nand_erase_block(handle, block);\n    return ret;\n}\n\nesp_err_t nand_erase_chip(spi_nand_flash_device_t *handle)\n{\n    esp_err_t ret = ESP_OK;\n    for (int i = 0; i < handle->chip.num_blocks; i++) {\n        esp_err_t err = nand_erase_good_block(handle, (uint32_t)i);\n        if (err == ESP_ERR_NOT_FINISHED) {\n            ret = ESP_ERR_NOT_FINISHED;\n        } else if (err != ESP_OK) {\n            ESP_LOGE(TAG, \"Error in nand_erase_chip %d\", err);\n            return err;\n        }\n    }\n    return ret;\n}\n\nesp_err_t nand_prog(spi_nand_flash_device_t *handle, uint32_t page, const uint8_t *data)\n{\n    ESP_LOGV(TAG, \"prog, page=%\"PRIu32\",\", page);\n    esp_err_t ret = ESP_OK;\n    // Markers layout: [bad_block_marker (bytes 0-1)][page_used_marker (bytes 2-3)]\n    // For good block with used page: bad=0xFFFF, used=0x0000\n    uint8_t markers[4] = { 0xFF, 0xFF, 0x00, 0x00 };\n    uint8_t status;\n\n    uint32_t block = page >> handle->chip.log2_ppb;\n    uint16_t column_addr = get_column_address(handle, block, 0);\n\n    ESP_GOTO_ON_ERROR(read_page_and_wait(handle, page, NULL), fail, TAG, \"\");\n    ESP_GOTO_ON_ERROR(spi_nand_write_enable(handle), fail, TAG, \"\");\n    ESP_GOTO_ON_ERROR(spi_nand_program_load(handle, data, column_addr, handle->chip.page_size),\n                      fail, TAG, \"\");\n    // Write 4 bytes: bad block marker (0xFFFF - good block) + page used marker (0x0000 - used)\n    ESP_GOTO_ON_ERROR(spi_nand_program_load(handle, (uint8_t *)&markers,\n                                            column_addr + handle->chip.page_size, 4), fail, TAG, \"\");\n\n    ESP_GOTO_ON_ERROR(program_execute_and_wait(handle, page, &status), fail, TAG, \"\");\n\n    if ((status & STAT_PROGRAM_FAILED) != 0) {\n        ESP_LOGE(TAG, \"prog failed, page=%\"PRIu32\", status=0x%02x\", page, status);\n        return ESP_ERR_NOT_FINISHED;\n    }\n\n#if CONFIG_NAND_FLASH_VERIFY_WRITE\n    ret = s_verify_write(handle, data, column_addr, handle->chip.page_size);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"%s: prog page=%\"PRIu32\" write verification failed\", __func__, page);\n    }\n    ret = s_verify_write(handle, (uint8_t *)&markers, column_addr + handle->chip.page_size, 4);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"%s: prog page=%\"PRIu32\" markers write verification failed\", __func__, page);\n    }\n#endif //CONFIG_NAND_FLASH_VERIFY_WRITE\n\n    return ret;\nfail:\n    ESP_LOGE(TAG, \"Error in nand_prog %d\", ret);\n    return ret;\n}\n\nesp_err_t nand_is_free(spi_nand_flash_device_t *handle, uint32_t page, bool *is_free_status)\n{\n    esp_err_t ret = ESP_OK;\n    // Markers layout: [bad_block_marker (bytes 0-1)][page_used_marker (bytes 2-3)]\n    uint8_t markers[4];\n\n    ESP_GOTO_ON_ERROR(read_page_and_wait(handle, page, NULL), fail, TAG, \"\");\n\n    uint32_t block = page >> handle->chip.log2_ppb;\n    uint16_t column_addr = get_column_address(handle, block, handle->chip.page_size);\n\n    // Read 4 bytes to get both bad block marker and page used marker\n    ESP_GOTO_ON_ERROR(spi_nand_read(handle, (uint8_t *)handle->read_buffer,\n                                    column_addr, 4), fail, TAG, \"\");\n\n    memcpy(&markers, handle->read_buffer, sizeof(markers));\n    ESP_LOGD(TAG, \"is free, page=%\"PRIu32\", used_marker=%02x,%02x,\", page, markers[2], markers[3]);\n    *is_free_status = (markers[2] == 0xFF && markers[3] == 0xFF);\n    return ret;\nfail:\n    ESP_LOGE(TAG, \"Error in nand_is_free %d\", ret);\n    return ret;\n}\n\n#define PACK_2BITS_STATUS(status, bit1, bit0)         ((((status) & (bit1)) << 1) | ((status) & (bit0)))\n#define PACK_3BITS_STATUS(status, bit2, bit1, bit0)   ((((status) & (bit2)) << 2) | (((status) & (bit1)) << 1) | ((status) & (bit0)))\n\nstatic bool is_ecc_error(spi_nand_flash_device_t *dev, uint8_t status)\n{\n    bool is_ecc_err = false;\n    nand_ecc_status_t bits_corrected_status = NAND_ECC_OK;\n    if (dev->chip.ecc_data.ecc_status_reg_len_in_bits == 2) {\n        bits_corrected_status = PACK_2BITS_STATUS(status, STAT_ECC1, STAT_ECC0);\n    } else if (dev->chip.ecc_data.ecc_status_reg_len_in_bits == 3) {\n        bits_corrected_status = PACK_3BITS_STATUS(status, STAT_ECC2, STAT_ECC1, STAT_ECC0);\n    } else {\n        bits_corrected_status = NAND_ECC_MAX;\n    }\n    dev->chip.ecc_data.ecc_corrected_bits_status = bits_corrected_status;\n    if (bits_corrected_status) {\n        if (bits_corrected_status == NAND_ECC_MAX) {\n            ESP_LOGE(TAG, \"%s: Error while initializing value of ecc_status_reg_len_in_bits\", __func__);\n            is_ecc_err = true;\n        } else if (bits_corrected_status == NAND_ECC_NOT_CORRECTED) {\n            is_ecc_err = true;\n        }\n    }\n    return is_ecc_err;\n}\n\nesp_err_t nand_read(spi_nand_flash_device_t *handle, uint32_t page, size_t offset, size_t length, uint8_t *data)\n{\n    ESP_LOGV(TAG, \"read, page=%\"PRIu32\", offset=%d, length=%d\", page, offset, length);\n    assert(page < handle->chip.num_blocks * (1 << handle->chip.log2_ppb));\n    esp_err_t ret = ESP_OK;\n    uint8_t status;\n\n    ESP_GOTO_ON_ERROR(read_page_and_wait(handle, page, &status), fail, TAG, \"\");\n\n    if (is_ecc_error(handle, status)) {\n        ESP_LOGD(TAG, \"read ecc error, page=%\"PRIu32\"\", page);\n        return ESP_FAIL;\n    }\n\n    uint32_t block = page >> handle->chip.log2_ppb;\n    uint16_t column_addr = get_column_address(handle, block, offset);\n\n    ESP_GOTO_ON_ERROR(spi_nand_read(handle, data, column_addr, length), fail, TAG, \"\");\n\n    return ret;\nfail:\n    ESP_LOGE(TAG, \"Error in nand_read %d\", ret);\n    return ret;\n}\n\nesp_err_t nand_copy(spi_nand_flash_device_t *handle, uint32_t src, uint32_t dst)\n{\n    ESP_LOGD(TAG, \"copy, src=%\"PRIu32\", dst=%\"PRIu32\"\", src, dst);\n    esp_err_t ret = ESP_OK;\n#if CONFIG_NAND_FLASH_VERIFY_WRITE\n    uint8_t *temp_buf = NULL;\n#endif //CONFIG_NAND_FLASH_VERIFY_WRITE\n\n    uint8_t status;\n    ESP_GOTO_ON_ERROR(read_page_and_wait(handle, src, &status), fail, TAG, \"\");\n\n    if (is_ecc_error(handle, status)) {\n        ESP_LOGD(TAG, \"copy, ecc error\");\n        return ESP_FAIL;\n    }\n\n    ESP_GOTO_ON_ERROR(spi_nand_write_enable(handle), fail, TAG, \"\");\n    uint32_t src_block = src >> handle->chip.log2_ppb;\n    uint32_t dst_block = dst >> handle->chip.log2_ppb;\n    uint16_t src_column_addr = get_column_address(handle, src_block, 0);\n    uint16_t dst_column_addr = get_column_address(handle, dst_block, 0);\n\n    if (src_column_addr != dst_column_addr) {\n        // In a 2 plane structure of the flash, if the pages are not on the same plane, the data must be copied through RAM.\n        uint8_t *copy_buf = heap_caps_malloc(handle->chip.page_size, MALLOC_CAP_DMA | MALLOC_CAP_8BIT);\n        ESP_GOTO_ON_FALSE(copy_buf, ESP_ERR_NO_MEM, fail, TAG, \"Failed to allocate copy buffer\");\n\n        ESP_GOTO_ON_ERROR(spi_nand_read(handle, copy_buf, src_column_addr, handle->chip.page_size), fail, TAG, \"\");\n\n        ESP_GOTO_ON_ERROR(spi_nand_write_enable(handle), fail, TAG, \"\");\n\n        ESP_GOTO_ON_ERROR(spi_nand_program_load(handle, copy_buf, dst_column_addr, handle->chip.page_size),\n                          fail, TAG, \"\");\n\n        // Write 4 bytes: bad block marker (0xFFFF - good block) + page used marker (0x0000 - used)\n        uint8_t markers[4] = { 0xFF, 0xFF, 0x00, 0x00 };\n        ESP_GOTO_ON_ERROR(spi_nand_program_load(handle, (uint8_t *)&markers,\n                                                dst_column_addr + handle->chip.page_size, 4), fail, TAG, \"\");\n        ESP_GOTO_ON_ERROR(program_execute_and_wait(handle, dst, &status), fail, TAG, \"\");\n\n        if ((status & STAT_PROGRAM_FAILED) != 0) {\n            ESP_LOGD(TAG, \"copy, prog failed\");\n            return ESP_ERR_NOT_FINISHED;\n        }\n        free(copy_buf);\n    }\n\n    ESP_GOTO_ON_ERROR(program_execute_and_wait(handle, dst, &status), fail, TAG, \"\");\n    if ((status & STAT_PROGRAM_FAILED) != 0) {\n        ESP_LOGD(TAG, \"copy, prog failed\");\n        return ESP_ERR_NOT_FINISHED;\n    }\n\n#if CONFIG_NAND_FLASH_VERIFY_WRITE\n    // First read src page data from cache to temp_buf\n    if (src_column_addr != dst_column_addr) {\n        // Then read src page data from nand memory array and load it in cache\n        ESP_GOTO_ON_ERROR(read_page_and_wait(handle, src, &status), fail, TAG, \"\");\n        if (is_ecc_error(handle, status)) {\n            ESP_LOGE(TAG, \"%s: dst_page=%\"PRIu32\" read, ecc error\", __func__, dst);\n            goto fail;\n        }\n    }\n\n    temp_buf = heap_caps_malloc(handle->chip.page_size, MALLOC_CAP_DMA | MALLOC_CAP_8BIT);\n    ESP_RETURN_ON_FALSE(temp_buf != NULL, ESP_ERR_NO_MEM, TAG, \"nomem\");\n    if (spi_nand_read(handle, temp_buf, src_column_addr, handle->chip.page_size)) {\n        ESP_LOGE(TAG, \"%s: Failed to read src_page=%\"PRIu32\"\", __func__, src);\n        goto fail;\n    }\n    // Then read dst page data from nand memory array and load it in cache\n    ESP_GOTO_ON_ERROR(read_page_and_wait(handle, dst, &status), fail, TAG, \"\");\n    if (is_ecc_error(handle, status)) {\n        ESP_LOGE(TAG, \"%s: dst_page=%\"PRIu32\" read, ecc error\", __func__, dst);\n        goto fail;\n    }\n    // Check if the data in the src page matches the dst page\n    ret = s_verify_write(handle, temp_buf, dst_column_addr, handle->chip.page_size);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"%s: dst_page=%\"PRIu32\" write verification failed\", __func__, dst);\n    }\n\n    free(temp_buf);\n#endif //CONFIG_NAND_FLASH_VERIFY_WRITE\n    return ret;\n\nfail:\n#if CONFIG_NAND_FLASH_VERIFY_WRITE\n    free(temp_buf);\n#endif //CONFIG_NAND_FLASH_VERIFY_WRITE\n    ESP_LOGE(TAG, \"Error in nand_copy %d\", ret);\n    return ret;\n}\n\nesp_err_t nand_get_ecc_status(spi_nand_flash_device_t *handle, uint32_t page)\n{\n    esp_err_t ret = ESP_OK;\n    uint8_t status;\n    ESP_GOTO_ON_ERROR(read_page_and_wait(handle, page, &status), fail, TAG, \"\");\n\n    if (is_ecc_error(handle, status)) {\n        ESP_LOGD(TAG, \"read ecc error, page=%\"PRIu32\"\", page);\n    }\n    return ret;\n\nfail:\n    ESP_LOGE(TAG, \"Error in nand_is_ecc_error %d\", ret);\n    return ret;\n}\n"
  },
  {
    "path": "spi_nand_flash/src/nand_impl_linux.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <inttypes.h>\n#include <stdint.h>\n#include <string.h>\n#include \"esp_check.h\"\n#include \"esp_err.h\"\n#include \"spi_nand_flash.h\"\n#include \"nand.h\"\n#include \"nand_linux_mmap_emul.h\"\n\nstatic const char *TAG = \"nand_linux\";\n\n/* OOB marker layout at page data offset `page_size` (matches nand_impl.c HW path):\n * bytes 0-1: bad-block marker (0xFFFF = good / erased, 0x0000 = bad)\n * bytes 2-3: page-used marker (0xFFFF = free, 0x0000 = used after program) */\nstatic const uint8_t s_oob_used_page_markers[4] = { 0xFF, 0xFF, 0x00, 0x00 };\nstatic const uint8_t s_oob_mark_bad_markers[4] = { 0x00, 0x00, 0xFF, 0xFF };\n\n/* Start of erase block `block` in the mmap file: ppb slots of (data + OOB) per page. */\nstatic esp_err_t linux_mmap_block_file_offset(const spi_nand_flash_device_t *handle, uint32_t block, size_t *out_offset)\n{\n    ESP_RETURN_ON_FALSE(out_offset != NULL, ESP_ERR_INVALID_ARG, TAG, \"out_offset is NULL\");\n    ESP_RETURN_ON_FALSE(handle->chip.num_blocks > 0, ESP_ERR_INVALID_STATE, TAG, \"num_blocks is 0\");\n    ESP_RETURN_ON_FALSE(block < handle->chip.num_blocks, ESP_ERR_INVALID_ARG, TAG, \"block index out of range\");\n\n    const uint64_t ppb = 1ull << handle->chip.log2_ppb;\n    const uint64_t bytes_per_block = ppb * (uint64_t)handle->chip.emulated_page_size;\n    const uint64_t off = (uint64_t)block * bytes_per_block;\n\n    ESP_RETURN_ON_FALSE(off <= (uint64_t)SIZE_MAX, ESP_ERR_INVALID_SIZE, TAG, \"mmap block offset overflow\");\n    *out_offset = (size_t)off;\n    return ESP_OK;\n}\n\nstatic esp_err_t detect_chip(spi_nand_flash_device_t *dev)\n{\n    esp_err_t ret = ESP_OK;\n    spi_nand_flash_config_t *config = &dev->config;\n\n    ESP_GOTO_ON_ERROR(nand_emul_init(dev, config->emul_conf), fail, TAG, \"\");\n    dev->chip.page_size = (1 << dev->chip.log2_page_size);\n\n    dev->chip.emulated_page_oob = 64;  // The default page size is 2048, so the OOB size is 64.\n\n    if (dev->chip.page_size == 512) {\n        dev->chip.emulated_page_oob = 16;\n    } else if (dev->chip.page_size == 2048) {\n        dev->chip.emulated_page_oob = 64;\n    } else if (dev->chip.page_size == 4096) {\n        dev->chip.emulated_page_oob = 128;\n    }\n    dev->chip.emulated_page_size = dev->chip.page_size + dev->chip.emulated_page_oob;\n    /* chip.block_size: user-visible data per erase block (matches nand_impl.c / BDL).\n     * File layout interleaves OOB after each page; use file_bytes_per_block for num_blocks\n     * and linux_mmap_block_file_offset() for mmap byte addresses. */\n    dev->chip.block_size = (1u << dev->chip.log2_ppb) * dev->chip.page_size;\n    const uint32_t file_bytes_per_block = (1u << dev->chip.log2_ppb) * dev->chip.emulated_page_size;\n\n    if (dev->chip.block_size == 0 || file_bytes_per_block == 0) {\n        ESP_LOGE(TAG, \"Invalid block size (0)\");\n        ret = ESP_ERR_INVALID_SIZE;\n        goto fail;\n    }\n\n    if (config->emul_conf->flash_file_size % dev->chip.block_size != 0) {\n        ESP_LOGE(TAG, \"flash_file_size (0x%\" PRIx64 \") is not a multiple of chip.block_size (0x%\" PRIx32 \")\",\n                 config->emul_conf->flash_file_size, dev->chip.block_size);\n        ret = ESP_ERR_INVALID_SIZE;\n        goto fail;\n    }\n\n    dev->chip.num_blocks = config->emul_conf->flash_file_size / file_bytes_per_block;\n    dev->chip.erase_block_delay_us = 3000;\n    dev->chip.program_page_delay_us = 630;\n    dev->chip.read_page_delay_us = 60;\n\n    /* Device info for GET_NAND_FLASH_INFO ioctl (host tests expect non-zero IDs and non-empty chip name) */\n    dev->device_info.manufacturer_id = 0xEF;  /* Synthetic ID for Linux emulator */\n    dev->device_info.device_id = 0xE100;\n    strncpy(dev->device_info.chip_name, \"Linux NAND mmap emul\", sizeof(dev->device_info.chip_name) - 1);\n    dev->device_info.chip_name[sizeof(dev->device_info.chip_name) - 1] = '\\0';\n\nfail:\n    return ret;\n}\n\nesp_err_t nand_init_device(spi_nand_flash_config_t *config, spi_nand_flash_device_t **handle)\n{\n    esp_err_t ret = ESP_OK;\n    ESP_RETURN_ON_FALSE(config->emul_conf != NULL, ESP_ERR_INVALID_ARG, TAG, \"Linux mmap emulation configuration pointer can not be NULL\");\n\n    *handle = heap_caps_calloc(1, sizeof(spi_nand_flash_device_t), MALLOC_CAP_DEFAULT);\n    if (*handle == NULL) {\n        return ESP_ERR_NO_MEM;\n    }\n\n    memcpy(&(*handle)->config, config, sizeof(spi_nand_flash_config_t));\n\n    (*handle)->chip.ecc_data.ecc_status_reg_len_in_bits = 2;\n    (*handle)->chip.ecc_data.ecc_data_refresh_threshold = 4;\n    (*handle)->chip.log2_ppb = 6;         // 64 pages per block is standard\n    (*handle)->chip.log2_page_size = 11;  // 2048 bytes per page is fairly standard\n    (*handle)->chip.num_planes = 1;\n    (*handle)->chip.flags = 0;\n    (*handle)->chip.page_size = 1 << (*handle)->chip.log2_page_size;\n    (*handle)->chip.block_size = (1 << (*handle)->chip.log2_ppb) * (*handle)->chip.page_size;\n\n    ESP_GOTO_ON_ERROR(detect_chip(*handle), fail, TAG, \"Failed to detect nand chip\");\n\n    (*handle)->work_buffer = heap_caps_malloc((*handle)->chip.page_size, MALLOC_CAP_DEFAULT);\n    ESP_GOTO_ON_FALSE((*handle)->work_buffer != NULL, ESP_ERR_NO_MEM, fail, TAG, \"nomem\");\n\n    (*handle)->read_buffer = heap_caps_malloc((*handle)->chip.page_size, MALLOC_CAP_DEFAULT);\n    ESP_GOTO_ON_FALSE((*handle)->read_buffer != NULL, ESP_ERR_NO_MEM, fail, TAG, \"nomem\");\n\n    (*handle)->mutex = xSemaphoreCreateMutex();\n    if (!(*handle)->mutex) {\n        ret = ESP_ERR_NO_MEM;\n        goto fail;\n    }\n    return ret;\n\nfail:\n    free((*handle)->work_buffer);\n    free((*handle)->read_buffer);\n    if ((*handle)->mutex) {\n        vSemaphoreDelete((*handle)->mutex);\n    }\n    free(*handle);\n    *handle = NULL;\n    return ret;\n}\n\nesp_err_t nand_is_bad(spi_nand_flash_device_t *handle, uint32_t block, bool *is_bad_status)\n{\n    uint8_t markers[4];\n    size_t block_offset = 0;\n\n    ESP_RETURN_ON_ERROR(linux_mmap_block_file_offset(handle, block, &block_offset), TAG, \"nand_is_bad: mmap block offset failed\");\n\n    ESP_RETURN_ON_ERROR(nand_emul_read(handle, block_offset + handle->chip.page_size, markers, sizeof(markers)),\n                        TAG, \"Error in nand_is_bad\");\n\n    ESP_LOGD(TAG, \"is_bad, block=%\"PRIu32\", file_off=%zu,indicator = %02x,%02x\", block, block_offset, markers[0], markers[1]);\n    *is_bad_status = (markers[0] != 0xFF || markers[1] != 0xFF);\n    return ESP_OK;\n}\n\nesp_err_t nand_mark_bad(spi_nand_flash_device_t *handle, uint32_t block)\n{\n    size_t block_base = 0;\n\n    uint64_t first_block_page = (uint64_t)block * (1ull << handle->chip.log2_ppb);\n    ESP_LOGD(TAG, \"mark_bad, block=%\"PRIu32\", first_page=%\"PRIu64\"\", block, first_block_page);\n\n    ESP_RETURN_ON_ERROR(linux_mmap_block_file_offset(handle, block, &block_base), TAG, \"nand_mark_bad: mmap block offset failed\");\n    ESP_RETURN_ON_ERROR(nand_emul_erase_block(handle, block_base), TAG, \"nand_mark_bad: erase failed\");\n\n    ESP_RETURN_ON_ERROR(nand_emul_write(handle, block_base + handle->chip.page_size,\n                                        s_oob_mark_bad_markers, sizeof(s_oob_mark_bad_markers)), TAG, \"nand_mark_bad: OOB marker write failed\");\n\n    return ESP_OK;\n}\n\nesp_err_t nand_erase_block(spi_nand_flash_device_t *handle, uint32_t block)\n{\n    ESP_LOGD(TAG, \"erase_block, block=%\"PRIu32\",\", block);\n    esp_err_t ret = ESP_OK;\n    size_t address = 0;\n\n    ESP_RETURN_ON_ERROR(linux_mmap_block_file_offset(handle, block, &address), TAG, \"nand_erase_block: mmap block offset failed\");\n\n    ESP_RETURN_ON_ERROR(nand_emul_erase_block(handle, address), TAG, \"Error in nand_erase %x\", ret);\n    return ESP_OK;\n}\n\nstatic esp_err_t nand_erase_good_block(spi_nand_flash_device_t *handle, uint32_t block)\n{\n    ESP_LOGD(TAG, \"erase_block, block=%\"PRIu32\",\", block);\n    esp_err_t ret = ESP_OK;\n    bool is_bad = false;\n    ret = nand_is_bad(handle, block, &is_bad);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Error querying bad block status for block=%\"PRIu32\"\", block);\n        return ret;\n    }\n    if (is_bad) {\n        ESP_LOGD(TAG, \"skip erase of bad block=%\"PRIu32\"\", block);\n        return ESP_OK;\n    }\n    ret = nand_erase_block(handle, block);\n    return ret;\n}\n\nesp_err_t nand_erase_chip(spi_nand_flash_device_t *handle)\n{\n    esp_err_t ret = ESP_OK;\n    for (int i = 0; i < handle->chip.num_blocks; i++) {\n        esp_err_t err = nand_erase_good_block(handle, (uint32_t)i);\n        if (err == ESP_ERR_NOT_FINISHED) {\n            ret = ESP_ERR_NOT_FINISHED;\n        } else if (err != ESP_OK) {\n            ESP_LOGE(TAG, \"Error in nand_erase_chip %d\", err);\n            return err;\n        }\n    }\n    return ret;\n}\n\nesp_err_t nand_prog(spi_nand_flash_device_t *handle, uint32_t page, const uint8_t *data)\n{\n    ESP_LOGV(TAG, \"prog, page=%\"PRIu32\",\", page);\n    esp_err_t ret = ESP_OK;\n    uint32_t data_offset = page * handle->chip.emulated_page_size;\n\n    ESP_RETURN_ON_ERROR(nand_emul_write(handle, data_offset, data, handle->chip.page_size), TAG, \"Error in nand_prog %d\", ret);\n    ESP_RETURN_ON_ERROR(nand_emul_write(handle, data_offset + handle->chip.page_size,\n                                        s_oob_used_page_markers, sizeof(s_oob_used_page_markers)), TAG, \"Error in nand_prog %d\", ret);\n\n    return ret;\n}\n\nesp_err_t nand_is_free(spi_nand_flash_device_t *handle, uint32_t page, bool *is_free_status)\n{\n    esp_err_t ret = ESP_OK;\n    uint8_t markers[4];\n\n    ESP_RETURN_ON_ERROR(nand_emul_read(handle, page * handle->chip.emulated_page_size + handle->chip.page_size,\n                                       markers, sizeof(markers)),\n                        TAG, \"Error in nand_is_free %d\", ret);\n\n    ESP_LOGD(TAG, \"is free, page=%\"PRIu32\", used_marker=%02x%02x,\", page, markers[2], markers[3]);\n    *is_free_status = (markers[2] == 0xFF && markers[3] == 0xFF);\n    return ret;\n}\n\nesp_err_t nand_read(spi_nand_flash_device_t *handle, uint32_t page, size_t offset, size_t length, uint8_t *data)\n{\n    ESP_LOGV(TAG, \"read, page=%\"PRIu32\", offset=%ld, length=%ld\", page, offset, length);\n    assert(page < handle->chip.num_blocks * (1 << handle->chip.log2_ppb));\n    esp_err_t ret = ESP_OK;\n\n    ESP_RETURN_ON_ERROR(nand_emul_read(handle, page * handle->chip.emulated_page_size + offset, data, length),\n                        TAG, \"Error in nand_read %d\", ret);\n\n    return ret;\n}\n\nesp_err_t nand_copy(spi_nand_flash_device_t *handle, uint32_t src, uint32_t dst)\n{\n    ESP_LOGD(TAG, \"copy, src=%\"PRIu32\", dst=%\"PRIu32\"\", src, dst);\n    esp_err_t ret = ESP_OK;\n    uint32_t dst_offset = dst * handle->chip.emulated_page_size;\n    uint32_t src_offset = src * handle->chip.emulated_page_size;\n\n    ESP_RETURN_ON_ERROR(nand_emul_read(handle, (size_t)src_offset, (void *)handle->read_buffer, handle->chip.page_size),\n                        TAG, \"Error in nand_copy %d\", ret);\n    ESP_RETURN_ON_ERROR(nand_emul_write(handle, (size_t)dst_offset, (void *)handle->read_buffer, handle->chip.page_size),\n                        TAG, \"Error in nand_copy %d\", ret);\n    ESP_RETURN_ON_ERROR(nand_emul_write(handle, (size_t)dst_offset + handle->chip.page_size,\n                                        s_oob_used_page_markers, sizeof(s_oob_used_page_markers)), TAG, \"Error in nand_copy %d\", ret);\n\n    return ret;\n}\n\nesp_err_t nand_get_ecc_status(spi_nand_flash_device_t *handle, uint32_t page)\n{\n    esp_err_t ret = ESP_OK;\n    return ret;\n}\n"
  },
  {
    "path": "spi_nand_flash/src/nand_impl_wrap.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include \"esp_check.h\"\n#include \"esp_err.h\"\n#include \"spi_nand_flash.h\"\n#include \"nand.h\"\n#include \"nand_impl.h\"\n\nesp_err_t nand_wrap_is_bad(spi_nand_flash_device_t *handle, uint32_t block, bool *is_bad_status)\n{\n    esp_err_t ret = ESP_OK;\n    xSemaphoreTake(handle->mutex, portMAX_DELAY);\n    ret = nand_is_bad(handle, block, is_bad_status);\n    xSemaphoreGive(handle->mutex);\n    return ret;\n}\n\nesp_err_t nand_wrap_mark_bad(spi_nand_flash_device_t *handle, uint32_t block)\n{\n    esp_err_t ret = ESP_OK;\n    xSemaphoreTake(handle->mutex, portMAX_DELAY);\n    ret = nand_mark_bad(handle, block);\n    xSemaphoreGive(handle->mutex);\n    return ret;\n}\n\nesp_err_t nand_wrap_erase_chip(spi_nand_flash_device_t *handle)\n{\n    esp_err_t ret = ESP_OK;\n    xSemaphoreTake(handle->mutex, portMAX_DELAY);\n    ret = nand_erase_chip(handle);\n    xSemaphoreGive(handle->mutex);\n    return ret;\n}\n\nesp_err_t nand_wrap_erase_block(spi_nand_flash_device_t *handle, uint32_t block)\n{\n    esp_err_t ret = ESP_OK;\n    xSemaphoreTake(handle->mutex, portMAX_DELAY);\n    ret = nand_erase_block(handle, block);\n    xSemaphoreGive(handle->mutex);\n    return ret;\n}\n\nesp_err_t nand_wrap_prog(spi_nand_flash_device_t *handle, uint32_t page, const uint8_t *data)\n{\n    esp_err_t ret = ESP_OK;\n    xSemaphoreTake(handle->mutex, portMAX_DELAY);\n    ret = nand_prog(handle, page, data);\n    xSemaphoreGive(handle->mutex);\n    return ret;\n}\n\nesp_err_t nand_wrap_is_free(spi_nand_flash_device_t *handle, uint32_t page, bool *is_free_status)\n{\n    esp_err_t ret = ESP_OK;\n    xSemaphoreTake(handle->mutex, portMAX_DELAY);\n    ret = nand_is_free(handle, page, is_free_status);\n    xSemaphoreGive(handle->mutex);\n    return ret;\n}\n\nesp_err_t nand_wrap_read(spi_nand_flash_device_t *handle, uint32_t page, size_t offset, size_t length, uint8_t *data)\n{\n    esp_err_t ret = ESP_OK;\n    xSemaphoreTake(handle->mutex, portMAX_DELAY);\n    ret = nand_read(handle, page, offset, length, data);\n    xSemaphoreGive(handle->mutex);\n    return ret;\n}\n\nesp_err_t nand_wrap_copy(spi_nand_flash_device_t *handle, uint32_t src, uint32_t dst)\n{\n    esp_err_t ret = ESP_OK;\n    xSemaphoreTake(handle->mutex, portMAX_DELAY);\n    ret = nand_copy(handle, src, dst);\n    xSemaphoreGive(handle->mutex);\n    return ret;\n}\n\nesp_err_t nand_wrap_get_ecc_status(spi_nand_flash_device_t *handle, uint32_t page)\n{\n    esp_err_t ret = ESP_OK;\n    xSemaphoreTake(handle->mutex, portMAX_DELAY);\n    ret = nand_get_ecc_status(handle, page);\n    xSemaphoreGive(handle->mutex);\n    return ret;\n}\n"
  },
  {
    "path": "spi_nand_flash/src/nand_linux_mmap_emul.c",
    "content": "/*\n* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n*\n* SPDX-License-Identifier: Apache-2.0\n*/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <inttypes.h>\n#include <sys/mman.h>\n#include <sys/stat.h>\n#include <fcntl.h>\n#include <unistd.h>\n#include <errno.h>\n#include <assert.h>\n#include \"esp_log.h\"\n#include \"nand_linux_mmap_emul.h\"\n#include \"nand.h\"\n\nstatic const char *TAG = \"nand_linux_emul\";\n\n// Initialize NAND flash Emulation\n// Exposes direct pointer to the memory mapped file created by nand_partition_mmap\n// No address alignment is performed\nstatic esp_err_t nand_emul_mmap_init(nand_mmap_emul_handle_t *emul_handle)\n{\n    if (emul_handle->mem_file_buf != NULL) {\n        ESP_LOGE(TAG, \"NAND flash already initialized\");\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    // Open the backing file. If nand_emul_init already opened it via mkstemp(),\n    // mem_file_fd is valid and we skip open().\n    if (emul_handle->mem_file_fd == -1) {\n        emul_handle->mem_file_fd = open(emul_handle->file_mmap_ctrl.flash_file_name, O_RDWR | O_CREAT, 0600);\n    }\n\n    if (emul_handle->mem_file_fd == -1) {\n        ESP_LOGE(TAG, \"Failed to open NAND file %s: %s\",\n                 emul_handle->file_mmap_ctrl.flash_file_name, strerror(errno));\n        return ESP_ERR_NOT_FOUND;\n    }\n\n    // Set file size\n    if (ftruncate(emul_handle->mem_file_fd, emul_handle->file_mmap_ctrl.flash_file_size) != 0) {\n        ESP_LOGE(TAG, \"Failed to set NAND file size: %s\", strerror(errno));\n        close(emul_handle->mem_file_fd);\n        return ESP_ERR_INVALID_SIZE;\n    }\n\n    // Map file to memory\n    emul_handle->mem_file_buf = mmap(NULL, emul_handle->file_mmap_ctrl.flash_file_size,\n                                     PROT_READ | PROT_WRITE, MAP_SHARED,\n                                     emul_handle->mem_file_fd, 0);\n    if (emul_handle->mem_file_buf == MAP_FAILED) {\n        ESP_LOGE(TAG, \"Failed to mmap NAND file: %s\", strerror(errno));\n        close(emul_handle->mem_file_fd);\n        return ESP_ERR_NO_MEM;\n    }\n\n    // Initialize with 0xFF (erased state)\n    memset(emul_handle->mem_file_buf, 0xFF, emul_handle->file_mmap_ctrl.flash_file_size);\n\n    ESP_LOGI(TAG, \"NAND flash emulation initialized: %s (size: %zu bytes)\",\n             emul_handle->file_mmap_ctrl.flash_file_name,\n             emul_handle->file_mmap_ctrl.flash_file_size);\n\n    return ESP_OK;\n}\n\n// Cleanup NAND flash emulation\nstatic esp_err_t nand_emul_mmap_deinit(nand_mmap_emul_handle_t *emul_handle)\n{\n    if (emul_handle->mem_file_buf == NULL) {\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    // Unmap memory\n    if (munmap(emul_handle->mem_file_buf, emul_handle->file_mmap_ctrl.flash_file_size) != 0) {\n        ESP_LOGE(TAG, \"Failed to munmap NAND file: %s\", strerror(errno));\n        return ESP_ERR_INVALID_RESPONSE;\n    }\n\n    // Close file\n    if (close(emul_handle->mem_file_fd) != 0) {\n        ESP_LOGE(TAG, \"Failed to close NAND file: %s\", strerror(errno));\n        return ESP_ERR_INVALID_RESPONSE;\n    }\n\n    // Remove file if requested\n    if (!emul_handle->file_mmap_ctrl.keep_dump) {\n        if (remove(emul_handle->file_mmap_ctrl.flash_file_name) != 0) {\n            ESP_LOGE(TAG, \"Failed to remove NAND file: %s\", strerror(errno));\n            return ESP_ERR_INVALID_RESPONSE;\n        }\n    }\n\n    // Reset state\n    emul_handle->mem_file_buf = NULL;\n    emul_handle->mem_file_fd = -1;\n    memset(&emul_handle->file_mmap_ctrl, 0, sizeof(emul_handle->file_mmap_ctrl));\n\n    return ESP_OK;\n}\n\nesp_err_t nand_emul_init(spi_nand_flash_device_t *handle, nand_file_mmap_emul_config_t *cfg)\n{\n    nand_mmap_emul_handle_t *emul_handle = heap_caps_calloc(1, sizeof(nand_mmap_emul_handle_t), MALLOC_CAP_DEFAULT);\n    if (emul_handle == NULL) {\n        return ESP_ERR_NO_MEM;\n    }\n    emul_handle->mem_file_buf = NULL;\n    emul_handle->mem_file_fd = -1;\n#ifdef CONFIG_NAND_ENABLE_STATS\n    emul_handle->stats.read_ops = 0;\n    emul_handle->stats.write_ops = 0;\n    emul_handle->stats.erase_ops = 0;\n    emul_handle->stats.read_bytes = 0;\n    emul_handle->stats.write_bytes = 0;\n#endif //CONFIG_NAND_ENABLE_STATS\n    handle->emul_handle = emul_handle;\n\n    // Store configuration\n    if (!cfg->flash_file_size) {\n        cfg->flash_file_size = EMULATED_NAND_SIZE;\n    }\n    if (*(cfg->flash_file_name)) {\n        // Named file: copy the caller-provided path\n        strlcpy(emul_handle->file_mmap_ctrl.flash_file_name,\n                cfg->flash_file_name,\n                sizeof(emul_handle->file_mmap_ctrl.flash_file_name));\n    } else {\n        // Temporary file: copy the template and let mkstemp resolve it now,\n        // so that nand_emul_mmap_init sees the real path and an already-open fd.\n        strlcpy(emul_handle->file_mmap_ctrl.flash_file_name,\n                \"/tmp/idf-nand-XXXXXX\",\n                sizeof(emul_handle->file_mmap_ctrl.flash_file_name));\n        emul_handle->mem_file_fd = mkstemp(emul_handle->file_mmap_ctrl.flash_file_name);\n        if (emul_handle->mem_file_fd == -1) {\n            ESP_LOGE(TAG, \"Failed to create temporary NAND file: %s\", strerror(errno));\n            free(emul_handle);\n            handle->emul_handle = NULL;\n            return ESP_ERR_NOT_FOUND;\n        }\n    }\n    emul_handle->file_mmap_ctrl.flash_file_size = cfg->flash_file_size ? cfg->flash_file_size : EMULATED_NAND_SIZE;\n    emul_handle->file_mmap_ctrl.keep_dump = cfg->keep_dump;\n\n    esp_err_t err = nand_emul_mmap_init(emul_handle);\n    if (err != ESP_OK) {\n        free(emul_handle);\n        handle->emul_handle = NULL;\n    }\n    return err;\n}\n\nesp_err_t nand_emul_deinit(spi_nand_flash_device_t *handle)\n{\n    if (handle == NULL || handle->emul_handle == NULL) {\n        return ESP_OK;\n    }\n    esp_err_t ret = nand_emul_mmap_deinit(handle->emul_handle);\n    free(handle->emul_handle);\n    handle->emul_handle = NULL;\n    return ret;\n}\n\n// Read from NAND\nesp_err_t nand_emul_read(spi_nand_flash_device_t *handle, size_t addr, void *dst, size_t size)\n{\n    nand_mmap_emul_handle_t *emul_handle = handle->emul_handle;\n    if (emul_handle == NULL) {\n        return ESP_ERR_INVALID_STATE;\n    }\n    if (emul_handle->mem_file_buf == NULL) {\n        return ESP_ERR_INVALID_STATE;\n    }\n    size_t limit = emul_handle->file_mmap_ctrl.flash_file_size;\n    /* Avoid computing addr + size for the bounds test: with unsigned size_t that sum can\n     * wrap, so addr + size > limit could be false even when the access runs past the end.\n     * If size > limit the range is invalid. Otherwise size <= limit makes (limit - size)\n     * well defined, and addr > limit - size is equivalent to addr + size > limit. */\n    if (size > limit || addr > limit - size) {\n        return ESP_ERR_INVALID_SIZE;\n    }\n\n    void *src_addr = emul_handle->mem_file_buf + addr;\n    memcpy(dst, src_addr, size);\n\n#ifdef CONFIG_NAND_ENABLE_STATS\n    emul_handle->stats.read_ops++;\n    emul_handle->stats.read_bytes += size;\n#endif\n\n    return ESP_OK;\n}\n\n// Write to NAND\nesp_err_t nand_emul_write(spi_nand_flash_device_t *handle, size_t addr, const void *src, size_t size)\n{\n    nand_mmap_emul_handle_t *emul_handle = handle->emul_handle;\n    if (emul_handle == NULL) {\n        return ESP_ERR_INVALID_STATE;\n    }\n    if (emul_handle->mem_file_buf == NULL) {\n        return ESP_ERR_INVALID_STATE;\n    }\n    size_t limit = emul_handle->file_mmap_ctrl.flash_file_size;\n    /* Overflow-safe range check; see comment in nand_emul_read. */\n    if (size > limit || addr > limit - size) {\n        return ESP_ERR_INVALID_SIZE;\n    }\n\n    void *dst_addr = emul_handle->mem_file_buf + addr;\n\n    // Emulate NAND behavior: can only change 1->0\n    for (size_t i = 0; i < size; i++) {\n        ((uint8_t *)dst_addr)[i] &= ((uint8_t *)src)[i];\n    }\n\n#ifdef CONFIG_NAND_ENABLE_STATS\n    emul_handle->stats.write_ops++;\n    emul_handle->stats.write_bytes += size;\n#endif\n\n    return ESP_OK;\n}\n\n// Erase NAND memory range\nesp_err_t nand_emul_erase_block(spi_nand_flash_device_t *handle, size_t offset)\n{\n    nand_mmap_emul_handle_t *emul_handle = handle->emul_handle;\n    if (emul_handle == NULL) {\n        return ESP_ERR_INVALID_STATE;\n    }\n    if (emul_handle->mem_file_buf == NULL) {\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    /* Erase one physical block in the mmap file: ppb pages × (data + OOB) each.\n     * chip.block_size is data-only (BDL); nbytes is the on-disk stride for this layer. */\n    const size_t nbytes = (size_t)(1u << handle->chip.log2_ppb) * (size_t)handle->chip.emulated_page_size;\n    size_t limit = emul_handle->file_mmap_ctrl.flash_file_size;\n    /* Same principle as read/write: do not test offset + nbytes (unsigned wrap). */\n    if (nbytes > limit || offset > limit - nbytes) {\n        return ESP_ERR_INVALID_SIZE;\n    }\n\n    void *dst_addr = emul_handle->mem_file_buf + offset;\n    memset(dst_addr, 0xFF, nbytes);\n\n#ifdef CONFIG_NAND_ENABLE_STATS\n    emul_handle->stats.erase_ops++;\n#endif\n\n    return ESP_OK;\n}\n\n#ifdef CONFIG_NAND_ENABLE_STATS\n// Clear statistics\nvoid nand_emul_clear_stats(spi_nand_flash_device_t *handle)\n{\n    nand_mmap_emul_handle_t *emul_handle = handle->emul_handle;\n    if (emul_handle == NULL) {\n        return;\n    }\n    emul_handle->stats.read_ops = 0;\n    emul_handle->stats.write_ops = 0;\n    emul_handle->stats.erase_ops = 0;\n    emul_handle->stats.read_bytes = 0;\n    emul_handle->stats.write_bytes = 0;\n}\n#endif\n"
  },
  {
    "path": "spi_nand_flash/src/nand_wl_blockdev.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include \"esp_check.h\"\n#include \"esp_log.h\"\n#include \"nand.h\"\n#include \"esp_blockdev.h\"\n#include \"esp_nand_blockdev.h\"\n#include \"nand_device_types.h\"\n\nstatic const char *TAG = \"nand_wl_blockdev\";\n\n/**************************************************************************************\n **************************************************************************************\n * Block Device Layer interface implementation\n **************************************************************************************\n */\n\nstatic esp_err_t spi_nand_flash_wl_blockdev_read(esp_blockdev_handle_t handle, uint8_t *dst_buf, size_t dst_buf_size, uint64_t src_addr, size_t data_read_len)\n{\n    uint32_t page_size = (uint32_t)handle->geometry.read_size;\n\n    if (page_size == 0) {\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n\n    if (dst_buf == NULL || dst_buf_size < data_read_len) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    if ((src_addr % page_size) != 0 || (data_read_len % page_size) != 0) {\n        ESP_LOGE(TAG, \"Source address 0x%.16\" PRIx64 \" or Read length 0x%08\" PRIx32 \" is not aligned to Page size %\" PRIu32,\n                 src_addr, (uint32_t)data_read_len, page_size);\n        return ESP_ERR_INVALID_SIZE;\n    }\n\n    if (src_addr + data_read_len > handle->geometry.disk_size) {\n        ESP_LOGE(TAG, \"Read range exceeds device bounds\");\n        return ESP_ERR_INVALID_SIZE;\n    }\n\n    spi_nand_flash_device_t *dev_handle = (spi_nand_flash_device_t *)((esp_blockdev_handle_t)handle->ctx)->ctx;\n    uint32_t start_page_id = (uint32_t)(src_addr >> dev_handle->chip.log2_page_size);\n    uint32_t page_count = (uint32_t)(data_read_len >> dev_handle->chip.log2_page_size);\n\n    esp_err_t ret = ESP_OK;\n    for (uint32_t page_id = start_page_id; page_id < (start_page_id + page_count); page_id++) {\n        ret = spi_nand_flash_read_page(dev_handle, dst_buf, page_id);\n        if (ret) {\n            ESP_LOGE(TAG, \"%s, Failed to read the page, result=0x%08x\", __func__, ret);\n            return ret;\n        }\n        dst_buf += page_size;\n    }\n    ESP_LOGV(TAG, \"read - src_addr=0x%.16\" PRIx64 \", size=0x%08\" PRIx32 \", result=0x%08x\", src_addr, (uint32_t)data_read_len, ret);\n    return ret;\n}\n\nstatic esp_err_t spi_nand_flash_wl_blockdev_write(esp_blockdev_handle_t handle, const uint8_t *src_buf, uint64_t dst_addr, size_t data_write_len)\n{\n    uint32_t page_size = (uint32_t)handle->geometry.write_size;\n\n    if (handle->device_flags.read_only || page_size == 0) {\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n\n    if (src_buf == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    if ((dst_addr % page_size) != 0 || (data_write_len % page_size) != 0) {\n        ESP_LOGE(TAG, \"Write address 0x%\" PRIx64 \" not aligned to page size %\" PRIu32, dst_addr, page_size);\n        return ESP_ERR_INVALID_SIZE;\n    }\n\n    if (dst_addr + data_write_len > handle->geometry.disk_size) {\n        ESP_LOGE(TAG, \"Write range exceeds device bounds\");\n        return ESP_ERR_INVALID_SIZE;\n    }\n\n    spi_nand_flash_device_t *dev_handle = (spi_nand_flash_device_t *)((esp_blockdev_handle_t)handle->ctx)->ctx;\n    uint32_t start_page_id = (uint32_t)(dst_addr >> dev_handle->chip.log2_page_size);\n    uint32_t page_count = (uint32_t)(data_write_len >> dev_handle->chip.log2_page_size);\n    esp_err_t ret = ESP_OK;\n    for (uint32_t page_id = start_page_id; page_id < (start_page_id + page_count); page_id++) {\n        ret = spi_nand_flash_write_page(dev_handle, src_buf, page_id);\n        if (ret) {\n            ESP_LOGE(TAG, \"%s, Failed to write the page\", __func__);\n            return ret;\n        }\n        src_buf += page_size;\n    }\n    ESP_LOGV(TAG, \"write - dst_addr=0x%.16\" PRIx64 \", size=0x%08\" PRIx32 \", result=0x%08x\", dst_addr, (uint32_t)data_write_len, ret);\n    return ret;\n}\n\nstatic esp_err_t spi_nand_flash_wl_blockdev_erase(esp_blockdev_handle_t handle, uint64_t start_addr, size_t erase_len)\n{\n    uint32_t page_size = (uint32_t)handle->geometry.write_size;\n    uint32_t erase_size = (uint32_t)handle->geometry.erase_size;\n\n    if (handle->device_flags.read_only || erase_size == 0 || page_size == 0) {\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n\n    if ((start_addr % erase_size) != 0 || (erase_len % erase_size) != 0 || (erase_size % page_size != 0)) {\n        ESP_LOGE(TAG, \"Start address 0x%\" PRIx64 \" or Erase length %zu not aligned to Erase size %\" PRIu32,\n                 start_addr, erase_len, erase_size);\n        return ESP_ERR_INVALID_SIZE;\n    }\n\n    if (start_addr + erase_len > handle->geometry.disk_size) {\n        ESP_LOGE(TAG, \"Erase range exceeds device bounds\");\n        return ESP_ERR_INVALID_SIZE;\n    }\n\n    spi_nand_flash_device_t *dev_handle = (spi_nand_flash_device_t *)((esp_blockdev_handle_t)handle->ctx)->ctx;\n    uint32_t page_count = (uint32_t)(erase_len >> dev_handle->chip.log2_page_size);\n    uint32_t start_page_id = (uint32_t)(start_addr >> dev_handle->chip.log2_page_size);\n    esp_err_t ret = ESP_OK;\n    for (uint32_t page_id = start_page_id; page_id < (start_page_id + page_count); page_id++) {\n        ret = spi_nand_flash_trim(dev_handle, page_id);\n        if (ret != ESP_OK) {\n            ESP_LOGE(TAG, \"%s, Failed to trim the page\", __func__);\n            return ret;\n        }\n    }\n    ret = spi_nand_flash_gc(dev_handle);\n    ESP_LOGV(TAG, \"erase - start_addr=0x%.16\" PRIx64 \", size=0x%zx, result=0x%08x\", start_addr, erase_len, ret);\n    return ret;\n}\n\nstatic esp_err_t spi_nand_flash_wl_blockdev_sync(esp_blockdev_handle_t handle)\n{\n    spi_nand_flash_device_t *dev_handle = (spi_nand_flash_device_t *)((esp_blockdev_handle_t)handle->ctx)->ctx;\n    return spi_nand_flash_sync(dev_handle);\n}\n\nstatic esp_err_t spi_nand_flash_wl_blockdev_ioctl(esp_blockdev_handle_t handle, const uint8_t cmd, void *args)\n{\n    if (args == NULL) {\n        return ESP_ERR_INVALID_ARG;\n    }\n    esp_err_t ret = ESP_OK;\n\n    esp_blockdev_handle_t nand_bdl = (esp_blockdev_handle_t)handle->ctx;\n    spi_nand_flash_device_t *dev_handle = (spi_nand_flash_device_t *)nand_bdl->ctx;\n\n    switch (cmd) {\n    case ESP_BLOCKDEV_CMD_MARK_DELETED: {\n        esp_blockdev_cmd_arg_erase_t *trim_arg = (esp_blockdev_cmd_arg_erase_t *)args;\n        uint32_t page_size = (uint32_t)handle->geometry.write_size;\n        if (page_size == 0) {\n            return ESP_ERR_NOT_SUPPORTED;\n        }\n        if ((trim_arg->start_addr % page_size) != 0 ||\n                (trim_arg->erase_len % page_size != 0)) {\n            ESP_LOGE(TAG, \"Start address/length 0x%\" PRIx64 \"/%zu not aligned to page size %\" PRIu32,\n                     trim_arg->start_addr, trim_arg->erase_len, page_size);\n            return ESP_ERR_INVALID_SIZE;\n        }\n        uint32_t page_count = (uint32_t)(trim_arg->erase_len >> dev_handle->chip.log2_page_size);\n        uint32_t start_page_id = (uint32_t)(trim_arg->start_addr >> dev_handle->chip.log2_page_size);\n        uint32_t total_pages = (uint32_t)(handle->geometry.disk_size / page_size);\n\n        if ((start_page_id + page_count) > total_pages) {\n            ESP_LOGE(TAG, \"TRIM range exceeds device bounds: start_page_id=%\"PRIu32\" count=%\"PRIu32\" total=%\"PRIu32\"\",\n                     start_page_id, page_count, total_pages);\n            return ESP_ERR_INVALID_ARG;\n        }\n        for (uint32_t page_id = start_page_id; page_id < (start_page_id + page_count); page_id++) {\n            ret = spi_nand_flash_trim(dev_handle, page_id);\n            if (ret != ESP_OK) {\n                ESP_LOGE(TAG, \"Failed to trim page %\"PRIu32\"\", page_id);\n                return ret;\n            }\n        }\n    }\n    break;\n\n    case ESP_BLOCKDEV_CMD_GET_NAND_FLASH_INFO:\n    case ESP_BLOCKDEV_CMD_GET_BAD_BLOCKS_COUNT:\n    case ESP_BLOCKDEV_CMD_GET_ECC_STATS: {\n        ret = nand_bdl->ops->ioctl(nand_bdl, cmd, args);\n    }\n    break;\n\n    default:\n        return ESP_ERR_NOT_SUPPORTED;\n    }\n\n    return ret;\n}\n\nstatic esp_err_t spi_nand_flash_wl_blockdev_release(esp_blockdev_handle_t handle)\n{\n    esp_blockdev_handle_t nand_handle = (esp_blockdev_handle_t)handle->ctx;\n    spi_nand_flash_device_t *dev_handle = (spi_nand_flash_device_t *)nand_handle->ctx;\n\n    nand_wl_detach_ops(dev_handle);\n    esp_err_t ret = nand_handle->ops->release(nand_handle);\n    free(handle);\n\n    return ret;\n}\n\nstatic const esp_blockdev_ops_t spi_nand_flash_wl_blockdev_ops = {\n    .read = spi_nand_flash_wl_blockdev_read,\n    .write = spi_nand_flash_wl_blockdev_write,\n    .erase = spi_nand_flash_wl_blockdev_erase,\n    .ioctl = spi_nand_flash_wl_blockdev_ioctl,\n    .sync = spi_nand_flash_wl_blockdev_sync,\n    .release = spi_nand_flash_wl_blockdev_release,\n};\n\nesp_err_t spi_nand_flash_wl_get_blockdev(esp_blockdev_handle_t nand_bdl, esp_blockdev_handle_t *out_bdl_handle_ptr)\n{\n    // Validate input parameters\n    ESP_RETURN_ON_FALSE(nand_bdl != NULL, ESP_ERR_INVALID_ARG, TAG, \"nand_bdl cannot be NULL\");\n    ESP_RETURN_ON_FALSE(out_bdl_handle_ptr != NULL, ESP_ERR_INVALID_ARG, TAG, \"out_bdl_handle_ptr cannot be NULL\");\n\n    spi_nand_flash_device_t *dev = (spi_nand_flash_device_t *)nand_bdl->ctx;\n    ESP_RETURN_ON_FALSE(dev != NULL, ESP_ERR_INVALID_ARG, TAG, \"spi_nand_flash_device_t pointer cannot be NULL\");\n\n    // Validate that Flash BDL operations are available\n    ESP_RETURN_ON_FALSE(nand_bdl->ops != NULL, ESP_ERR_INVALID_STATE, TAG, \"Flash BDL ops cannot be NULL\");\n    ESP_RETURN_ON_FALSE(nand_bdl->ops->read != NULL, ESP_ERR_INVALID_STATE, TAG, \"Flash BDL read operation is required\");\n    ESP_RETURN_ON_FALSE(nand_bdl->ops->write != NULL, ESP_ERR_INVALID_STATE, TAG, \"Flash BDL write operation is required\");\n    ESP_RETURN_ON_FALSE(nand_bdl->ops->erase != NULL, ESP_ERR_INVALID_STATE, TAG, \"Flash BDL erase operation is required\");\n    ESP_RETURN_ON_FALSE(nand_bdl->ops->ioctl != NULL, ESP_ERR_INVALID_STATE, TAG, \"Flash BDL ioctl operation is required\");\n    ESP_RETURN_ON_FALSE(nand_bdl->ops->release != NULL, ESP_ERR_INVALID_STATE, TAG, \"Flash BDL release operation is required\");\n\n    // Initialize ops with dhara operations\n    esp_err_t ret = nand_wl_attach_ops(dev);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to attach wear-leveling operations\");\n        return ret;\n    }\n\n    // Initialize dhara lib\n    if (dev->ops->init == NULL) {\n        ESP_LOGE(TAG, \"WL init operation is NULL\");\n        nand_wl_detach_ops(dev);\n        return ESP_FAIL;\n    }\n\n    ret = dev->ops->init(dev, nand_bdl);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to initialize wear-leveling layer\");\n        nand_wl_detach_ops(dev);\n        return ret;\n    }\n\n    esp_blockdev_t *blockdev = (esp_blockdev_t *) heap_caps_calloc(1, sizeof(esp_blockdev_t), MALLOC_CAP_DEFAULT);\n    if (blockdev == NULL) {\n        dev->ops->deinit(dev);\n        nand_wl_detach_ops(dev);\n        return ESP_ERR_NO_MEM;\n    }\n    blockdev->ctx = (void *)nand_bdl;\n\n    blockdev->device_flags.read_only = 0;\n    blockdev->device_flags.encrypted = 0;\n    blockdev->device_flags.erase_before_write = 0;\n    blockdev->device_flags.and_type_write = 0;\n    blockdev->device_flags.default_val_after_erase = 1;\n    blockdev->device_flags.reserved = 0;\n    blockdev->ops = &spi_nand_flash_wl_blockdev_ops;\n\n    // Set up geometry information (BDL exposes logical pages as \"sectors\" per esp_blockdev API)\n    uint32_t num_pages;\n    spi_nand_flash_get_page_count(dev, &num_pages);\n    uint32_t page_size = dev->chip.page_size;\n\n    blockdev->geometry.disk_size = (uint64_t)num_pages * page_size;\n    blockdev->geometry.write_size = page_size;\n    blockdev->geometry.read_size = page_size;\n    blockdev->geometry.erase_size = page_size;\n    blockdev->geometry.recommended_write_size = page_size;\n    blockdev->geometry.recommended_read_size = page_size;\n    blockdev->geometry.recommended_erase_size = page_size;\n\n    *out_bdl_handle_ptr = blockdev;\n    return ESP_OK;\n}\n"
  },
  {
    "path": "spi_nand_flash/src/spi_nand_flash_test_helpers.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"spi_nand_flash_test_helpers.h\"\n\n#define SPI_NAND_FLASH_PATTERN_SEED  0x12345678U\n\nvoid spi_nand_flash_fill_buffer(uint8_t *dst, size_t count)\n{\n    uint32_t *p = (uint32_t *)dst;\n    for (size_t i = 0; i < count; ++i) {\n        p[i] = SPI_NAND_FLASH_PATTERN_SEED + (uint32_t)i;\n    }\n}\n\nvoid spi_nand_flash_fill_buffer_seeded(uint8_t *dst, size_t count, uint32_t seed)\n{\n    uint32_t *p = (uint32_t *)dst;\n    for (size_t i = 0; i < count; ++i) {\n        p[i] = seed + (uint32_t)i;\n    }\n}\n\nint spi_nand_flash_check_buffer(const uint8_t *src, size_t count)\n{\n    const uint32_t *p = (const uint32_t *)src;\n    for (size_t i = 0; i < count; ++i) {\n        if (p[i] != SPI_NAND_FLASH_PATTERN_SEED + (uint32_t)i) {\n            return (int)(i + 1);\n        }\n    }\n    return 0;\n}\n\nint spi_nand_flash_check_buffer_seeded(const uint8_t *src, size_t count, uint32_t seed)\n{\n    const uint32_t *p = (const uint32_t *)src;\n    for (size_t i = 0; i < count; ++i) {\n        if (p[i] != seed + (uint32_t)i) {\n            return (int)(i + 1);\n        }\n    }\n    return 0;\n}\n"
  },
  {
    "path": "spi_nand_flash/src/spi_nand_oper.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 mikkeldamsgaard project\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * SPDX-FileContributor: 2015-2023 Espressif Systems (Shanghai) CO LTD\n */\n\n#include <string.h>\n#include \"spi_nand_oper.h\"\n#include \"driver/spi_master.h\"\n#include \"esp_memory_utils.h\"\n#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE == 1\n#include \"esp_private/esp_cache_private.h\"\n#endif\n\nesp_err_t spi_nand_execute_transaction(spi_nand_flash_device_t *handle, spi_nand_transaction_t *transaction)\n{\n    uint8_t half_duplex = handle->config.flags & SPI_DEVICE_HALFDUPLEX;\n    if (!half_duplex) {\n        uint32_t len = transaction->miso_len > transaction->mosi_len ? transaction->miso_len : transaction->mosi_len;\n        transaction->miso_len = len;\n        transaction->mosi_len = len;\n    }\n\n    spi_transaction_ext_t e = {\n        .base = {\n            .flags = SPI_TRANS_VARIABLE_ADDR |  SPI_TRANS_VARIABLE_CMD |  SPI_TRANS_VARIABLE_DUMMY | transaction->flags,\n            .rxlength = transaction->miso_len * 8,\n            .rx_buffer = transaction->miso_data,\n            .length = transaction->mosi_len * 8,\n            .tx_buffer = transaction->mosi_data,\n            .addr = transaction->address,\n            .cmd = transaction->command\n        },\n        .address_bits = transaction->address_bytes * 8,\n        .command_bits = 8,\n        .dummy_bits = transaction->dummy_bits\n    };\n\n    if (transaction->flags & SPI_TRANS_USE_TXDATA) {\n        assert(transaction->mosi_len <= 4 && \"SPI_TRANS_USE_TXDATA used for a long transaction\");\n        memcpy(e.base.tx_data, transaction->mosi_data, transaction->mosi_len);\n    }\n    if (transaction->flags & SPI_TRANS_USE_RXDATA) {\n        assert(transaction->miso_len <= 4 && \"SPI_TRANS_USE_RXDATA used for a long transaction\");\n    }\n\n    esp_err_t ret = spi_device_transmit(handle->config.device_handle, (spi_transaction_t *) &e);\n    if (ret == ESP_OK) {\n        if (transaction->flags == SPI_TRANS_USE_RXDATA) {\n            memcpy(transaction->miso_data, e.base.rx_data, transaction->miso_len);\n        }\n    }\n    return ret;\n}\n\nesp_err_t spi_nand_read_manufacturer_id(spi_nand_flash_device_t *handle, uint8_t *manufacturer_id)\n{\n    esp_err_t ret = ESP_OK;\n    spi_nand_transaction_t t = {\n        .command = CMD_READ_ID,\n        .address = 0, // This normally selects the manufacturer id. Some chips ignores it, but still expects 8 dummy bits here\n        .address_bytes = 1,\n        .miso_len = 1,\n        .miso_data = manufacturer_id,\n        .flags = SPI_TRANS_USE_RXDATA,\n    };\n    ret = spi_nand_execute_transaction(handle, &t);\n    return ret;\n}\n\nesp_err_t spi_nand_read_device_id(spi_nand_flash_device_t *handle, uint8_t *device_id, uint8_t length)\n{\n    esp_err_t ret = ESP_OK;\n    spi_nand_transaction_t t = {\n        .command = CMD_READ_ID,\n        .address = 0,\n        .address_bytes = 2,\n        .miso_len = length,\n        .miso_data = device_id,\n        .flags = SPI_TRANS_USE_RXDATA,\n    };\n    ret = spi_nand_execute_transaction(handle, &t);\n    return ret;\n}\n\nesp_err_t spi_nand_read_register(spi_nand_flash_device_t *handle, uint8_t reg, uint8_t *val)\n{\n    spi_nand_transaction_t t = {\n        .command = CMD_READ_REGISTER,\n        .address_bytes = 1,\n        .address = reg,\n        .miso_len = 1,\n        .miso_data = val,\n        .flags = SPI_TRANS_USE_RXDATA,\n    };\n\n    return spi_nand_execute_transaction(handle, &t);\n}\n\nesp_err_t spi_nand_write_register(spi_nand_flash_device_t *handle, uint8_t reg, uint8_t val)\n{\n    spi_nand_transaction_t t = {\n        .command = CMD_SET_REGISTER,\n        .address_bytes = 1,\n        .address = reg,\n        .mosi_len = 1,\n        .mosi_data = &val,\n        .flags = SPI_TRANS_USE_TXDATA,\n    };\n\n    return spi_nand_execute_transaction(handle, &t);\n}\n\nesp_err_t spi_nand_write_enable(spi_nand_flash_device_t *handle)\n{\n    spi_nand_transaction_t t = {\n        .command = CMD_WRITE_ENABLE\n    };\n\n    return spi_nand_execute_transaction(handle, &t);\n}\n\nesp_err_t spi_nand_read_page(spi_nand_flash_device_t *handle, uint32_t page)\n{\n    spi_nand_transaction_t t = {\n        .command = CMD_PAGE_READ,\n        .address_bytes = 3,\n        .address = page\n    };\n\n    return spi_nand_execute_transaction(handle, &t);\n}\n\nsize_t spi_nand_get_dma_alignment(void)\n{\n    size_t alignment;\n#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE == 1\n    esp_cache_get_alignment(MALLOC_CAP_DMA, &alignment);\n#else\n    // For non-L1CACHE targets, use DMA alignment of 4 bytes\n    alignment = 4;\n#endif\n    return alignment;\n}\n\nstatic uint16_t check_length_alignment(spi_nand_flash_device_t *handle, uint16_t length, size_t alignment)\n{\n    uint16_t data_len = length;\n\n    bool is_length_unaligned = (length & (alignment - 1)) ? true : false;\n    if (is_length_unaligned) {\n        if (length < alignment) {\n            data_len = ((length + alignment) & ~(alignment - 1));\n        } else {\n            data_len = ((length + (alignment - 1)) & ~(alignment - 1));\n        }\n    }\n    if (!(handle->config.flags & SPI_DEVICE_HALFDUPLEX)) {\n        data_len = data_len + alignment;\n    }\n    return data_len;\n}\n\n#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)\nstatic bool spi_nand_buf_dma_aligned(const void *buf, size_t alignment)\n{\n    return esp_ptr_dma_capable(buf) && (((uintptr_t)buf % alignment) == 0);\n}\n\n/**\n * Prepare the TX buffer for a NAND program-load SPI transaction.\n *\n * When @p length is DMA-aligned but @p user_buf is not DMA-capable or not properly\n * aligned (ESP-IDF >= 5.2), data is copied into handle->temp_buffer and\n * @p *out_manual_dma is set so the caller sets SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL.\n *\n * When @p length is not DMA-aligned we cannot pad the write (extra bytes would be\n * programmed into the NAND page); @p *out_manual_dma stays false and the SPI driver\n * handles alignment internally.\n */\nstatic void spi_nand_tx_prepare_write_buffers(spi_nand_flash_device_t *handle,\n        const uint8_t *user_buf, uint16_t length,\n        const uint8_t **out_data_write, bool *out_manual_dma)\n{\n    *out_data_write = user_buf;\n    *out_manual_dma = false;\n\n    size_t alignment = spi_nand_get_dma_alignment();\n    uint16_t aligned_len = check_length_alignment(handle, length, alignment);\n    if (aligned_len != length) {\n        return;\n    }\n\n    if (!spi_nand_buf_dma_aligned(user_buf, alignment)) {\n        memcpy(handle->temp_buffer, user_buf, length);\n        *out_data_write = handle->temp_buffer;\n    }\n    *out_manual_dma = true;\n}\n#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)\n\n/**\n * Prepare the RX buffer for a NAND read SPI transaction.\n *\n * Decides whether the caller's buffer can be used directly for DMA, or whether the\n * receive must be bounced through handle->temp_buffer.\n *\n * Bounce is needed when:\n *  1. @p length is not DMA-aligned — the padded amount is read into temp_buffer\n *     (*out_data_read_len > length).\n *  2. @p length is DMA-aligned but @p user_buf is not DMA-capable or not properly\n *     aligned (ESP-IDF >= 5.2) — the original length is read into temp_buffer\n *     (*out_data_read_len == length).\n *\n * When *out_data_read != @p user_buf after a successful transaction, copy the useful\n * data back into @p user_buf. The copy is not always from offset 0: in full-duplex\n * fast read, byte 0 of the receive buffer is a dummy clocked during the command /\n * address phase and must be skipped (see spi_nand_fast_read).\n */\nstatic void spi_nand_rx_prepare_read_buffers(spi_nand_flash_device_t *handle, uint8_t *user_buf, uint16_t length,\n        uint8_t **out_data_read, uint16_t *out_data_read_len)\n{\n    size_t alignment = spi_nand_get_dma_alignment();\n    uint16_t aligned_len = check_length_alignment(handle, length, alignment);\n\n    if (aligned_len != length) {\n        *out_data_read = handle->temp_buffer;\n        *out_data_read_len = aligned_len;\n        return;\n    }\n\n#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)\n    if (!spi_nand_buf_dma_aligned(user_buf, alignment)) {\n        *out_data_read = handle->temp_buffer;\n        *out_data_read_len = length;\n        return;\n    }\n#endif\n\n    *out_data_read = user_buf;\n    *out_data_read_len = length;\n}\n\nstatic esp_err_t spi_nand_quad_read(spi_nand_flash_device_t *handle, uint8_t *data, uint16_t column, uint16_t length)\n{\n    uint32_t spi_flags = SPI_TRANS_MODE_QIO;\n    uint8_t cmd = CMD_READ_X4;\n    uint8_t dummy_bits = 8;\n\n    uint8_t *data_read;\n    uint16_t data_read_len;\n\n    spi_nand_rx_prepare_read_buffers(handle, data, length, &data_read, &data_read_len);\n\n    if (handle->config.io_mode == SPI_NAND_IO_MODE_QIO) {\n        spi_flags |= SPI_TRANS_MULTILINE_ADDR;\n        cmd = CMD_READ_QIO;\n        dummy_bits = 4;\n    }\n\n    spi_nand_transaction_t t = {\n        .command = cmd,\n        .address_bytes = 2,\n        .address = column,\n        .miso_len = data_read_len,\n        .miso_data = data_read,\n        .dummy_bits = dummy_bits,\n        .flags = spi_flags,\n    };\n\n#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)\n    t.flags |= SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL;\n#endif\n    esp_err_t ret = spi_nand_execute_transaction(handle, &t);\n\n    if (ret == ESP_OK && (data_read != data)) {\n        memcpy(data, data_read, length);\n    }\n\n    return ret;\n}\n\nstatic esp_err_t spi_nand_dual_read(spi_nand_flash_device_t *handle, uint8_t *data, uint16_t column, uint16_t length)\n{\n    uint32_t spi_flags = SPI_TRANS_MODE_DIO;\n    uint8_t cmd = CMD_READ_X2;\n    uint8_t dummy_bits = 8;\n\n    uint8_t *data_read;\n    uint16_t data_read_len;\n\n    spi_nand_rx_prepare_read_buffers(handle, data, length, &data_read, &data_read_len);\n\n    if (handle->config.io_mode == SPI_NAND_IO_MODE_DIO) {\n        spi_flags |= SPI_TRANS_MULTILINE_ADDR;\n        cmd = CMD_READ_DIO;\n        dummy_bits = 4;\n    }\n\n    spi_nand_transaction_t t = {\n        .command = cmd,\n        .address_bytes = 2,\n        .address = column,\n        .miso_len = data_read_len,\n        .miso_data = data_read,\n        .dummy_bits = dummy_bits,\n        .flags = spi_flags,\n    };\n\n#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)\n    t.flags |= SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL;\n#endif\n    esp_err_t ret = spi_nand_execute_transaction(handle, &t);\n\n    if (ret == ESP_OK && (data_read != data)) {\n        memcpy(data, data_read, length);\n    }\n\n    return ret;\n}\n\nstatic esp_err_t spi_nand_fast_read(spi_nand_flash_device_t *handle, uint8_t *data, uint16_t column, uint16_t length)\n{\n    uint8_t half_duplex = handle->config.flags & SPI_DEVICE_HALFDUPLEX;\n    uint8_t *data_read;\n    uint16_t data_read_len;\n\n    spi_nand_rx_prepare_read_buffers(handle, data, length, &data_read, &data_read_len);\n\n    spi_nand_transaction_t t = {\n        .command = CMD_READ_FAST,\n        .address_bytes = 2,\n        .address = column,\n        .miso_len = data_read_len,\n        .miso_data = data_read,\n    };\n\n#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)\n    t.flags = SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL;\n#endif\n\n    if (half_duplex) {\n        t.dummy_bits = 8;\n    }\n    esp_err_t ret = spi_nand_execute_transaction(handle, &t);\n    if (ret != ESP_OK) {\n        goto fail;\n    }\n\n    if (data_read != data) {\n        if (!half_duplex) {\n            /* In full-duplex fast read, byte 0 in the receive buffer is a dummy\n               clocked in during the command/address phase — skip it.\n               check_length_alignment() guarantees data_read_len > length for\n               full-duplex (it unconditionally pads by 'alignment'), so the +1\n               offset is always within bounds.*/\n            assert(data_read_len > length);\n            memcpy(data, data_read + 1, length);\n        } else {\n            memcpy(data, data_read, length);\n        }\n    }\n\nfail:\n    return ret;\n}\n\nesp_err_t spi_nand_read(spi_nand_flash_device_t *handle, uint8_t *data, uint16_t column, uint16_t length)\n{\n    if (handle->config.io_mode == SPI_NAND_IO_MODE_DOUT || handle->config.io_mode == SPI_NAND_IO_MODE_DIO) {\n        return spi_nand_dual_read(handle, data, column, length);\n    } else if (handle->config.io_mode == SPI_NAND_IO_MODE_QOUT || handle->config.io_mode == SPI_NAND_IO_MODE_QIO) {\n        return spi_nand_quad_read(handle, data, column, length);\n    }\n    return spi_nand_fast_read(handle, data, column, length);\n}\n\nesp_err_t spi_nand_program_execute(spi_nand_flash_device_t *handle, uint32_t page)\n{\n    spi_nand_transaction_t t = {\n        .command = CMD_PROGRAM_EXECUTE,\n        .address_bytes = 3,\n        .address = page\n    };\n\n    return spi_nand_execute_transaction(handle, &t);\n}\n\nesp_err_t spi_nand_program_load(spi_nand_flash_device_t *handle, const uint8_t *data, uint16_t column, uint16_t length)\n{\n    uint8_t cmd = CMD_PROGRAM_LOAD;\n    uint32_t spi_flags = 0;\n    if (handle->config.io_mode == SPI_NAND_IO_MODE_QOUT || handle->config.io_mode == SPI_NAND_IO_MODE_QIO) {\n        cmd = CMD_PROGRAM_LOAD_X4;\n        spi_flags = SPI_TRANS_MODE_QIO;\n    }\n\n    const uint8_t *data_write = data;\n#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)\n    bool manual_dma = false;\n    spi_nand_tx_prepare_write_buffers(handle, data, length, &data_write, &manual_dma);\n    if (manual_dma) {\n        spi_flags |= SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL;\n    }\n#endif\n\n    spi_nand_transaction_t t = {\n        .command = cmd,\n        .address_bytes = 2,\n        .address = column,\n        .mosi_len = length,\n        .mosi_data = data_write,\n        .flags = spi_flags,\n    };\n\n    return spi_nand_execute_transaction(handle, &t);\n}\n\nesp_err_t spi_nand_erase_block(spi_nand_flash_device_t *handle, uint32_t page)\n{\n    spi_nand_transaction_t  t = {\n        .command = CMD_ERASE_BLOCK,\n        .address_bytes = 3,\n        .address = page\n    };\n\n    return spi_nand_execute_transaction(handle, &t);\n}\n"
  },
  {
    "path": "spi_nand_flash/test_app/CMakeLists.txt",
    "content": "# This is the project CMakeLists.txt file for the test subproject\ncmake_minimum_required(VERSION 3.5)\n\nset(COMPONENTS main)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nproject(spi_nand_flash_test)\n"
  },
  {
    "path": "spi_nand_flash/test_app/README.md",
    "content": "| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |\n| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |\n"
  },
  {
    "path": "spi_nand_flash/test_app/main/CMakeLists.txt",
    "content": "set(src \"test_app_main.c\")\n\nif(CONFIG_NAND_FLASH_ENABLE_BDL)\n    list(APPEND src \"test_spi_nand_flash_bdl.c\")\nelse()\n    list(APPEND src \"test_spi_nand_flash.c\")\nendif()\n\nset(priv_reqs unity esp_timer)\nif(\"${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}\" VERSION_GREATER \"5.3\")\n    list(APPEND priv_reqs esp_driver_spi)\nelse()\n    list(APPEND priv_reqs driver)\nendif()\n\nidf_component_register(SRCS ${src}\n                       PRIV_REQUIRES ${priv_reqs}\n                       WHOLE_ARCHIVE\n                       )\n"
  },
  {
    "path": "spi_nand_flash/test_app/main/idf_component.yml",
    "content": "dependencies:\n  espressif/spi_nand_flash:\n    version: '*'\n    override_path: '../../'\n"
  },
  {
    "path": "spi_nand_flash/test_app/main/test_app_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n\n#include \"unity.h\"\n#include \"unity_test_utils.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_newlib.h\"\n#include \"unity_test_utils_memory.h\"\n\nvoid setUp(void)\n{\n    unity_utils_record_free_mem();\n}\n\nvoid tearDown(void)\n{\n    esp_reent_cleanup();    //clean up some of the newlib's lazy allocations\n    unity_utils_evaluate_leaks_direct(32);\n}\n\nvoid app_main(void)\n{\n    printf(\"Running spi_nand_flash component tests\\n\");\n    unity_run_menu();\n}\n"
  },
  {
    "path": "spi_nand_flash/test_app/main/test_spi_nand_flash.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/param.h>\n#include <inttypes.h>\n#include \"esp_attr.h\"\n#include \"esp_intr_alloc.h\"\n#include \"esp_log.h\"\n#include \"esp_timer.h\"\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"freertos/semphr.h\"\n#include \"driver/spi_master.h\"\n#include \"spi_nand_flash.h\"\n#include \"nand_private/nand_impl_wrap.h\"\n#include \"unity.h\"\n#include \"soc/spi_pins.h\"\n#include \"sdkconfig.h\"\n#include \"spi_nand_flash_test_helpers.h\"\n\n\n// Pin mapping\n// ESP32 (VSPI)\n#ifdef CONFIG_IDF_TARGET_ESP32\n#define HOST_ID     SPI3_HOST\n#define PIN_MOSI     SPI3_IOMUX_PIN_NUM_MOSI\n#define PIN_MISO     SPI3_IOMUX_PIN_NUM_MISO\n#define PIN_CLK      SPI3_IOMUX_PIN_NUM_CLK\n#define PIN_CS       SPI3_IOMUX_PIN_NUM_CS\n#define PIN_WP       SPI3_IOMUX_PIN_NUM_WP\n#define PIN_HD       SPI3_IOMUX_PIN_NUM_HD\n#define SPI_DMA_CHAN SPI_DMA_CH_AUTO\n#else // Other chips (SPI2/HSPI)\n#define HOST_ID      SPI2_HOST\n#define PIN_MOSI     SPI2_IOMUX_PIN_NUM_MOSI\n#define PIN_MISO     SPI2_IOMUX_PIN_NUM_MISO\n#define PIN_CLK      SPI2_IOMUX_PIN_NUM_CLK\n#define PIN_CS       SPI2_IOMUX_PIN_NUM_CS\n#define PIN_WP       SPI2_IOMUX_PIN_NUM_WP\n#define PIN_HD       SPI2_IOMUX_PIN_NUM_HD\n#define SPI_DMA_CHAN SPI_DMA_CH_AUTO\n#endif\n\nstatic void do_single_write_test(spi_nand_flash_device_t *flash, uint32_t start_page, uint16_t page_count);\nstatic void setup_bus(spi_host_device_t host_id)\n{\n    spi_bus_config_t spi_bus_cfg = {\n        .mosi_io_num = PIN_MOSI,\n        .miso_io_num = PIN_MISO,\n        .sclk_io_num = PIN_CLK,\n        .quadhd_io_num = PIN_HD,\n        .quadwp_io_num = PIN_WP,\n        .max_transfer_sz = 64,\n    };\n    esp_err_t ret = spi_bus_initialize(host_id, &spi_bus_cfg, SPI_DMA_CHAN);\n    TEST_ESP_OK(ret);\n}\n\nstatic void setup_chip(spi_device_handle_t *spi, uint8_t flags)\n{\n    setup_bus(HOST_ID);\n\n    spi_device_interface_config_t devcfg = {\n        .clock_speed_hz = 40 * 1000 * 1000,\n        .mode = 0,\n        .spics_io_num = PIN_CS,\n        .queue_size = 10,\n        .flags = flags,\n    };\n\n    TEST_ESP_OK(spi_bus_add_device(HOST_ID, &devcfg, spi));\n}\n\nstatic void setup_nand_flash(spi_nand_flash_device_t **out_handle, spi_device_handle_t *spi_handle, spi_nand_flash_io_mode_t mode, uint8_t flags)\n{\n    spi_device_handle_t spi;\n    setup_chip(&spi, flags);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = flags,\n        .io_mode = mode,\n    };\n    spi_nand_flash_device_t *device_handle;\n    TEST_ESP_OK(spi_nand_flash_init_device(&nand_flash_config, &device_handle));\n\n    *out_handle = device_handle;\n    *spi_handle = spi;\n}\n\nstatic void deinit_nand_flash(spi_nand_flash_device_t *flash, spi_device_handle_t spi)\n{\n    spi_nand_flash_deinit_device(flash);\n    spi_bus_remove_device(spi);\n    spi_bus_free(HOST_ID);\n}\n\nTEST_CASE(\"erase nand flash\", \"[spi_nand_flash]\")\n{\n    spi_nand_flash_device_t *nand_flash_device_handle;\n    spi_device_handle_t spi;\n    setup_nand_flash(&nand_flash_device_handle, &spi, SPI_NAND_IO_MODE_SIO, SPI_DEVICE_HALFDUPLEX);\n    TEST_ESP_OK(spi_nand_erase_chip(nand_flash_device_handle));\n    do_single_write_test(nand_flash_device_handle, 1, 1);\n    deinit_nand_flash(nand_flash_device_handle, spi);\n}\n\nstatic void do_single_write_test(spi_nand_flash_device_t *flash, uint32_t start_page, uint16_t page_count)\n{\n    uint8_t *temp_buf = NULL;\n    uint8_t *pattern_buf = NULL;\n    uint32_t page_size, num_pages;\n\n    TEST_ESP_OK(spi_nand_flash_get_page_count(flash, &num_pages));\n    TEST_ESP_OK(spi_nand_flash_get_page_size(flash, &page_size));\n\n    TEST_ESP_OK((start_page + page_count) > num_pages);\n\n    pattern_buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DEFAULT);\n    TEST_ASSERT_NOT_NULL(pattern_buf);\n    temp_buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DEFAULT);\n    TEST_ASSERT_NOT_NULL(temp_buf);\n\n    spi_nand_flash_fill_buffer(pattern_buf, page_size / sizeof(uint32_t));\n\n    int64_t read_time = 0;\n    int64_t write_time = 0;\n\n    for (uint32_t i = start_page; i < (start_page + page_count); i++) {\n        int64_t start = esp_timer_get_time();\n        TEST_ESP_OK(spi_nand_flash_write_page(flash, pattern_buf, i));\n        write_time += esp_timer_get_time() - start;\n\n        memset((void *)temp_buf, 0x00, page_size);\n\n        start = esp_timer_get_time();\n        TEST_ESP_OK(spi_nand_flash_read_page(flash, temp_buf, i));\n        read_time += esp_timer_get_time() - start;\n\n        TEST_ASSERT_EQUAL(0, spi_nand_flash_check_buffer(temp_buf, page_size / sizeof(uint32_t)));\n    }\n    free(pattern_buf);\n    free(temp_buf);\n\n    printf(\"Wrote %\" PRIu32 \" bytes in %\" PRId64 \" us, avg %.2f kB/s\\n\", page_size * page_count, write_time, (float)page_size * page_count / write_time * 1000);\n    printf(\"Read %\" PRIu32 \" bytes in %\" PRId64 \" us, avg %.2f kB/s\\n\", page_size * page_count, read_time, (float)page_size * page_count / read_time * 1000);\n}\n\nstatic void test_write_nand_flash_pages(spi_nand_flash_io_mode_t mode, uint8_t flags)\n{\n    uint32_t num_pages, page_size;\n    spi_nand_flash_device_t *nand_flash_device_handle;\n    spi_device_handle_t spi;\n    setup_nand_flash(&nand_flash_device_handle, &spi, mode, flags);\n\n    TEST_ESP_OK(spi_nand_flash_get_page_count(nand_flash_device_handle, &num_pages));\n    TEST_ESP_OK(spi_nand_flash_get_page_size(nand_flash_device_handle, &page_size));\n    printf(\"Number of pages: %\" PRIu32 \", Page size: %\" PRIu32 \"\\n\", num_pages, page_size);\n\n    do_single_write_test(nand_flash_device_handle, 1, 16);\n    do_single_write_test(nand_flash_device_handle, 16, 32);\n    do_single_write_test(nand_flash_device_handle, 32, 64);\n    do_single_write_test(nand_flash_device_handle, 64, 128);\n    do_single_write_test(nand_flash_device_handle, num_pages / 2, 32);\n    do_single_write_test(nand_flash_device_handle, num_pages / 2, 256);\n    do_single_write_test(nand_flash_device_handle, num_pages - 20, 16);\n\n    deinit_nand_flash(nand_flash_device_handle, spi);\n}\n\nTEST_CASE(\"read and write nand flash pages (sio half-duplex)\", \"[spi_nand_flash]\")\n{\n    test_write_nand_flash_pages(SPI_NAND_IO_MODE_SIO, SPI_DEVICE_HALFDUPLEX);\n}\n\nTEST_CASE(\"read and write nand flash pages (sio full-duplex)\", \"[spi_nand_flash]\")\n{\n    test_write_nand_flash_pages(SPI_NAND_IO_MODE_SIO, 0); //set flags 0 for full-duplex mode\n}\n\nTEST_CASE(\"read and write nand flash pages (dio)\", \"[spi_nand_flash]\")\n{\n    test_write_nand_flash_pages(SPI_NAND_IO_MODE_DIO, SPI_DEVICE_HALFDUPLEX);\n}\n\nTEST_CASE(\"read and write nand flash pages (dout)\", \"[spi_nand_flash]\")\n{\n    test_write_nand_flash_pages(SPI_NAND_IO_MODE_DOUT, SPI_DEVICE_HALFDUPLEX);\n}\n\nTEST_CASE(\"read and write nand flash pages (qio)\", \"[spi_nand_flash]\")\n{\n    test_write_nand_flash_pages(SPI_NAND_IO_MODE_QIO, SPI_DEVICE_HALFDUPLEX);\n}\n\nTEST_CASE(\"read and write nand flash pages (qout)\", \"[spi_nand_flash]\")\n{\n    test_write_nand_flash_pages(SPI_NAND_IO_MODE_QOUT, SPI_DEVICE_HALFDUPLEX);\n}\n\nstatic void test_copy_nand_flash_pages(spi_nand_flash_io_mode_t mode, uint8_t flags)\n{\n    spi_nand_flash_device_t *nand_flash_device_handle;\n    spi_device_handle_t spi;\n    setup_nand_flash(&nand_flash_device_handle, &spi, mode, flags);\n    uint32_t num_pages, page_size;\n    uint32_t src_page = 10;\n    uint32_t dst_page = 11;\n\n    TEST_ESP_OK(spi_nand_flash_get_page_count(nand_flash_device_handle, &num_pages));\n    TEST_ESP_OK(spi_nand_flash_get_page_size(nand_flash_device_handle, &page_size));\n    printf(\"Number of pages: %\" PRIu32 \", Page size: %\" PRIu32 \"\\n\", num_pages, page_size);\n\n    if (src_page < num_pages && dst_page < num_pages) {\n        do_single_write_test(nand_flash_device_handle, src_page, 1);\n        TEST_ESP_OK(spi_nand_flash_copy_page(nand_flash_device_handle, src_page, dst_page));\n    }\n    deinit_nand_flash(nand_flash_device_handle, spi);\n}\n\nTEST_CASE(\"copy nand flash pages (sio half-duplex)\", \"[spi_nand_flash]\")\n{\n    test_copy_nand_flash_pages(SPI_NAND_IO_MODE_SIO, SPI_DEVICE_HALFDUPLEX);\n}\n\nTEST_CASE(\"copy nand flash pages (sio full-duplex)\", \"[spi_nand_flash]\")\n{\n    test_copy_nand_flash_pages(SPI_NAND_IO_MODE_SIO, 0);\n}\n\nTEST_CASE(\"copy nand flash pages (dio)\", \"[spi_nand_flash]\")\n{\n    test_copy_nand_flash_pages(SPI_NAND_IO_MODE_DIO, SPI_DEVICE_HALFDUPLEX);\n}\n\nTEST_CASE(\"copy nand flash pages (dout)\", \"[spi_nand_flash]\")\n{\n    test_copy_nand_flash_pages(SPI_NAND_IO_MODE_DOUT, SPI_DEVICE_HALFDUPLEX);\n}\n\nTEST_CASE(\"copy nand flash pages (qio)\", \"[spi_nand_flash]\")\n{\n    test_copy_nand_flash_pages(SPI_NAND_IO_MODE_QIO, SPI_DEVICE_HALFDUPLEX);\n}\n\nTEST_CASE(\"copy nand flash pages (qout)\", \"[spi_nand_flash]\")\n{\n    test_copy_nand_flash_pages(SPI_NAND_IO_MODE_QOUT, SPI_DEVICE_HALFDUPLEX);\n}\n\nstatic void test_nand_operations(spi_nand_flash_io_mode_t mode, uint8_t flags)\n{\n    spi_nand_flash_device_t *nand_flash_device_handle;\n    spi_device_handle_t spi;\n    uint32_t num_pages, page_size, block_size;\n\n    setup_nand_flash(&nand_flash_device_handle, &spi, mode, flags);\n\n    TEST_ESP_OK(spi_nand_flash_get_page_count(nand_flash_device_handle, &num_pages));\n    TEST_ESP_OK(spi_nand_flash_get_page_size(nand_flash_device_handle, &page_size));\n    TEST_ESP_OK(spi_nand_flash_get_block_size(nand_flash_device_handle, &block_size));\n    printf(\"Number of pages: %\" PRIu32 \", Page size: %\" PRIu32 \"\\n\", num_pages, page_size);\n\n    uint8_t *pattern_buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DMA);\n    TEST_ASSERT_NOT_NULL(pattern_buf);\n    uint8_t *temp_buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DMA);\n    TEST_ASSERT_NOT_NULL(temp_buf);\n\n    spi_nand_flash_fill_buffer(pattern_buf, page_size / sizeof(uint32_t));\n\n    bool is_page_free = true;\n    uint32_t src_block = 20;\n    uint32_t dst_block = 21;\n    uint32_t test_page = src_block * (block_size / page_size); // pages_per_block\n    uint32_t dst_page = dst_block * (block_size / page_size);\n    TEST_ESP_OK(nand_wrap_erase_block(nand_flash_device_handle, src_block));\n    TEST_ESP_OK(nand_wrap_erase_block(nand_flash_device_handle, dst_block));\n    TEST_ASSERT_TRUE(test_page < num_pages);\n\n    // Verify if test_page is free\n    TEST_ESP_OK(nand_wrap_is_free(nand_flash_device_handle, test_page, &is_page_free));\n    TEST_ASSERT_TRUE(is_page_free == true);\n    // Write/program test_page\n    TEST_ESP_OK(nand_wrap_prog(nand_flash_device_handle, test_page, pattern_buf));\n    // Verify if test_page is used/programmed\n    TEST_ESP_OK(nand_wrap_is_free(nand_flash_device_handle, test_page, &is_page_free));\n    TEST_ASSERT_TRUE(is_page_free == false);\n    // read test_page and verify with pattern_buf\n    TEST_ESP_OK(nand_wrap_read(nand_flash_device_handle, test_page, 0, page_size, temp_buf));\n    TEST_ASSERT_EQUAL(0, spi_nand_flash_check_buffer(temp_buf, page_size / sizeof(uint32_t)));\n    // Copy test_page to dst_page\n    TEST_ESP_OK(nand_wrap_copy(nand_flash_device_handle, test_page, dst_page));\n    // read dst_page and verify with pattern_buf\n    TEST_ESP_OK(nand_wrap_read(nand_flash_device_handle, dst_page, 0, page_size, temp_buf));\n    TEST_ASSERT_EQUAL(0, spi_nand_flash_check_buffer(temp_buf, page_size / sizeof(uint32_t)));\n\n    free(pattern_buf);\n    free(temp_buf);\n    deinit_nand_flash(nand_flash_device_handle, spi);\n}\n\nTEST_CASE(\"verify nand_prog, nand_read, nand_copy, nand_is_free works (bypassing dhara) (sio half-duplex)\", \"[spi_nand_flash]\")\n{\n    test_nand_operations(SPI_NAND_IO_MODE_SIO, SPI_DEVICE_HALFDUPLEX);\n}\n\nTEST_CASE(\"verify nand_prog, nand_read, nand_copy, nand_is_free works (bypassing dhara) (sio full-duplex)\", \"[spi_nand_flash]\")\n{\n    test_nand_operations(SPI_NAND_IO_MODE_SIO, 0);\n}\n\nTEST_CASE(\"verify nand_prog, nand_read, nand_copy, nand_is_free works (bypassing dhara) (dio)\", \"[spi_nand_flash]\")\n{\n    test_nand_operations(SPI_NAND_IO_MODE_DIO, SPI_DEVICE_HALFDUPLEX);\n}\n\nTEST_CASE(\"verify nand_prog, nand_read, nand_copy, nand_is_free works (bypassing dhara) (dout)\", \"[spi_nand_flash]\")\n{\n    test_nand_operations(SPI_NAND_IO_MODE_DOUT, SPI_DEVICE_HALFDUPLEX);\n}\n\nTEST_CASE(\"verify nand_prog, nand_read, nand_copy, nand_is_free works (bypassing dhara) (qio)\", \"[spi_nand_flash]\")\n{\n    test_nand_operations(SPI_NAND_IO_MODE_QIO, SPI_DEVICE_HALFDUPLEX);\n}\n\nTEST_CASE(\"verify nand_prog, nand_read, nand_copy, nand_is_free works (bypassing dhara) (qout)\", \"[spi_nand_flash]\")\n{\n    test_nand_operations(SPI_NAND_IO_MODE_QOUT, SPI_DEVICE_HALFDUPLEX);\n}\n\nTEST_CASE(\"Fail safe test if chip is not detected\", \"[spi_nand_flash]\")\n{\n    spi_device_handle_t spi;\n    spi_bus_config_t spi_bus_cfg = {\n        .mosi_io_num = PIN_MOSI,\n        .miso_io_num = PIN_MISO,\n        .sclk_io_num = PIN_MISO,        // Initialize with wrong pin\n        .max_transfer_sz = 64,\n    };\n    esp_err_t ret = spi_bus_initialize(HOST_ID, &spi_bus_cfg, SPI_DMA_CHAN);\n    TEST_ESP_OK(ret);\n\n    spi_device_interface_config_t devcfg = {\n        .clock_speed_hz = 40 * 1000 * 1000,\n        .mode = 0,\n        .spics_io_num = PIN_CS,\n        .queue_size = 10,\n        .flags = SPI_DEVICE_HALFDUPLEX,\n    };\n    TEST_ESP_OK(spi_bus_add_device(HOST_ID, &devcfg, &spi));\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n    };\n    spi_nand_flash_device_t *device_handle;\n    esp_err_t err = spi_nand_flash_init_device(&nand_flash_config, &device_handle);\n    TEST_ASSERT_TRUE(err != ESP_OK);\n\n    spi_bus_remove_device(spi);\n    spi_bus_free(HOST_ID);\n}\n"
  },
  {
    "path": "spi_nand_flash/test_app/main/test_spi_nand_flash_bdl.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/param.h>\n#include <inttypes.h>\n#include \"esp_attr.h\"\n#include \"esp_intr_alloc.h\"\n#include \"esp_log.h\"\n#include \"esp_timer.h\"\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"freertos/semphr.h\"\n#include \"driver/spi_master.h\"\n#include \"spi_nand_flash.h\"\n#include \"nand_private/nand_impl_wrap.h\"\n#include \"unity.h\"\n#include \"soc/spi_pins.h\"\n#include \"sdkconfig.h\"\n#include \"esp_blockdev.h\"\n#include \"esp_nand_blockdev.h\"\n#include \"spi_nand_flash_test_helpers.h\"\n\n\n// Pin mapping\n// ESP32 (VSPI)\n#ifdef CONFIG_IDF_TARGET_ESP32\n#define HOST_ID     SPI3_HOST\n#define PIN_MOSI     SPI3_IOMUX_PIN_NUM_MOSI\n#define PIN_MISO     SPI3_IOMUX_PIN_NUM_MISO\n#define PIN_CLK      SPI3_IOMUX_PIN_NUM_CLK\n#define PIN_CS       SPI3_IOMUX_PIN_NUM_CS\n#define PIN_WP       SPI3_IOMUX_PIN_NUM_WP\n#define PIN_HD       SPI3_IOMUX_PIN_NUM_HD\n#define SPI_DMA_CHAN SPI_DMA_CH_AUTO\n#else // Other chips (SPI2/HSPI)\n#define HOST_ID      SPI2_HOST\n#define PIN_MOSI     SPI2_IOMUX_PIN_NUM_MOSI\n#define PIN_MISO     SPI2_IOMUX_PIN_NUM_MISO\n#define PIN_CLK      SPI2_IOMUX_PIN_NUM_CLK\n#define PIN_CS       SPI2_IOMUX_PIN_NUM_CS\n#define PIN_WP       SPI2_IOMUX_PIN_NUM_WP\n#define PIN_HD       SPI2_IOMUX_PIN_NUM_HD\n#define SPI_DMA_CHAN SPI_DMA_CH_AUTO\n#endif\n\nstatic void do_single_write_test(esp_blockdev_handle_t bdl, uint32_t start_page, uint16_t page_count);\nstatic void setup_bus(spi_host_device_t host_id)\n{\n    spi_bus_config_t spi_bus_cfg = {\n        .mosi_io_num = PIN_MOSI,\n        .miso_io_num = PIN_MISO,\n        .sclk_io_num = PIN_CLK,\n        .quadhd_io_num = PIN_HD,\n        .quadwp_io_num = PIN_WP,\n        .max_transfer_sz = 64,\n    };\n    esp_err_t ret = spi_bus_initialize(host_id, &spi_bus_cfg, SPI_DMA_CHAN);\n    TEST_ESP_OK(ret);\n}\n\nstatic void setup_chip(spi_device_handle_t *spi, uint8_t flags)\n{\n    setup_bus(HOST_ID);\n\n    spi_device_interface_config_t devcfg = {\n        .clock_speed_hz = 40 * 1000 * 1000,\n        .mode = 0,\n        .spics_io_num = PIN_CS,\n        .queue_size = 10,\n        .flags = flags,\n    };\n\n    TEST_ESP_OK(spi_bus_add_device(HOST_ID, &devcfg, spi));\n}\n\nstatic void setup_nand_flash(spi_device_handle_t *spi_handle, spi_nand_flash_io_mode_t mode, uint8_t flags, esp_blockdev_handle_t *bdl_handle)\n{\n    spi_device_handle_t spi;\n    setup_chip(&spi, flags);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = flags,\n        .io_mode = mode,\n    };\n    esp_blockdev_handle_t wl_bdl;\n    TEST_ESP_OK(spi_nand_flash_init_with_layers(&nand_flash_config, &wl_bdl));\n\n    *spi_handle = spi;\n    *bdl_handle = wl_bdl;\n}\n\nstatic void deinit_nand_flash(spi_device_handle_t spi, esp_blockdev_handle_t bdl_handle)\n{\n    bdl_handle->ops->release(bdl_handle);\n    spi_bus_remove_device(spi);\n    spi_bus_free(HOST_ID);\n}\n\nTEST_CASE(\"erase nand flash using block device interface [via dhara]\", \"[spi_nand_flash]\")\n{\n    spi_device_handle_t spi;\n    esp_blockdev_handle_t bdl_handle;\n    setup_nand_flash(&spi, SPI_NAND_IO_MODE_SIO, SPI_DEVICE_HALFDUPLEX, &bdl_handle);\n\n    /* Erase length must be aligned to erase_size (block size) */\n    size_t erase_size = (size_t)bdl_handle->geometry.erase_size;\n    size_t erase_len = (size_t)((bdl_handle->geometry.disk_size / erase_size) * erase_size);\n    TEST_ESP_OK(bdl_handle->ops->erase(bdl_handle, 0, erase_len));\n\n    do_single_write_test(bdl_handle, 1, 1);\n    deinit_nand_flash(spi, bdl_handle);\n}\n\nstatic void do_single_write_test(esp_blockdev_handle_t bdl, uint32_t start_page, uint16_t page_count)\n{\n    uint8_t *temp_buf = NULL;\n    uint8_t *pattern_buf = NULL;\n    uint32_t page_size = bdl->geometry.write_size;\n    TEST_ASSERT_TRUE(page_size > 0);\n    uint32_t num_pages = (uint32_t)(bdl->geometry.disk_size / page_size);\n\n    TEST_ASSERT_TRUE((start_page + page_count) <= num_pages);\n\n    pattern_buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DEFAULT);\n    TEST_ASSERT_NOT_NULL(pattern_buf);\n    temp_buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DEFAULT);\n    TEST_ASSERT_NOT_NULL(temp_buf);\n\n    spi_nand_flash_fill_buffer(pattern_buf, page_size / sizeof(uint32_t));\n\n    int64_t read_time = 0;\n    int64_t write_time = 0;\n\n    for (uint32_t i = start_page; i < (start_page + page_count); i++) {\n        int64_t start = esp_timer_get_time();\n        bdl->ops->write(bdl, pattern_buf, i * page_size, page_size);\n        write_time += esp_timer_get_time() - start;\n\n        memset((void *)temp_buf, 0x00, page_size);\n\n        start = esp_timer_get_time();\n        bdl->ops->read(bdl, temp_buf, page_size, i * page_size, page_size);\n        read_time += esp_timer_get_time() - start;\n\n        TEST_ASSERT_EQUAL(0, spi_nand_flash_check_buffer(temp_buf, page_size / sizeof(uint32_t)));\n    }\n    free(pattern_buf);\n    free(temp_buf);\n\n    printf(\"Wrote %\" PRIu32 \" bytes in %\" PRId64 \" us, avg %.2f kB/s\\n\", page_size * page_count, write_time, (float)page_size * page_count / write_time * 1000);\n    printf(\"Read %\" PRIu32 \" bytes in %\" PRId64 \" us, avg %.2f kB/s\\n\", page_size * page_count, read_time, (float)page_size * page_count / read_time * 1000);\n}\n\n/* Returns 0 on success, non-zero on failure. Frees buffers so caller can always run cleanup. */\nstatic int do_multiple_page_write_test(esp_blockdev_handle_t bdl, uint32_t start_page, uint16_t page_count)\n{\n    uint8_t *temp_buf = NULL;\n    uint8_t *pattern_buf = NULL;\n    uint32_t page_size = bdl->geometry.write_size;\n    uint32_t num_pages = bdl->geometry.disk_size / page_size;\n    int ret = -1;\n\n    if ((start_page + page_count) > num_pages) {\n        return -1;\n    }\n\n    pattern_buf = (uint8_t *)heap_caps_malloc(page_size * page_count, MALLOC_CAP_DEFAULT);\n    if (pattern_buf == NULL) {\n        return -1;\n    }\n    temp_buf = (uint8_t *)heap_caps_malloc(page_size * page_count, MALLOC_CAP_DEFAULT);\n    if (temp_buf == NULL) {\n        free(pattern_buf);\n        return -1;\n    }\n\n    spi_nand_flash_fill_buffer(pattern_buf, page_size * page_count / sizeof(uint32_t));\n\n    int64_t read_time = 0;\n    int64_t write_time = 0;\n\n    int64_t start = esp_timer_get_time();\n    if (bdl->ops->write(bdl, pattern_buf, start_page * page_size, page_count * page_size) != ESP_OK) {\n        free(pattern_buf);\n        free(temp_buf);\n        return -1;\n    }\n    write_time += esp_timer_get_time() - start;\n\n    memset((void *)temp_buf, 0x00, page_count * page_size);\n\n    start = esp_timer_get_time();\n    if (bdl->ops->read(bdl, temp_buf, page_count * page_size, start_page * page_size, page_count * page_size) != ESP_OK) {\n        free(pattern_buf);\n        free(temp_buf);\n        return -1;\n    }\n    read_time += esp_timer_get_time() - start;\n\n    ret = spi_nand_flash_check_buffer(temp_buf, page_size * page_count / sizeof(uint32_t));\n    free(pattern_buf);\n    free(temp_buf);\n\n    printf(\"Wrote %\" PRIu32 \" bytes in %\" PRId64 \" us, avg %.2f kB/s\\n\", page_size * page_count, write_time, (float)page_size * page_count / write_time * 1000);\n    printf(\"Read %\" PRIu32 \" bytes in %\" PRId64 \" us, avg %.2f kB/s\\n\", page_size * page_count, read_time, (float)page_size * page_count / read_time * 1000);\n    return ret;\n}\n\nstatic void test_write_nand_flash_pages(spi_nand_flash_io_mode_t mode, uint8_t flags)\n{\n    spi_device_handle_t spi;\n    esp_blockdev_handle_t bdl_handle;\n    setup_nand_flash(&spi, mode, flags, &bdl_handle);\n\n    uint32_t page_size = bdl_handle->geometry.write_size;\n    TEST_ASSERT_TRUE(page_size > 0);\n    uint32_t num_pages = (uint32_t)(bdl_handle->geometry.disk_size / page_size);\n    printf(\"Number of pages: %\" PRIu32 \", Page size: %\" PRIu32 \"\\n\", num_pages, page_size);\n\n    int ret = do_multiple_page_write_test(bdl_handle, 1, 2);\n    do_single_write_test(bdl_handle, 16, 32);\n    deinit_nand_flash(spi, bdl_handle);\n    TEST_ASSERT_EQUAL(0, ret);\n}\n\nTEST_CASE(\"read and write nand flash pages using block device interface (via dhara) (sio half-duplex)\", \"[spi_nand_flash]\")\n{\n    test_write_nand_flash_pages(SPI_NAND_IO_MODE_SIO, SPI_DEVICE_HALFDUPLEX);\n}\n\n/**\n * For raw Flash BDL: query IS_BAD_BLOCK, then erase only if the block is good.\n * @return true if erase was issued, false if block was bad (erase skipped).\n */\nstatic bool flash_bdl_erase_block_if_good(esp_blockdev_handle_t bdl, uint32_t block)\n{\n    esp_blockdev_cmd_arg_is_bad_block_t arg = {.num = block, .status = false};\n    TEST_ESP_OK(bdl->ops->ioctl(bdl, ESP_BLOCKDEV_CMD_IS_BAD_BLOCK, &arg));\n    if (arg.status) {\n        return false;\n    }\n    uint32_t block_size = (uint32_t)bdl->geometry.erase_size;\n    TEST_ESP_OK(bdl->ops->erase(bdl, (uint64_t)block * block_size, (size_t)block_size));\n    return true;\n}\n\nstatic void test_nand_operations(spi_nand_flash_io_mode_t mode, uint8_t flags)\n{\n\n    spi_device_handle_t spi;\n    setup_chip(&spi, flags);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = flags,\n        .io_mode = mode,\n    };\n    esp_blockdev_handle_t bdl_handle;\n    TEST_ESP_OK(nand_flash_get_blockdev(&nand_flash_config, &bdl_handle));\n\n    uint32_t page_size = bdl_handle->geometry.write_size;\n    uint32_t block_size = bdl_handle->geometry.erase_size;\n    uint32_t num_pages = bdl_handle->geometry.disk_size / bdl_handle->geometry.read_size;\n\n    printf(\"Number of pages: %\" PRIu32 \", Page size: %\" PRIu32 \"\\n\", num_pages, page_size);\n\n    uint32_t num_blocks = (uint32_t)(bdl_handle->geometry.disk_size / block_size);\n    uint32_t src_block = 20;\n    if (src_block >= num_blocks) {\n        src_block = 0;\n    }\n    if (!flash_bdl_erase_block_if_good(bdl_handle, src_block)) {\n        src_block = UINT32_MAX;\n        for (uint32_t b = 0; b < num_blocks; b++) {\n            if (flash_bdl_erase_block_if_good(bdl_handle, b)) {\n                src_block = b;\n                break;\n            }\n        }\n        TEST_ASSERT_NOT_EQUAL(UINT32_MAX, src_block);\n    }\n    uint32_t test_page = src_block * (block_size / page_size); // pages_per_block\n    uint32_t page_count = 2;\n    TEST_ASSERT_TRUE(test_page < num_pages);\n\n    // Verify if test_page is free\n    for (uint32_t page = test_page; page < (test_page + page_count); page++) {\n        esp_blockdev_cmd_arg_is_free_page_t page_free_status = {page, false};\n        TEST_ESP_OK(bdl_handle->ops->ioctl(bdl_handle, ESP_BLOCKDEV_CMD_IS_FREE_PAGE, &page_free_status));\n        TEST_ASSERT_TRUE(page_free_status.status == true);\n    }\n\n    TEST_ASSERT_EQUAL(0, do_multiple_page_write_test(bdl_handle, test_page, page_count));\n\n    // Verify if test_page is free\n    for (uint32_t page = test_page; page < (test_page + page_count); page++) {\n        esp_blockdev_cmd_arg_is_free_page_t page_free_status = {page, true};\n        TEST_ESP_OK(bdl_handle->ops->ioctl(bdl_handle, ESP_BLOCKDEV_CMD_IS_FREE_PAGE, &page_free_status));\n        TEST_ASSERT_TRUE(page_free_status.status == false);\n    }\n\n    deinit_nand_flash(spi, bdl_handle);\n}\n\nTEST_CASE(\"verify nand_prog, nand_read, nand_is_free works (bypassing dhara) using block device interface (sio half-duplex)\", \"[spi_nand_flash]\")\n{\n    test_nand_operations(SPI_NAND_IO_MODE_SIO, SPI_DEVICE_HALFDUPLEX);\n}\n\n\nTEST_CASE(\"verify ioctl (bad blocks and ecc stats) works with bdl interface\", \"[spi_nand_flash]\")\n{\n    spi_nand_flash_io_mode_t mode = SPI_NAND_IO_MODE_SIO;\n    uint8_t flags = SPI_DEVICE_HALFDUPLEX;\n\n    spi_device_handle_t spi;\n    setup_chip(&spi, flags);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = flags,\n        .io_mode = mode,\n    };\n    esp_blockdev_handle_t nand_bdl = NULL;\n    TEST_ESP_OK(nand_flash_get_blockdev(&nand_flash_config, &nand_bdl));\n    TEST_ASSERT_TRUE(nand_bdl != NULL);\n\n    uint32_t bad_block_count = 0xFFFF;\n    TEST_ESP_OK(nand_bdl->ops->ioctl(nand_bdl, ESP_BLOCKDEV_CMD_GET_BAD_BLOCKS_COUNT, &bad_block_count));\n    TEST_ASSERT_TRUE(bad_block_count != 0xFFFF);\n\n    esp_blockdev_cmd_arg_ecc_stats_t ecc_stats;\n    memset(&ecc_stats, 0xFF, sizeof(ecc_stats));\n    TEST_ESP_OK(nand_bdl->ops->ioctl(nand_bdl, ESP_BLOCKDEV_CMD_GET_ECC_STATS, &ecc_stats));\n    TEST_ASSERT_TRUE(ecc_stats.ecc_threshold != 0xFF);\n\n\n    deinit_nand_flash(spi, nand_bdl);\n}\n\nTEST_CASE(\"Flash BDL geometry and device_flags after nand_flash_get_blockdev\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    setup_chip(&spi, SPI_DEVICE_HALFDUPLEX);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = SPI_DEVICE_HALFDUPLEX,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n    };\n    esp_blockdev_handle_t bdl = NULL;\n    TEST_ESP_OK(nand_flash_get_blockdev(&nand_flash_config, &bdl));\n    TEST_ASSERT_NOT_NULL(bdl);\n\n    uint32_t block_size = bdl->geometry.erase_size;\n    uint32_t num_blocks = (uint32_t)(bdl->geometry.disk_size / block_size);\n    TEST_ASSERT_EQUAL_UINT32(num_blocks * block_size, (uint32_t)bdl->geometry.disk_size);\n\n    TEST_ASSERT_EQUAL(bdl->geometry.read_size, bdl->geometry.write_size);\n    TEST_ASSERT_TRUE(bdl->geometry.read_size > 0);\n    TEST_ASSERT_TRUE(bdl->geometry.erase_size > 0);\n\n    TEST_ASSERT_TRUE(bdl->device_flags.erase_before_write);\n    TEST_ASSERT_TRUE(bdl->device_flags.and_type_write);\n    TEST_ASSERT_TRUE(bdl->device_flags.default_val_after_erase);\n\n    TEST_ASSERT_NOT_NULL(bdl->ops);\n    TEST_ASSERT_NOT_NULL(bdl->ops->read);\n    TEST_ASSERT_NOT_NULL(bdl->ops->write);\n    TEST_ASSERT_NOT_NULL(bdl->ops->erase);\n    TEST_ASSERT_NOT_NULL(bdl->ops->ioctl);\n    TEST_ASSERT_NOT_NULL(bdl->ops->release);\n\n    deinit_nand_flash(spi, bdl);\n}\n\nTEST_CASE(\"Flash BDL multi-block erase honours erase_len\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    setup_chip(&spi, SPI_DEVICE_HALFDUPLEX);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = SPI_DEVICE_HALFDUPLEX,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n    };\n    esp_blockdev_handle_t bdl = NULL;\n    TEST_ESP_OK(nand_flash_get_blockdev(&nand_flash_config, &bdl));\n    TEST_ASSERT_NOT_NULL(bdl);\n\n    uint32_t block_size = bdl->geometry.erase_size;\n    uint32_t page_size = bdl->geometry.write_size;\n    const uint32_t num_blocks_to_erase = 3;\n    const uint32_t start_block = 30;\n    uint64_t start_addr = (uint64_t)start_block * block_size;\n    bool erased[3];\n    TEST_ASSERT_EQUAL(3u, num_blocks_to_erase);\n    for (uint32_t i = 0; i < num_blocks_to_erase; i++) {\n        erased[i] = flash_bdl_erase_block_if_good(bdl, start_block + i);\n    }\n\n    uint8_t *read_buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DEFAULT);\n    TEST_ASSERT_NOT_NULL(read_buf);\n    for (uint32_t blk = 0; blk < num_blocks_to_erase; blk++) {\n        if (!erased[blk]) {\n            continue;\n        }\n        uint32_t pages_per_block = block_size / page_size;\n        for (uint32_t p = 0; p < pages_per_block; p++) {\n            uint64_t addr = start_addr + (uint64_t)(blk * block_size + p * page_size);\n            TEST_ESP_OK(bdl->ops->read(bdl, read_buf, page_size, addr, page_size));\n            for (size_t i = 0; i < page_size; i++) {\n                TEST_ASSERT_EQUAL_HEX8(0xFF, read_buf[i]);\n            }\n        }\n    }\n    free(read_buf);\n    deinit_nand_flash(spi, bdl);\n}\n\nTEST_CASE(\"Flash BDL GET_NAND_FLASH_INFO ioctl\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    setup_chip(&spi, SPI_DEVICE_HALFDUPLEX);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = SPI_DEVICE_HALFDUPLEX,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n    };\n    esp_blockdev_handle_t bdl = NULL;\n    TEST_ESP_OK(nand_flash_get_blockdev(&nand_flash_config, &bdl));\n    TEST_ASSERT_NOT_NULL(bdl);\n\n    esp_blockdev_cmd_arg_nand_flash_info_t flash_info;\n    memset(&flash_info, 0, sizeof(flash_info));\n    TEST_ESP_OK(bdl->ops->ioctl(bdl, ESP_BLOCKDEV_CMD_GET_NAND_FLASH_INFO, &flash_info));\n\n    TEST_ASSERT_TRUE(flash_info.device_info.manufacturer_id != 0 || flash_info.device_info.device_id != 0);\n    TEST_ASSERT_TRUE(strnlen((char *)flash_info.device_info.chip_name, sizeof(flash_info.device_info.chip_name)) > 0);\n    TEST_ASSERT_EQUAL(bdl->geometry.read_size, flash_info.geometry.page_size);\n    TEST_ASSERT_EQUAL(bdl->geometry.erase_size, flash_info.geometry.block_size);\n    TEST_ASSERT_EQUAL((uint32_t)(bdl->geometry.disk_size / bdl->geometry.erase_size), flash_info.geometry.num_blocks);\n\n    deinit_nand_flash(spi, bdl);\n}\n\nTEST_CASE(\"nand_flash_get_blockdev and spi_nand_flash_wl_get_blockdev error paths\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    setup_chip(&spi, SPI_DEVICE_HALFDUPLEX);\n    spi_nand_flash_config_t config = {\n        .device_handle = spi,\n        .flags = SPI_DEVICE_HALFDUPLEX,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n    };\n    esp_blockdev_handle_t out = NULL;\n\n    TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, nand_flash_get_blockdev(NULL, &out));\n    TEST_ASSERT_NULL(out);\n    TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, nand_flash_get_blockdev(&config, NULL));\n\n    esp_blockdev_handle_t flash_bdl = NULL;\n    TEST_ESP_OK(nand_flash_get_blockdev(&config, &flash_bdl));\n    TEST_ASSERT_NOT_NULL(flash_bdl);\n\n    out = NULL;\n    TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spi_nand_flash_wl_get_blockdev(NULL, &out));\n    TEST_ASSERT_NULL(out);\n    TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spi_nand_flash_wl_get_blockdev(flash_bdl, NULL));\n\n    deinit_nand_flash(spi, flash_bdl);\n}\n\nTEST_CASE(\"Flash BDL erase invalid args\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    setup_chip(&spi, SPI_DEVICE_HALFDUPLEX);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = SPI_DEVICE_HALFDUPLEX,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n    };\n    esp_blockdev_handle_t bdl = NULL;\n    TEST_ESP_OK(nand_flash_get_blockdev(&nand_flash_config, &bdl));\n    TEST_ASSERT_NOT_NULL(bdl);\n\n    uint32_t block_size = bdl->geometry.erase_size;\n    esp_err_t ret = bdl->ops->erase(bdl, block_size / 2, block_size);\n    TEST_ASSERT_TRUE(ret == ESP_ERR_INVALID_ARG || ret == ESP_ERR_INVALID_SIZE);\n\n    ret = bdl->ops->erase(bdl, 0, block_size / 2);\n    TEST_ASSERT_TRUE(ret == ESP_ERR_INVALID_ARG || ret == ESP_ERR_INVALID_SIZE);\n\n    ret = bdl->ops->erase(bdl, 0, 0);\n    TEST_ASSERT_TRUE(ret == ESP_ERR_INVALID_ARG || ret == ESP_ERR_INVALID_SIZE);\n\n    deinit_nand_flash(spi, bdl);\n}\n\nTEST_CASE(\"Flash BDL unsupported ioctl returns ESP_ERR_NOT_SUPPORTED\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    setup_chip(&spi, SPI_DEVICE_HALFDUPLEX);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = SPI_DEVICE_HALFDUPLEX,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n    };\n    esp_blockdev_handle_t bdl = NULL;\n    TEST_ESP_OK(nand_flash_get_blockdev(&nand_flash_config, &bdl));\n    TEST_ASSERT_NOT_NULL(bdl);\n\n    uint32_t dummy = 0;\n    esp_err_t ret = bdl->ops->ioctl(bdl, (uint8_t)0xFF, &dummy);\n    TEST_ASSERT_EQUAL(ESP_ERR_NOT_SUPPORTED, ret);\n\n    deinit_nand_flash(spi, bdl);\n}\n\nTEST_CASE(\"Flash BDL COPY_PAGE ioctl\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    setup_chip(&spi, SPI_DEVICE_HALFDUPLEX);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = SPI_DEVICE_HALFDUPLEX,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n    };\n    esp_blockdev_handle_t bdl = NULL;\n    TEST_ESP_OK(nand_flash_get_blockdev(&nand_flash_config, &bdl));\n    TEST_ASSERT_NOT_NULL(bdl);\n\n    uint32_t page_size = bdl->geometry.write_size;\n    uint32_t block_size = bdl->geometry.erase_size;\n    uint32_t num_pages = (uint32_t)(bdl->geometry.disk_size / page_size);\n    uint32_t pages_per_block = block_size / page_size;\n\n    uint32_t src_block = 5;\n    uint32_t dst_block = 6;\n    uint32_t src_page = src_block * pages_per_block;\n    uint32_t dst_page = dst_block * pages_per_block;\n    TEST_ASSERT_TRUE(dst_page < num_pages);\n\n    TEST_ASSERT_TRUE(flash_bdl_erase_block_if_good(bdl, src_block));\n    TEST_ASSERT_TRUE(flash_bdl_erase_block_if_good(bdl, dst_block));\n\n    uint8_t *pattern_buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DEFAULT);\n    uint8_t *read_buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DEFAULT);\n    TEST_ASSERT_NOT_NULL(pattern_buf);\n    TEST_ASSERT_NOT_NULL(read_buf);\n\n    spi_nand_flash_fill_buffer(pattern_buf, page_size / sizeof(uint32_t));\n    TEST_ESP_OK(bdl->ops->write(bdl, pattern_buf, src_page * (uint64_t)page_size, page_size));\n\n    esp_blockdev_cmd_arg_copy_page_t copy_cmd = {\n        .src_page = src_page,\n        .dst_page = dst_page,\n    };\n    TEST_ESP_OK(bdl->ops->ioctl(bdl, ESP_BLOCKDEV_CMD_COPY_PAGE, &copy_cmd));\n\n    memset(read_buf, 0, page_size);\n    TEST_ESP_OK(bdl->ops->read(bdl, read_buf, page_size, dst_page * (uint64_t)page_size, page_size));\n    TEST_ASSERT_EQUAL(0, spi_nand_flash_check_buffer(read_buf, page_size / sizeof(uint32_t)));\n\n    free(pattern_buf);\n    free(read_buf);\n    deinit_nand_flash(spi, bdl);\n}\n\nTEST_CASE(\"Flash BDL GET_PAGE_ECC_STATUS ioctl\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    setup_chip(&spi, SPI_DEVICE_HALFDUPLEX);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = SPI_DEVICE_HALFDUPLEX,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n    };\n    esp_blockdev_handle_t bdl = NULL;\n    TEST_ESP_OK(nand_flash_get_blockdev(&nand_flash_config, &bdl));\n    TEST_ASSERT_NOT_NULL(bdl);\n\n    uint32_t page_size = bdl->geometry.write_size;\n    uint32_t block_size = bdl->geometry.erase_size;\n    uint32_t test_page = (bdl->geometry.disk_size / page_size) / 2;\n    uint32_t pages_per_block = block_size / page_size;\n    uint32_t ecc_block = test_page / pages_per_block;\n    TEST_ASSERT_TRUE(flash_bdl_erase_block_if_good(bdl, ecc_block));\n\n    uint8_t *pattern_buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DEFAULT);\n    TEST_ASSERT_NOT_NULL(pattern_buf);\n    spi_nand_flash_fill_buffer(pattern_buf, page_size / sizeof(uint32_t));\n    TEST_ESP_OK(bdl->ops->write(bdl, pattern_buf, test_page * (uint64_t)page_size, page_size));\n    free(pattern_buf);\n\n    esp_blockdev_cmd_arg_ecc_status_t page_ecc_status = {\n        .page_num = test_page,\n        .ecc_status = 0xFF,\n    };\n    TEST_ESP_OK(bdl->ops->ioctl(bdl, ESP_BLOCKDEV_CMD_GET_PAGE_ECC_STATUS, &page_ecc_status));\n\n    deinit_nand_flash(spi, bdl);\n}\n\nTEST_CASE(\"Flash BDL read invalid args\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    setup_chip(&spi, SPI_DEVICE_HALFDUPLEX);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = SPI_DEVICE_HALFDUPLEX,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n    };\n    esp_blockdev_handle_t bdl = NULL;\n    TEST_ESP_OK(nand_flash_get_blockdev(&nand_flash_config, &bdl));\n    TEST_ASSERT_NOT_NULL(bdl);\n\n    uint32_t page_size = bdl->geometry.read_size;\n    uint8_t *buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DEFAULT);\n    TEST_ASSERT_NOT_NULL(buf);\n\n    esp_err_t ret = bdl->ops->read(bdl, NULL, page_size, 0, page_size);\n    TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, ret);\n\n    ret = bdl->ops->read(bdl, buf, page_size - 1, 0, page_size);\n    TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, ret);\n\n    uint64_t oob_addr = bdl->geometry.disk_size;\n    if (oob_addr >= page_size) {\n        ret = bdl->ops->read(bdl, buf, page_size, oob_addr - page_size / 2, page_size);\n        TEST_ASSERT_TRUE(ret != ESP_OK);\n    }\n\n    /* Read that crosses page boundary returns error */\n    size_t bad_len = page_size + 1;\n    ret = bdl->ops->read(bdl, buf, bad_len, 0, bad_len);\n    TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, ret);\n\n    free(buf);\n    deinit_nand_flash(spi, bdl);\n}\n\nTEST_CASE(\"Flash BDL write invalid args\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    setup_chip(&spi, SPI_DEVICE_HALFDUPLEX);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = SPI_DEVICE_HALFDUPLEX,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n    };\n    esp_blockdev_handle_t bdl = NULL;\n    TEST_ESP_OK(nand_flash_get_blockdev(&nand_flash_config, &bdl));\n    TEST_ASSERT_NOT_NULL(bdl);\n\n    uint32_t page_size = bdl->geometry.write_size;\n    uint8_t *buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DEFAULT);\n    TEST_ASSERT_NOT_NULL(buf);\n    memset(buf, 0x55, page_size);\n\n    esp_err_t ret = bdl->ops->write(bdl, NULL, 0, page_size);\n    TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, ret);\n\n    ret = bdl->ops->write(bdl, buf, 1, page_size);\n    TEST_ASSERT_TRUE(ret == ESP_ERR_INVALID_ARG || ret == ESP_ERR_INVALID_SIZE);\n\n    ret = bdl->ops->write(bdl, buf, 0, page_size - 1);\n    TEST_ASSERT_TRUE(ret == ESP_ERR_INVALID_ARG || ret == ESP_ERR_INVALID_SIZE);\n\n    uint64_t oob = bdl->geometry.disk_size;\n    if (oob >= page_size) {\n        ret = bdl->ops->write(bdl, buf, oob - page_size + 1, page_size);\n        TEST_ASSERT_TRUE(ret != ESP_OK);\n    }\n\n    free(buf);\n    deinit_nand_flash(spi, bdl);\n}\n\nTEST_CASE(\"Flash BDL multi-page read and write\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    setup_chip(&spi, SPI_DEVICE_HALFDUPLEX);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = SPI_DEVICE_HALFDUPLEX,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n    };\n    esp_blockdev_handle_t bdl = NULL;\n    TEST_ESP_OK(nand_flash_get_blockdev(&nand_flash_config, &bdl));\n    TEST_ASSERT_NOT_NULL(bdl);\n\n    uint32_t page_size = bdl->geometry.write_size;\n    uint32_t block_size = bdl->geometry.erase_size;\n    const uint32_t num_pages = 3;\n    uint32_t start_page = (uint32_t)(bdl->geometry.disk_size / page_size) / 2;\n    if (start_page + num_pages > bdl->geometry.disk_size / page_size) {\n        start_page = 0;\n    }\n\n    uint32_t start_block = start_page / (block_size / page_size);\n    TEST_ASSERT_TRUE(flash_bdl_erase_block_if_good(bdl, start_block));\n\n    size_t total_len = num_pages * page_size;\n    uint8_t *pattern_buf = (uint8_t *)heap_caps_malloc(total_len, MALLOC_CAP_DEFAULT);\n    uint8_t *read_buf = (uint8_t *)heap_caps_malloc(total_len, MALLOC_CAP_DEFAULT);\n    TEST_ASSERT_NOT_NULL(pattern_buf);\n    TEST_ASSERT_NOT_NULL(read_buf);\n\n    spi_nand_flash_fill_buffer(pattern_buf, total_len / sizeof(uint32_t));\n    TEST_ESP_OK(bdl->ops->write(bdl, pattern_buf, start_page * (uint64_t)page_size, total_len));\n    memset(read_buf, 0, total_len);\n    TEST_ESP_OK(bdl->ops->read(bdl, read_buf, total_len, start_page * (uint64_t)page_size, total_len));\n    TEST_ASSERT_EQUAL(0, spi_nand_flash_check_buffer(read_buf, total_len / sizeof(uint32_t)));\n\n    /* Read back in single-page chunks */\n    uint8_t *chunk_buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DEFAULT);\n    TEST_ASSERT_NOT_NULL(chunk_buf);\n    for (uint32_t i = 0; i < num_pages; i++) {\n        memset(chunk_buf, 0, page_size);\n        TEST_ESP_OK(bdl->ops->read(bdl, chunk_buf, page_size, start_page * (uint64_t)page_size + i * (uint64_t)page_size, page_size));\n        TEST_ASSERT_EQUAL_MEMORY(pattern_buf + i * page_size, chunk_buf, page_size);\n    }\n    free(chunk_buf);\n\n    free(pattern_buf);\n    free(read_buf);\n    deinit_nand_flash(spi, bdl);\n}\n\nTEST_CASE(\"Flash BDL release then create again (no use-after-free)\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    setup_chip(&spi, SPI_DEVICE_HALFDUPLEX);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = SPI_DEVICE_HALFDUPLEX,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n    };\n    esp_blockdev_handle_t bdl = NULL;\n    TEST_ESP_OK(nand_flash_get_blockdev(&nand_flash_config, &bdl));\n    TEST_ASSERT_NOT_NULL(bdl);\n    bdl->ops->release(bdl);\n\n    bdl = NULL;\n    TEST_ESP_OK(nand_flash_get_blockdev(&nand_flash_config, &bdl));\n    TEST_ASSERT_NOT_NULL(bdl);\n\n    uint32_t page_size = bdl->geometry.write_size;\n    uint8_t *buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DEFAULT);\n    TEST_ASSERT_NOT_NULL(buf);\n    memset(buf, 0xAA, page_size);\n    TEST_ESP_OK(bdl->ops->write(bdl, buf, 0, page_size));\n    memset(buf, 0, page_size);\n    TEST_ESP_OK(bdl->ops->read(bdl, buf, page_size, 0, page_size));\n    free(buf);\n\n    deinit_nand_flash(spi, bdl);\n}\n\nTEST_CASE(\"Flash BDL sync returns success\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    setup_chip(&spi, SPI_DEVICE_HALFDUPLEX);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = SPI_DEVICE_HALFDUPLEX,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n    };\n    esp_blockdev_handle_t bdl = NULL;\n    TEST_ESP_OK(nand_flash_get_blockdev(&nand_flash_config, &bdl));\n    TEST_ASSERT_NOT_NULL(bdl);\n\n    esp_err_t ret = bdl->ops->sync(bdl);\n    TEST_ASSERT_EQUAL(ESP_OK, ret);\n\n    deinit_nand_flash(spi, bdl);\n}\n\nTEST_CASE(\"Flash BDL ioctl with NULL args returns error\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    setup_chip(&spi, SPI_DEVICE_HALFDUPLEX);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = SPI_DEVICE_HALFDUPLEX,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n    };\n    esp_blockdev_handle_t bdl = NULL;\n    TEST_ESP_OK(nand_flash_get_blockdev(&nand_flash_config, &bdl));\n    TEST_ASSERT_NOT_NULL(bdl);\n\n    esp_err_t ret = bdl->ops->ioctl(bdl, ESP_BLOCKDEV_CMD_GET_NAND_FLASH_INFO, NULL);\n    TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, ret);\n\n    ret = bdl->ops->ioctl(bdl, ESP_BLOCKDEV_CMD_GET_BAD_BLOCKS_COUNT, NULL);\n    TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, ret);\n\n    deinit_nand_flash(spi, bdl);\n}\n\nTEST_CASE(\"Flash BDL zero-length read and write\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    setup_chip(&spi, SPI_DEVICE_HALFDUPLEX);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = SPI_DEVICE_HALFDUPLEX,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n    };\n    esp_blockdev_handle_t bdl = NULL;\n    TEST_ESP_OK(nand_flash_get_blockdev(&nand_flash_config, &bdl));\n    TEST_ASSERT_NOT_NULL(bdl);\n\n    uint8_t buf = 0;\n    esp_err_t ret = bdl->ops->read(bdl, &buf, 1, 0, 0);\n    TEST_ASSERT_EQUAL(ESP_OK, ret);\n\n    ret = bdl->ops->write(bdl, &buf, 0, 0);\n    TEST_ASSERT_EQUAL(ESP_OK, ret);\n\n    deinit_nand_flash(spi, bdl);\n}\n\nTEST_CASE(\"Flash BDL sub-page (partial page) read\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    setup_chip(&spi, SPI_DEVICE_HALFDUPLEX);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = SPI_DEVICE_HALFDUPLEX,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n    };\n    esp_blockdev_handle_t bdl = NULL;\n    TEST_ESP_OK(nand_flash_get_blockdev(&nand_flash_config, &bdl));\n    TEST_ASSERT_NOT_NULL(bdl);\n\n    uint32_t page_size = bdl->geometry.write_size;\n    uint32_t block_size = bdl->geometry.erase_size;\n    size_t partial_len = (page_size >= 256) ? 256 : (page_size / 2);\n    if (partial_len == 0) {\n        partial_len = 1;\n    }\n\n    uint32_t test_page = (uint32_t)(bdl->geometry.disk_size / page_size) / 2;\n    uint64_t addr = test_page * (uint64_t)page_size;\n    uint32_t sub_block = (uint32_t)(addr / block_size);\n    TEST_ASSERT_TRUE(flash_bdl_erase_block_if_good(bdl, sub_block));\n\n    uint8_t *pattern_buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DEFAULT);\n    uint8_t *read_buf = (uint8_t *)heap_caps_malloc(partial_len, MALLOC_CAP_DEFAULT);\n    TEST_ASSERT_NOT_NULL(pattern_buf);\n    TEST_ASSERT_NOT_NULL(read_buf);\n\n    spi_nand_flash_fill_buffer(pattern_buf, page_size / sizeof(uint32_t));\n    TEST_ESP_OK(bdl->ops->write(bdl, pattern_buf, addr, page_size));\n\n    memset(read_buf, 0, partial_len);\n    TEST_ESP_OK(bdl->ops->read(bdl, read_buf, partial_len, addr, partial_len));\n    TEST_ASSERT_EQUAL_MEMORY(pattern_buf, read_buf, partial_len);\n\n    size_t offset = (page_size >= 128) ? 128 : 1;\n    size_t len = (page_size > offset + 64) ? 64 : (page_size - offset);\n    if (len > 0) {\n        memset(read_buf, 0, len);\n        TEST_ESP_OK(bdl->ops->read(bdl, read_buf, len, addr + offset, len));\n        TEST_ASSERT_EQUAL_MEMORY((uint8_t *)pattern_buf + offset, read_buf, len);\n    }\n\n    free(pattern_buf);\n    free(read_buf);\n    deinit_nand_flash(spi, bdl);\n}\n\nTEST_CASE(\"Flash BDL multi-page spanning block boundary\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    setup_chip(&spi, SPI_DEVICE_HALFDUPLEX);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = SPI_DEVICE_HALFDUPLEX,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n    };\n    esp_blockdev_handle_t bdl = NULL;\n    TEST_ESP_OK(nand_flash_get_blockdev(&nand_flash_config, &bdl));\n    TEST_ASSERT_NOT_NULL(bdl);\n\n    uint32_t page_size = bdl->geometry.write_size;\n    uint32_t block_size = bdl->geometry.erase_size;\n    uint32_t pages_per_block = block_size / page_size;\n    uint32_t num_pages = (uint32_t)(bdl->geometry.disk_size / page_size);\n    if (pages_per_block < 2 || num_pages < pages_per_block + 2) {\n        deinit_nand_flash(spi, bdl);\n        return;\n    }\n\n    uint32_t last_page_of_block0 = pages_per_block - 1;\n    uint32_t page_count = 2;\n    uint64_t start_addr = last_page_of_block0 * (uint64_t)page_size;\n\n    TEST_ASSERT_TRUE(flash_bdl_erase_block_if_good(bdl, 0));\n    TEST_ASSERT_TRUE(flash_bdl_erase_block_if_good(bdl, 1));\n\n    size_t total_len = page_count * page_size;\n    uint8_t *pattern_buf = (uint8_t *)heap_caps_malloc(total_len, MALLOC_CAP_DEFAULT);\n    uint8_t *read_buf = (uint8_t *)heap_caps_malloc(total_len, MALLOC_CAP_DEFAULT);\n    TEST_ASSERT_NOT_NULL(pattern_buf);\n    TEST_ASSERT_NOT_NULL(read_buf);\n\n    spi_nand_flash_fill_buffer(pattern_buf, total_len / sizeof(uint32_t));\n    TEST_ESP_OK(bdl->ops->write(bdl, pattern_buf, start_addr, total_len));\n    memset(read_buf, 0, total_len);\n    TEST_ESP_OK(bdl->ops->read(bdl, read_buf, total_len, start_addr, total_len));\n    TEST_ASSERT_EQUAL_MEMORY(pattern_buf, read_buf, total_len);\n\n    free(pattern_buf);\n    free(read_buf);\n    deinit_nand_flash(spi, bdl);\n}\n\nTEST_CASE(\"Flash BDL read at end of device (last byte)\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    setup_chip(&spi, SPI_DEVICE_HALFDUPLEX);\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .flags = SPI_DEVICE_HALFDUPLEX,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n    };\n    esp_blockdev_handle_t bdl = NULL;\n    TEST_ESP_OK(nand_flash_get_blockdev(&nand_flash_config, &bdl));\n    TEST_ASSERT_NOT_NULL(bdl);\n\n    uint64_t disk_size = bdl->geometry.disk_size;\n    uint32_t block_size = (uint32_t)bdl->geometry.erase_size;\n    uint32_t last_block = (uint32_t)(disk_size / block_size) - 1;\n    TEST_ASSERT_TRUE(flash_bdl_erase_block_if_good(bdl, last_block));\n\n    uint8_t buf[1];\n    esp_err_t ret = bdl->ops->read(bdl, buf, sizeof(buf), disk_size - 1, 1);\n    TEST_ASSERT_EQUAL(ESP_OK, ret);\n\n    ret = bdl->ops->read(bdl, buf, sizeof(buf), disk_size, 1);\n    TEST_ASSERT_EQUAL(ESP_ERR_INVALID_SIZE, ret);\n\n    deinit_nand_flash(spi, bdl);\n}\n\n/* --- WL BDL tests (grouped together) --- */\n\nTEST_CASE(\"WL BDL sync after write\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    esp_blockdev_handle_t wl_bdl;\n    setup_nand_flash(&spi, SPI_NAND_IO_MODE_SIO, SPI_DEVICE_HALFDUPLEX, &wl_bdl);\n\n    uint32_t page_size = wl_bdl->geometry.write_size;\n    uint8_t *pattern_buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DEFAULT);\n    uint8_t *read_buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DEFAULT);\n    TEST_ASSERT_NOT_NULL(pattern_buf);\n    TEST_ASSERT_NOT_NULL(read_buf);\n\n    spi_nand_flash_fill_buffer(pattern_buf, page_size / sizeof(uint32_t));\n    TEST_ESP_OK(wl_bdl->ops->write(wl_bdl, pattern_buf, 0, page_size));\n    TEST_ESP_OK(wl_bdl->ops->sync(wl_bdl));\n    memset(read_buf, 0, page_size);\n    TEST_ESP_OK(wl_bdl->ops->read(wl_bdl, read_buf, page_size, 0, page_size));\n    TEST_ASSERT_EQUAL(0, spi_nand_flash_check_buffer(read_buf, page_size / sizeof(uint32_t)));\n\n    free(pattern_buf);\n    free(read_buf);\n    deinit_nand_flash(spi, wl_bdl);\n}\n\nTEST_CASE(\"WL BDL ESP_BLOCKDEV_CMD_MARK_DELETED (TRIM)\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    esp_blockdev_handle_t wl_bdl;\n    setup_nand_flash(&spi, SPI_NAND_IO_MODE_SIO, SPI_DEVICE_HALFDUPLEX, &wl_bdl);\n\n    uint32_t page_size = wl_bdl->geometry.write_size;\n    TEST_ASSERT_TRUE(page_size > 0);\n    uint32_t num_pages = (uint32_t)(wl_bdl->geometry.disk_size / page_size);\n    TEST_ASSERT_TRUE(num_pages >= 4);\n\n    uint8_t *pattern_buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DEFAULT);\n    TEST_ASSERT_NOT_NULL(pattern_buf);\n    spi_nand_flash_fill_buffer(pattern_buf, page_size / sizeof(uint32_t));\n\n    const uint32_t start_page = 1;\n    const uint32_t page_count = 3;\n    for (uint32_t i = start_page; i < start_page + page_count; i++) {\n        TEST_ESP_OK(wl_bdl->ops->write(wl_bdl, pattern_buf, (uint64_t)i * page_size, page_size));\n    }\n\n    esp_blockdev_cmd_arg_erase_t trim_arg = {\n        .start_addr = (uint64_t)start_page * page_size,\n        .erase_len = (size_t)page_count * page_size,\n    };\n    TEST_ESP_OK(wl_bdl->ops->ioctl(wl_bdl, ESP_BLOCKDEV_CMD_MARK_DELETED, &trim_arg));\n\n    free(pattern_buf);\n    deinit_nand_flash(spi, wl_bdl);\n}\n\nTEST_CASE(\"WL BDL read invalid args\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    esp_blockdev_handle_t wl_bdl;\n    setup_nand_flash(&spi, SPI_NAND_IO_MODE_SIO, SPI_DEVICE_HALFDUPLEX, &wl_bdl);\n\n    uint32_t page_size = wl_bdl->geometry.read_size;\n    uint8_t *buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DEFAULT);\n    TEST_ASSERT_NOT_NULL(buf);\n\n    esp_err_t ret = wl_bdl->ops->read(wl_bdl, NULL, page_size, 0, page_size);\n    TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, ret);\n\n    ret = wl_bdl->ops->read(wl_bdl, buf, page_size - 1, 0, page_size);\n    TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, ret);\n\n    ret = wl_bdl->ops->read(wl_bdl, buf, page_size, wl_bdl->geometry.disk_size, page_size);\n    TEST_ASSERT_TRUE(ret != ESP_OK);\n\n    free(buf);\n    deinit_nand_flash(spi, wl_bdl);\n}\n\nTEST_CASE(\"WL BDL write invalid args\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    esp_blockdev_handle_t wl_bdl;\n    setup_nand_flash(&spi, SPI_NAND_IO_MODE_SIO, SPI_DEVICE_HALFDUPLEX, &wl_bdl);\n\n    uint32_t page_size = wl_bdl->geometry.write_size;\n    uint8_t *buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DEFAULT);\n    TEST_ASSERT_NOT_NULL(buf);\n    memset(buf, 0x55, page_size);\n\n    esp_err_t ret = wl_bdl->ops->write(wl_bdl, NULL, 0, page_size);\n    TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, ret);\n\n    ret = wl_bdl->ops->write(wl_bdl, buf, 1, page_size);\n    TEST_ASSERT_TRUE(ret == ESP_ERR_INVALID_ARG || ret == ESP_ERR_INVALID_SIZE);\n\n    ret = wl_bdl->ops->write(wl_bdl, buf, wl_bdl->geometry.disk_size, page_size);\n    TEST_ASSERT_TRUE(ret != ESP_OK);\n\n    free(buf);\n    deinit_nand_flash(spi, wl_bdl);\n}\n\nTEST_CASE(\"WL BDL erase invalid args\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    esp_blockdev_handle_t wl_bdl;\n    setup_nand_flash(&spi, SPI_NAND_IO_MODE_SIO, SPI_DEVICE_HALFDUPLEX, &wl_bdl);\n\n    uint32_t erase_size = (uint32_t)wl_bdl->geometry.erase_size;\n\n    esp_err_t ret = wl_bdl->ops->erase(wl_bdl, erase_size / 2, erase_size);\n    TEST_ASSERT_TRUE(ret == ESP_ERR_INVALID_ARG || ret == ESP_ERR_INVALID_SIZE);\n\n    ret = wl_bdl->ops->erase(wl_bdl, wl_bdl->geometry.disk_size, erase_size);\n    TEST_ASSERT_TRUE(ret != ESP_OK);\n\n    deinit_nand_flash(spi, wl_bdl);\n}\n\nTEST_CASE(\"WL BDL zero-length read and write\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    esp_blockdev_handle_t wl_bdl;\n    setup_nand_flash(&spi, SPI_NAND_IO_MODE_SIO, SPI_DEVICE_HALFDUPLEX, &wl_bdl);\n\n    uint8_t buf = 0;\n    esp_err_t ret = wl_bdl->ops->read(wl_bdl, &buf, 1, 0, 0);\n    TEST_ASSERT_EQUAL(ESP_OK, ret);\n\n    ret = wl_bdl->ops->write(wl_bdl, &buf, 0, 0);\n    TEST_ASSERT_EQUAL(ESP_OK, ret);\n\n    deinit_nand_flash(spi, wl_bdl);\n}\n\nTEST_CASE(\"WL BDL geometry page count stable after full erase\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    esp_blockdev_handle_t wl_bdl;\n    setup_nand_flash(&spi, SPI_NAND_IO_MODE_SIO, SPI_DEVICE_HALFDUPLEX, &wl_bdl);\n\n    uint32_t page_size = wl_bdl->geometry.write_size;\n    TEST_ASSERT_TRUE(page_size > 0);\n    uint32_t num_before = (uint32_t)(wl_bdl->geometry.disk_size / page_size);\n\n    /* Erase length must be aligned to erase_size */\n    size_t erase_size = (size_t)wl_bdl->geometry.erase_size;\n    size_t erase_len = (size_t)((wl_bdl->geometry.disk_size / erase_size) * erase_size);\n    TEST_ESP_OK(wl_bdl->ops->erase(wl_bdl, 0, erase_len));\n\n    uint32_t num_after = (uint32_t)(wl_bdl->geometry.disk_size / page_size);\n    TEST_ASSERT_EQUAL_UINT32(num_before, num_after);\n\n    deinit_nand_flash(spi, wl_bdl);\n}\n\nTEST_CASE(\"WL BDL write N pages read back in different chunk sizes\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    esp_blockdev_handle_t wl_bdl;\n    setup_nand_flash(&spi, SPI_NAND_IO_MODE_SIO, SPI_DEVICE_HALFDUPLEX, &wl_bdl);\n\n    uint32_t page_size = wl_bdl->geometry.write_size;\n    TEST_ASSERT_TRUE(page_size > 0);\n    uint32_t num_pages = (uint32_t)(wl_bdl->geometry.disk_size / page_size);\n    TEST_ASSERT_TRUE(num_pages >= 3);\n\n    const uint32_t n = 3;\n    size_t total_len = n * page_size;\n    uint8_t *pattern_buf = (uint8_t *)heap_caps_malloc(total_len, MALLOC_CAP_DEFAULT);\n    uint8_t *read_buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DEFAULT);\n    TEST_ASSERT_NOT_NULL(pattern_buf);\n    TEST_ASSERT_NOT_NULL(read_buf);\n\n    spi_nand_flash_fill_buffer(pattern_buf, total_len / sizeof(uint32_t));\n    TEST_ESP_OK(wl_bdl->ops->write(wl_bdl, pattern_buf, 0, total_len));\n\n    for (uint32_t i = 0; i < n; i++) {\n        memset(read_buf, 0, page_size);\n        TEST_ESP_OK(wl_bdl->ops->read(wl_bdl, read_buf, page_size, i * (uint64_t)page_size, page_size));\n        TEST_ASSERT_EQUAL_MEMORY(pattern_buf + i * page_size, read_buf, page_size);\n    }\n\n    free(pattern_buf);\n    free(read_buf);\n    deinit_nand_flash(spi, wl_bdl);\n}\n\nTEST_CASE(\"WL BDL unaligned read and write length returns error\", \"[spi_nand_flash][bdl]\")\n{\n    spi_device_handle_t spi;\n    esp_blockdev_handle_t wl_bdl;\n    setup_nand_flash(&spi, SPI_NAND_IO_MODE_SIO, SPI_DEVICE_HALFDUPLEX, &wl_bdl);\n\n    uint32_t page_size = wl_bdl->geometry.read_size;\n    uint8_t *buf = (uint8_t *)heap_caps_malloc(page_size + 1, MALLOC_CAP_DEFAULT);\n    TEST_ASSERT_NOT_NULL(buf);\n\n    esp_err_t ret = wl_bdl->ops->read(wl_bdl, buf, page_size + 1, 0, page_size + 1);\n    TEST_ASSERT_TRUE(ret == ESP_ERR_INVALID_ARG || ret == ESP_ERR_INVALID_SIZE);\n\n    memset(buf, 0x55, page_size + 1);\n    ret = wl_bdl->ops->write(wl_bdl, buf, 0, page_size + 1);\n    TEST_ASSERT_TRUE(ret == ESP_ERR_INVALID_ARG || ret == ESP_ERR_INVALID_SIZE);\n\n    free(buf);\n    deinit_nand_flash(spi, wl_bdl);\n}\n"
  },
  {
    "path": "spi_nand_flash/test_app/pytest_spi_nand_flash.py",
    "content": "# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.utils import idf_parametrize\nimport glob\nfrom pathlib import Path\n\n\n@pytest.mark.spi_nand_flash\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that not build\"\n)\n@pytest.mark.parametrize(\n    'config',\n    [\n        'default',\n    ],\n    indirect=True,\n)\n@idf_parametrize('target', ['esp32'], indirect=['target'])\ndef test_spi_nand_flash(dut: Dut, config: str) -> None:\n    dut.run_all_single_board_cases()\n\n\n@pytest.mark.spi_nand_flash\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that not build\"\n)\n@pytest.mark.parametrize(\n    'config',\n    [\n        'bdl',\n    ],\n    indirect=True,\n)\n@idf_parametrize('target', ['esp32'], indirect=['target'])\ndef test_spi_nand_flash_bdl(dut: Dut, config: str) -> None:\n    dut.run_all_single_board_cases()\n"
  },
  {
    "path": "spi_nand_flash/test_app/sdkconfig.ci.bdl",
    "content": "CONFIG_NAND_FLASH_ENABLE_BDL=y\n"
  },
  {
    "path": "spi_nand_flash/test_app/sdkconfig.ci.default",
    "content": ""
  },
  {
    "path": "spi_nand_flash/test_app/sdkconfig.defaults",
    "content": "# Enable Unity fixture support\nCONFIG_UNITY_ENABLE_FIXTURE=n\nCONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y\n\nCONFIG_ESP_TASK_WDT_INIT=n\n"
  },
  {
    "path": "spi_nand_flash_fatfs/CHANGELOG.md",
    "content": "## [1.0.0]\n\n### Breaking Changes\n- FATFS integration for SPI NAND Flash now lives in this component. Projects that previously relied on FATFS support bundled inside `spi_nand_flash` must add `spi_nand_flash_fatfs` as a dependency and include its headers.\n\n**Migration:** See **Migration Guide (0.x → 1.0.0)** in [`spi_nand_flash/layered_architecture.md`](../spi_nand_flash/layered_architecture.md) (FATFS split, legacy init with BDL disabled, and related driver changes).\n"
  },
  {
    "path": "spi_nand_flash_fatfs/CMakeLists.txt",
    "content": "set(srcs \"src/diskio_nand.c\"\n         \"src/vfs_fat_spinandflash.c\")\n\nidf_component_register(\n    SRCS ${srcs}\n    INCLUDE_DIRS \"include\"\n    REQUIRES spi_nand_flash fatfs\n    PRIV_REQUIRES vfs\n)\n"
  },
  {
    "path": "spi_nand_flash_fatfs/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "spi_nand_flash_fatfs/README.md",
    "content": "# SPI NAND Flash FatFS Integration\n\nFatFS integration layer for the SPI NAND Flash driver.\n\n## Requirements (read first)\n\n**`spi_nand_flash_fatfs` only supports the legacy driver handle** (`spi_nand_flash_device_t` from `spi_nand_flash_init_device()`).\n\n- Keep **`CONFIG_NAND_FLASH_ENABLE_BDL` disabled** in menuconfig. When BDL is enabled, `spi_nand_flash_init_device()` returns `ESP_ERR_NOT_SUPPORTED`, so `esp_vfs_fat_nand_mount()` / diskio cannot be used.\n- **FatFs on top of the wear-leveling block device (`esp_blockdev_t`) is not supported in this release.** A future component integration will add it; until then use the legacy path above for FAT.\n\n**Migration from 0.x:** See the SPI NAND component’s [layered_architecture.md](../spi_nand_flash/layered_architecture.md) — **Migration Guide (0.x → 1.0.0)** (FATFS split, BDL vs legacy init).\n\n## Features\n\n- FATFS diskio adapter and VFS mount helpers using `spi_nand_flash_device_t`\n- Same usage as before the `spi_nand_flash` / `spi_nand_flash_fatfs` split (legacy init + mount)\n\n## Dependencies\n\n- `spi_nand_flash` component (driver)\n- ESP-IDF `fatfs` component\n- ESP-IDF `vfs` component\n\n## Usage\n\n```c\n#include \"spi_nand_flash.h\"\n#include \"esp_vfs_fat_nand.h\"\n\n// Initialize device (CONFIG_NAND_FLASH_ENABLE_BDL must be off)\nspi_nand_flash_device_t *nand_device;\nspi_nand_flash_init_device(&config, &nand_device);\n\n// Mount FATFS\nesp_vfs_fat_mount_config_t mount_config = {\n    .max_files = 4,\n    .format_if_mount_failed = true,\n};\nesp_vfs_fat_nand_mount(\"/nand\", nand_device, &mount_config);\n\n// Use filesystem...\nFILE *f = fopen(\"/nand/test.txt\", \"w\");\n// ...\n\n// Unmount\nesp_vfs_fat_nand_unmount(\"/nand\", nand_device);\nspi_nand_flash_deinit_device(nand_device);\n```\n\n## Examples\n\n| Example | Description | `CONFIG_NAND_FLASH_ENABLE_BDL` | IDF |\n|---------|-------------|--------------------------------|-----|\n| `examples/nand_flash` | FATFS on NAND (`spi_nand_flash_init_device` + `esp_vfs_fat_nand_mount`) | **Must be off** | 5.0+ |\n| `examples/nand_flash_debug_app` | Diagnostics (bad blocks, ECC stats, throughput); `spi_nand_flash` only, no VFS | **Must be off** | 5.0+ |\n\nSee each example’s `README.md` for hardware and usage.\n"
  },
  {
    "path": "spi_nand_flash_fatfs/examples/nand_flash/CMakeLists.txt",
    "content": "# The following lines of boilerplate have to be in your project's CMakeLists\n# in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.5)\n\nset(COMPONENTS main)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nproject(nand_flash)\n"
  },
  {
    "path": "spi_nand_flash_fatfs/examples/nand_flash/README.md",
    "content": "| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |\n| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |\n\n# SPI NAND Flash Example\n\nThis example demonstrates how to use the SPI NAND Flash driver with FAT filesystem in ESP-IDF.\n\n## Hardware Required\n\n* Any ESP board from the supported targets list above\n* An external SPI NAND Flash chip connected to the following pins:\n  * For ESP32 (SPI3):\n    - MOSI - SPI3_IOMUX_PIN_NUM_MOSI (23)\n    - MISO - SPI3_IOMUX_PIN_NUM_MISO (19)\n    - CLK  - SPI3_IOMUX_PIN_NUM_CLK (18)\n    - CS   - SPI3_IOMUX_PIN_NUM_CS (5)\n    - WP   - SPI3_IOMUX_PIN_NUM_WP (22)\n    - HD   - SPI3_IOMUX_PIN_NUM_HD (21)\n  * For other ESP chips (SPI2):\n    - MOSI - SPI2_IOMUX_PIN_NUM_MOSI (13)\n    - MISO - SPI2_IOMUX_PIN_NUM_MISO (12)\n    - CLK  - SPI2_IOMUX_PIN_NUM_CLK (14)\n    - CS   - SPI2_IOMUX_PIN_NUM_CS (15)\n    - WP   - SPI2_IOMUX_PIN_NUM_WP (2)\n    - HD   - SPI2_IOMUX_PIN_NUM_HD (4)\n\n## Configuration\n\nThe example can be configured to format the filesystem if mounting fails. This can be enabled using the `CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED` configuration option.\n\nKeep **`CONFIG_NAND_FLASH_ENABLE_BDL` disabled** (Component config → SPI NAND Flash). This example uses `spi_nand_flash_init_device()`, which is not available when BDL is enabled.\n\n## How to Use Example\n\nBuild the project and flash it to the board, then run monitor tool to view serial output:\n\n```bash\nidf.py -p PORT flash monitor\n```\n\n(To exit the serial monitor, type ``Ctrl-]``.)\n\nSee the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.\n\n## Example Output\n\nThe example:\n1. Initializes the SPI bus and NAND Flash device\n2. Mounts a FAT filesystem on the NAND Flash\n3. Creates and writes to a file named \"hello.txt\"\n4. Reads back and displays the contents of the file\n5. Displays filesystem space information\n6. Unmounts the filesystem and deinitializes the NAND Flash\n\nHere is the example's console output:\n```\n...\nI (315) main_task: Calling app_main()\nI (315) example: DMA CHANNEL: 3\nW (355) vfs_fat_nand: f_mount failed (13)\nI (355) vfs_fat_nand: Formatting FATFS partition, allocation unit size=16384\nI (6635) vfs_fat_nand: Mounting again\nI (6655) example: FAT FS: 117024 kB total, 117024 kB free\nI (6655) example: Opening file\nI (6685) example: File written\nI (6685) example: Reading file\nI (6685) example: Read from file: 'Written using ESP-IDF v5.5-dev-2627-g2cbfce97768'\nI (6685) example: FAT FS: 117024 kB total, 117008 kB free\nI (6695) gpio: GPIO[5]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0\nI (6705) gpio: GPIO[23]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0\nI (6705) gpio: GPIO[19]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0\nI (6715) gpio: GPIO[18]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0\nI (6725) gpio: GPIO[22]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0\nI (6735) gpio: GPIO[21]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0\nI (6745) main_task: Returned from app_main()\n...\n```\n"
  },
  {
    "path": "spi_nand_flash_fatfs/examples/nand_flash/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"spi_nand_flash_example_main.c\"\n                       INCLUDE_DIRS \".\"\n                       PRIV_REQUIRES spi_nand_flash_fatfs\n                       )\n"
  },
  {
    "path": "spi_nand_flash_fatfs/examples/nand_flash/main/Kconfig.projbuild",
    "content": "menu \"SPI Example Configuration\"\n\n    config EXAMPLE_FORMAT_IF_MOUNT_FAILED\n        bool \"Format the flash if mount failed\"\n        default n\n        help\n             If this config item is set, format_if_mount_failed will be set to true and the card will be formatted if\n             the mount has failed.\nendmenu\n"
  },
  {
    "path": "spi_nand_flash_fatfs/examples/nand_flash/main/idf_component.yml",
    "content": "dependencies:\n  espressif/spi_nand_flash_fatfs:\n    version: '*'\n    override_path: '../../../'\n"
  },
  {
    "path": "spi_nand_flash_fatfs/examples/nand_flash/main/spi_nand_flash_example_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"esp_system.h\"\n#include \"soc/spi_pins.h\"\n#include \"esp_vfs_fat_nand.h\"\n\n#define EXAMPLE_FLASH_FREQ_KHZ      40000\n\nstatic const char *TAG = \"example\";\n\n// Pin mapping\n// ESP32 (VSPI)\n#ifdef CONFIG_IDF_TARGET_ESP32\n#define HOST_ID  SPI3_HOST\n#define PIN_MOSI SPI3_IOMUX_PIN_NUM_MOSI\n#define PIN_MISO SPI3_IOMUX_PIN_NUM_MISO\n#define PIN_CLK  SPI3_IOMUX_PIN_NUM_CLK\n#define PIN_CS   SPI3_IOMUX_PIN_NUM_CS\n#define PIN_WP   SPI3_IOMUX_PIN_NUM_WP\n#define PIN_HD   SPI3_IOMUX_PIN_NUM_HD\n#define SPI_DMA_CHAN SPI_DMA_CH_AUTO\n#else // Other chips (SPI2/HSPI)\n#define HOST_ID  SPI2_HOST\n#define PIN_MOSI SPI2_IOMUX_PIN_NUM_MOSI\n#define PIN_MISO SPI2_IOMUX_PIN_NUM_MISO\n#define PIN_CLK  SPI2_IOMUX_PIN_NUM_CLK\n#define PIN_CS   SPI2_IOMUX_PIN_NUM_CS\n#define PIN_WP   SPI2_IOMUX_PIN_NUM_WP\n#define PIN_HD   SPI2_IOMUX_PIN_NUM_HD\n#define SPI_DMA_CHAN SPI_DMA_CH_AUTO\n#endif\n\n// Mount path for the partition\nconst char *base_path = \"/nandflash\";\n\nstatic void example_init_nand_flash(spi_nand_flash_device_t **out_handle, spi_device_handle_t *spi_handle)\n{\n    const spi_bus_config_t bus_config = {\n        .mosi_io_num = PIN_MOSI,\n        .miso_io_num = PIN_MISO,\n        .sclk_io_num = PIN_CLK,\n        .quadhd_io_num = PIN_HD,\n        .quadwp_io_num = PIN_WP,\n        .max_transfer_sz = 4096 * 2,\n    };\n\n    // Initialize the SPI bus\n    ESP_LOGI(TAG, \"DMA CHANNEL: %d\", SPI_DMA_CHAN);\n    ESP_ERROR_CHECK(spi_bus_initialize(HOST_ID, &bus_config, SPI_DMA_CHAN));\n\n    // spi_flags = SPI_DEVICE_HALFDUPLEX -> half duplex\n    // spi_flags = 0 -> full_duplex\n    const uint32_t spi_flags = SPI_DEVICE_HALFDUPLEX;\n\n    spi_device_interface_config_t devcfg = {\n        .clock_speed_hz = EXAMPLE_FLASH_FREQ_KHZ * 1000,\n        .mode = 0,\n        .spics_io_num = PIN_CS,\n        .queue_size = 10,\n        .flags = spi_flags,\n    };\n\n    spi_device_handle_t spi;\n    ESP_ERROR_CHECK(spi_bus_add_device(HOST_ID, &devcfg, &spi));\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n        .flags = spi_flags,\n    };\n    assert(devcfg.flags == nand_flash_config.flags);\n    spi_nand_flash_device_t *nand_flash_device_handle;\n    ESP_ERROR_CHECK(spi_nand_flash_init_device(&nand_flash_config, &nand_flash_device_handle));\n\n    *out_handle = nand_flash_device_handle;\n    *spi_handle = spi;\n}\n\nstatic void example_deinit_nand_flash(spi_nand_flash_device_t *flash, spi_device_handle_t spi)\n{\n    ESP_ERROR_CHECK(spi_nand_flash_deinit_device(flash));\n    ESP_ERROR_CHECK(spi_bus_remove_device(spi));\n    ESP_ERROR_CHECK(spi_bus_free(HOST_ID));\n}\n\nvoid app_main(void)\n{\n    esp_err_t ret;\n    // Set up SPI bus and initialize the external SPI Flash chip\n    spi_device_handle_t spi;\n    spi_nand_flash_device_t *flash;\n    example_init_nand_flash(&flash, &spi);\n    if (flash == NULL) {\n        return;\n    }\n\n    esp_vfs_fat_mount_config_t config = {\n        .max_files = 4,\n#ifdef CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED\n        .format_if_mount_failed = true,\n#else\n        .format_if_mount_failed = false,\n#endif\n        .allocation_unit_size = 16 * 1024\n    };\n\n    ret = esp_vfs_fat_nand_mount(base_path, flash, &config);\n    if (ret != ESP_OK) {\n        if (ret == ESP_FAIL) {\n            ESP_LOGE(TAG, \"Failed to mount filesystem. \"\n                     \"If you want the flash memory to be formatted, set the CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.\");\n        }\n        return;\n    }\n\n    // Print FAT FS size information\n    uint64_t bytes_total, bytes_free;\n    esp_vfs_fat_info(base_path, &bytes_total, &bytes_free);\n    ESP_LOGI(TAG, \"FAT FS: %\" PRIu64 \" kB total, %\" PRIu64 \" kB free\", bytes_total / 1024, bytes_free / 1024);\n\n    // Create a file in FAT FS\n    ESP_LOGI(TAG, \"Opening file\");\n    FILE *f = fopen(\"/nandflash/hello.txt\", \"wb\");\n    if (f == NULL) {\n        ESP_LOGE(TAG, \"Failed to open file for writing\");\n        return;\n    }\n    fprintf(f, \"Written using ESP-IDF %s\\n\", esp_get_idf_version());\n    fclose(f);\n    ESP_LOGI(TAG, \"File written\");\n\n    // Open file for reading\n    ESP_LOGI(TAG, \"Reading file\");\n    f = fopen(\"/nandflash/hello.txt\", \"rb\");\n    if (f == NULL) {\n        ESP_LOGE(TAG, \"Failed to open file for reading\");\n        return;\n    }\n    char line[128];\n    fgets(line, sizeof(line), f);\n    fclose(f);\n    // strip newline\n    char *pos = strchr(line, '\\n');\n    if (pos) {\n        *pos = '\\0';\n    }\n    ESP_LOGI(TAG, \"Read from file: '%s'\", line);\n\n    esp_vfs_fat_info(base_path, &bytes_total, &bytes_free);\n    ESP_LOGI(TAG, \"FAT FS: %\" PRIu64 \" kB total, %\" PRIu64 \" kB free\", bytes_total / 1024, bytes_free / 1024);\n\n    esp_vfs_fat_nand_unmount(base_path, flash);\n\n    example_deinit_nand_flash(flash, spi);\n}\n"
  },
  {
    "path": "spi_nand_flash_fatfs/examples/nand_flash/pytest_nand_flash_example.py",
    "content": "# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.utils import idf_parametrize\nimport glob\nfrom pathlib import Path\n\n\n@pytest.mark.spi_nand_flash\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that not build\"\n)\n@idf_parametrize('target', ['esp32'], indirect=['target'])\ndef test_nand_flash_example(dut) -> None:\n    dut.expect_exact(\"Opening file\")\n    dut.expect_exact(\"File written\")\n    dut.expect_exact(\"Reading file\")\n    dut.expect_exact(\"Read from file:\")\n    dut.expect_exact(\"Returned from app_main\")\n"
  },
  {
    "path": "spi_nand_flash_fatfs/examples/nand_flash/sdkconfig.ci",
    "content": "CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED=y\n"
  },
  {
    "path": "spi_nand_flash_fatfs/examples/nand_flash_debug_app/CMakeLists.txt",
    "content": "# The following lines of boilerplate have to be in your project's CMakeLists\n# in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.5)\n\nset(COMPONENTS main)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nproject(nand_flash_debug_app)\n"
  },
  {
    "path": "spi_nand_flash_fatfs/examples/nand_flash_debug_app/README.md",
    "content": "| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |\n| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |\n\n# SPI NAND Flash debug example\n\nThis example is designed to gather diagnostic statistics for NAND flash, as outlined below:\n\n1. Bad block statistics.\n2. ECC error statistics.\n3. Read-write NAND page throughput (both at the lower level and through the Dhara library).\n4. Verification of NAND write operations using the Kconfig option `CONFIG_NAND_FLASH_VERIFY_WRITE`.\n\n## How to use example\n\nTo run the example, type the following command:\n\n```CMake\n# CMake\nidf.py -p PORT flash monitor\n```\n\n(To exit the serial monitor, type ``Ctrl-]``.)\n\nSee the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.\n\n## Example output\n\nHere is the example's console output:\n```\n...\nI (353) debug_app: Get bad block statistics:\nI (533) nand_diag:\nTotal number of Blocks: 1024\nBad Blocks: 1\nValid Blocks: 1023\n\nI (533) debug_app: Read-Write Throughput via Dhara:\nI (3423) debug_app: Wrote 2048000 bytes in 2269005 us, avg 902.60 kB/s\nI (3423) debug_app: Read 2048000 bytes in 617570 us, avg 3316.22 kB/s\n\nI (3423) debug_app: Read-Write Throughput at lower level (bypassing Dhara):\nI (5913) debug_app: Wrote 2048000 bytes in 1883853 us, avg 1087.13 kB/s\nI (5913) debug_app: Read 2048000 bytes in 585556 us, avg 3497.53 kB/s\n\nI (5913) debug_app: ECC errors statistics:\nI (17173) nand_diag:\nTotal number of ECC errors: 42\nECC not corrected count: 0\nECC errors exceeding threshold (4): 0\n...\n```\n"
  },
  {
    "path": "spi_nand_flash_fatfs/examples/nand_flash_debug_app/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"spi_nand_flash_debug_app_main.c\"\n                       INCLUDE_DIRS \".\"\n                       PRIV_REQUIRES spi_nand_flash esp_timer\n                       )\n"
  },
  {
    "path": "spi_nand_flash_fatfs/examples/nand_flash_debug_app/main/idf_component.yml",
    "content": "dependencies:\n  espressif/spi_nand_flash:\n    version: '*'\n    override_path: '../../../../spi_nand_flash/'\n  espressif/spi_nand_flash_fatfs:\n    version: '*'\n    override_path: '../../../'\n"
  },
  {
    "path": "spi_nand_flash_fatfs/examples/nand_flash_debug_app/main/spi_nand_flash_debug_app_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"esp_system.h\"\n#include \"soc/spi_pins.h\"\n#include \"spi_nand_flash.h\"\n#include \"spi_nand_flash_test_helpers.h\"\n#include \"nand_diag_api.h\"\n#include \"nand_private/nand_impl_wrap.h\"\n#include \"esp_log.h\"\n#include \"esp_check.h\"\n#include \"esp_timer.h\"\n#include \"esp_heap_caps.h\"\n\n#define EXAMPLE_FLASH_FREQ_KHZ      40000\n\nstatic const char *TAG = \"debug_app\";\n\n// Pin mapping\n// ESP32 (VSPI)\n#ifdef CONFIG_IDF_TARGET_ESP32\n#define HOST_ID  SPI3_HOST\n#define PIN_MOSI SPI3_IOMUX_PIN_NUM_MOSI\n#define PIN_MISO SPI3_IOMUX_PIN_NUM_MISO\n#define PIN_CLK  SPI3_IOMUX_PIN_NUM_CLK\n#define PIN_CS   SPI3_IOMUX_PIN_NUM_CS\n#define PIN_WP   SPI3_IOMUX_PIN_NUM_WP\n#define PIN_HD   SPI3_IOMUX_PIN_NUM_HD\n#define SPI_DMA_CHAN SPI_DMA_CH_AUTO\n#else // Other chips (SPI2/HSPI)\n#define HOST_ID  SPI2_HOST\n#define PIN_MOSI SPI2_IOMUX_PIN_NUM_MOSI\n#define PIN_MISO SPI2_IOMUX_PIN_NUM_MISO\n#define PIN_CLK  SPI2_IOMUX_PIN_NUM_CLK\n#define PIN_CS   SPI2_IOMUX_PIN_NUM_CS\n#define PIN_WP   SPI2_IOMUX_PIN_NUM_WP\n#define PIN_HD   SPI2_IOMUX_PIN_NUM_HD\n#define SPI_DMA_CHAN SPI_DMA_CH_AUTO\n#endif\n\nstatic void example_init_nand_flash(spi_nand_flash_device_t **out_handle, spi_device_handle_t *spi_handle)\n{\n    const spi_bus_config_t bus_config = {\n        .mosi_io_num = PIN_MOSI,\n        .miso_io_num = PIN_MISO,\n        .sclk_io_num = PIN_CLK,\n        .quadhd_io_num = PIN_HD,\n        .quadwp_io_num = PIN_WP,\n        .max_transfer_sz = 4096 * 2,\n    };\n\n    // Initialize the SPI bus\n    ESP_LOGI(TAG, \"DMA CHANNEL: %d\", SPI_DMA_CHAN);\n    ESP_ERROR_CHECK(spi_bus_initialize(HOST_ID, &bus_config, SPI_DMA_CHAN));\n\n    // spi_flags = SPI_DEVICE_HALFDUPLEX -> half duplex\n    // spi_flags = 0 -> full_duplex\n    const uint32_t spi_flags = SPI_DEVICE_HALFDUPLEX;\n\n    spi_device_interface_config_t devcfg = {\n        .clock_speed_hz = EXAMPLE_FLASH_FREQ_KHZ * 1000,\n        .mode = 0,\n        .spics_io_num = PIN_CS,\n        .queue_size = 10,\n        .flags = spi_flags,\n    };\n\n    spi_device_handle_t spi;\n    ESP_ERROR_CHECK(spi_bus_add_device(HOST_ID, &devcfg, &spi));\n\n    spi_nand_flash_config_t nand_flash_config = {\n        .device_handle = spi,\n        .io_mode = SPI_NAND_IO_MODE_SIO,\n        .flags = spi_flags\n    };\n    spi_nand_flash_device_t *nand_flash_device_handle;\n    ESP_ERROR_CHECK(spi_nand_flash_init_device(&nand_flash_config, &nand_flash_device_handle));\n\n    *out_handle = nand_flash_device_handle;\n    *spi_handle = spi;\n}\n\nstatic void example_deinit_nand_flash(spi_nand_flash_device_t *flash, spi_device_handle_t spi)\n{\n    ESP_ERROR_CHECK(spi_nand_flash_deinit_device(flash));\n    ESP_ERROR_CHECK(spi_bus_remove_device(spi));\n    ESP_ERROR_CHECK(spi_bus_free(HOST_ID));\n}\n\nstatic esp_err_t read_write_pages_tp(spi_nand_flash_device_t *flash, uint32_t start_page, uint16_t page_count, bool get_raw_tp)\n{\n    esp_err_t ret = ESP_OK;\n    uint8_t *temp_buf = NULL;\n    uint8_t *pattern_buf = NULL;\n    uint32_t page_size, num_pages;\n\n    ESP_ERROR_CHECK(spi_nand_flash_get_page_count(flash, &num_pages));\n    ESP_ERROR_CHECK(spi_nand_flash_get_page_size(flash, &page_size));\n\n    ESP_RETURN_ON_FALSE((start_page + page_count) < num_pages, ESP_ERR_INVALID_ARG, TAG, \"invalid argument\");\n\n    pattern_buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DMA);\n    ESP_RETURN_ON_FALSE(pattern_buf != NULL, ESP_ERR_NO_MEM, TAG, \"nomem\");\n    temp_buf = (uint8_t *)heap_caps_malloc(page_size, MALLOC_CAP_DMA);\n    ESP_RETURN_ON_FALSE(temp_buf != NULL, ESP_ERR_NO_MEM, TAG, \"nomem\");\n\n    spi_nand_flash_fill_buffer(pattern_buf, page_size / sizeof(uint32_t));\n\n    int64_t read_time = 0;\n    int64_t write_time = 0;\n\n    for (uint32_t i = start_page; i < (start_page + page_count); i++) {\n        int64_t start = esp_timer_get_time();\n        if (get_raw_tp) {\n            ESP_ERROR_CHECK(nand_wrap_prog(flash, i, pattern_buf));\n        } else {\n            ESP_ERROR_CHECK(spi_nand_flash_write_page(flash, pattern_buf, i));\n        }\n        write_time += esp_timer_get_time() - start;\n\n        memset((void *)temp_buf, 0x00, page_size);\n\n        start = esp_timer_get_time();\n        if (get_raw_tp) {\n            ESP_ERROR_CHECK(nand_wrap_read(flash, i, 0, page_size, temp_buf));\n        } else {\n            ESP_ERROR_CHECK(spi_nand_flash_read_page(flash, temp_buf, i));\n        }\n        read_time += esp_timer_get_time() - start;\n    }\n    free(pattern_buf);\n    free(temp_buf);\n\n    ESP_LOGI(TAG, \"Wrote %\" PRIu32 \" bytes in %\" PRId64 \" us, avg %.2f kB/s\", page_size * page_count, write_time, (float)page_size * page_count / write_time * 1000);\n    ESP_LOGI(TAG, \"Read %\" PRIu32 \" bytes in %\" PRId64 \" us, avg %.2f kB/s\\n\", page_size * page_count, read_time, (float)page_size * page_count / read_time * 1000);\n    return ret;\n}\n\nvoid app_main(void)\n{\n    // Set up SPI bus and initialize the external SPI Flash chip\n    spi_device_handle_t spi;\n    spi_nand_flash_device_t *flash;\n    example_init_nand_flash(&flash, &spi);\n    if (flash == NULL) {\n        return;\n    }\n\n    uint32_t num_blocks;\n    ESP_ERROR_CHECK(spi_nand_flash_get_block_num(flash, &num_blocks));\n\n    // Get bad block statistics\n    uint32_t bad_block_count;\n    ESP_LOGI(TAG, \"Get bad block statistics:\");\n    ESP_ERROR_CHECK(nand_get_bad_block_stats(flash, &bad_block_count));\n    ESP_LOGI(TAG, \"\\nTotal number of Blocks: %\"PRIu32\"\\nBad Blocks: %\"PRIu32\"\\nValid Blocks: %\"PRIu32\"\\n\",\n             num_blocks, bad_block_count, num_blocks - bad_block_count);\n\n    // Calculate read and write throughput via Dhara\n    uint32_t start_page = 1;\n    uint16_t page_count = 1000;\n    bool get_raw_tp = false;\n    ESP_LOGI(TAG, \"Read-Write Throughput via Dhara:\");\n    ESP_ERROR_CHECK(read_write_pages_tp(flash, start_page, page_count, get_raw_tp));\n\n    // Calculate read and write throughput at lower level (bypassing Dhara)\n    start_page = 1001;\n    page_count = 1000;\n    get_raw_tp = true;\n    ESP_LOGI(TAG, \"Read-Write Throughput at lower level (bypassing Dhara):\");\n    ESP_ERROR_CHECK(read_write_pages_tp(flash, start_page, page_count, get_raw_tp));\n\n    // Get ECC error statistics\n    ESP_LOGI(TAG, \"ECC errors statistics:\");\n    ESP_ERROR_CHECK(nand_get_ecc_stats(flash));\n\n    example_deinit_nand_flash(flash, spi);\n}\n"
  },
  {
    "path": "spi_nand_flash_fatfs/examples/nand_flash_debug_app/pytest_nand_flash_debug_example.py",
    "content": "# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nfrom pytest_embedded_idf.utils import idf_parametrize\nimport glob\nfrom pathlib import Path\n\n\n@pytest.mark.spi_nand_flash\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that not build\"\n)\n@idf_parametrize('target', ['esp32'], indirect=['target'])\ndef test_nand_flash_debug_example(dut) -> None:\n    dut.expect_exact(\"Get bad block statistics:\")\n    dut.expect_exact(\"Read-Write Throughput via Dhara:\")\n    dut.expect_exact(\"Read-Write Throughput at lower level (bypassing Dhara):\")\n    dut.expect_exact(\"ECC errors statistics:\")\n    dut.expect_exact(\"Returned from app_main\")\n"
  },
  {
    "path": "spi_nand_flash_fatfs/examples/nand_flash_debug_app/sdkconfig.defaults",
    "content": "CONFIG_NAND_FLASH_VERIFY_WRITE=y\nCONFIG_ESP_TASK_WDT_EN=n\n"
  },
  {
    "path": "spi_nand_flash_fatfs/idf_component.yml",
    "content": "version: \"1.0.0\"\ndescription: \"FATFS integration for SPI NAND Flash\"\nurl: https://github.com/espressif/idf-extra-components/tree/master/spi_nand_flash_fatfs\nissues: https://github.com/espressif/idf-extra-components/issues\nrepository: https://github.com/espressif/idf-extra-components.git\ndocumentation: https://github.com/espressif/idf-extra-components/tree/master/spi_nand_flash_fatfs/README.md\n\ndependencies:\n  idf:\n    version: \">=5.0\"\n  espressif/spi_nand_flash:\n    version: \"*\"\n    override_path: \"../spi_nand_flash\"\n"
  },
  {
    "path": "spi_nand_flash_fatfs/include/diskio_nand.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 mikkeldamsgaard project\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * SPDX-FileContributor: 2015-2023 Espressif Systems (Shanghai) CO LTD\n */\n\n#pragma once\n\n#include \"spi_nand_flash.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * Register NAND flash diskio driver\n *\n * @param pdrv  drive number\n * @param device pointer to a nand flash device structure; device should be initialized before calling f_mount.\n */\nesp_err_t ff_diskio_register_nand(BYTE pdrv, spi_nand_flash_device_t *device);\n\n/**\n * @brief Get the driver number corresponding to a device\n *\n * @param device The device for which to return its driver\n * @return Driver number of the device\n */\nBYTE ff_diskio_get_pdrv_nand(const spi_nand_flash_device_t *device);\n\n/**\n * @brief Clear a registered nand driver, so it can be reused\n *\n * @param device The device for which to clear its registration\n */\nvoid ff_diskio_clear_pdrv_nand(const spi_nand_flash_device_t *dev);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "spi_nand_flash_fatfs/include/esp_vfs_fat_nand.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 mikkeldamsgaard project\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * SPDX-FileContributor: 2015-2023 Espressif Systems (Shanghai) CO LTD\n */\n\n#pragma once\n#include <stddef.h>\n#include \"spi_nand_flash.h\"\n#include \"esp_err.h\"\n#include \"esp_vfs_fat.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @brief Convenience function to initialize FAT filesystem in SPI nand flash and register it in VFS\n *\n * This is an all-in-one function which does the following:\n *\n * - mounts FAT partition using FATFS library on top of nand flash\n * - registers FATFS library with VFS, with prefix given by base_prefix variable\n *\n * @param base_path        path where FATFS partition should be mounted (e.g. \"/nandflash\")\n * @param nand_device      nand device handle returned by spi_nand_flash_init_device\n * @param mount_config     pointer to structure with extra parameters for mounting FATFS\n * @return\n *      - ESP_OK on success\n *      - ESP_ERR_NOT_FOUND if there are no more free fatfs slots\n *      - ESP_ERR_INVALID_STATE if esp_vfs_fat_nand_mount was already called\n *      - ESP_ERR_NO_MEM if memory can not be allocated\n *      - other error codes from nand driver, SPI flash driver, or FATFS drivers\n */\nesp_err_t esp_vfs_fat_nand_mount(const char *base_path,\n                                 spi_nand_flash_device_t *nand_device,\n                                 const esp_vfs_fat_mount_config_t *mount_config);\n\n/**\n * @brief Unmount FAT filesystem and release resources acquired using esp_vfs_fat_nand_mount\n *\n * @param base_path  path where nand flash is mounted\n * @param nand_device  nand device handle used in mount\n *\n * @return\n *      - ESP_OK on success\n *      - ESP_ERR_INVALID_STATE if esp_vfs_fat_nand_mount hasn't been called\n */\n\nesp_err_t esp_vfs_fat_nand_unmount(const char *base_path, spi_nand_flash_device_t *nand_device);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "spi_nand_flash_fatfs/src/diskio_nand.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 mikkeldamsgaard project\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * SPDX-FileContributor: 2015-2023 Espressif Systems (Shanghai) CO LTD\n */\n\n#include \"diskio.h\"\n#include \"esp_log.h\"\n#include \"esp_check.h\"\n#include \"diskio_nand.h\"\n#include \"spi_nand_flash.h\"\n#include \"diskio_impl.h\"\n\nstatic const char *TAG = \"diskio_nand\";\n\nstatic spi_nand_flash_device_t *ff_nand_handles[FF_VOLUMES] = {NULL};\n\nDSTATUS ff_nand_initialize(BYTE pdrv)\n{\n    return 0;\n}\n\nDSTATUS ff_nand_status(BYTE pdrv)\n{\n    return 0;\n}\n\nDRESULT ff_nand_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count)\n{\n    ESP_LOGV(TAG, \"ff_nand_read - pdrv=%i, sector=%lu, count=%u\", (unsigned int) pdrv, (unsigned long) sector,\n             (unsigned int) count);\n    esp_err_t ret;\n    uint32_t page_size;\n    spi_nand_flash_device_t *dev = ff_nand_handles[pdrv];\n    assert(dev);\n\n    ESP_GOTO_ON_ERROR(spi_nand_flash_get_page_size(dev, &page_size), fail, TAG, \"\");\n\n    for (uint32_t i = 0; i < count; i++) {\n        ESP_GOTO_ON_ERROR(spi_nand_flash_read_page(dev, buff + i * page_size, sector + i),\n                          fail, TAG, \"spi_nand_flash_read_page failed\");\n    }\n\n    return RES_OK;\n\nfail:\n    ESP_LOGE(TAG, \"ff_nand_read failed with error 0x%X\", ret);\n    return RES_ERROR;\n}\n\nDRESULT ff_nand_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)\n{\n    ESP_LOGV(TAG, \"ff_nand_write - pdrv=%i, sector=%lu, count=%u\", (unsigned int) pdrv, (unsigned long) sector,\n             (unsigned int) count);\n    esp_err_t ret;\n    uint32_t page_size;\n    spi_nand_flash_device_t *dev = ff_nand_handles[pdrv];\n    assert(dev);\n\n    ESP_GOTO_ON_ERROR(spi_nand_flash_get_page_size(dev, &page_size), fail, TAG, \"\");\n\n    for (uint32_t i = 0; i < count; i++) {\n        ESP_GOTO_ON_ERROR(spi_nand_flash_write_page(dev, buff + i * page_size, sector + i),\n                          fail, TAG, \"spi_nand_flash_write_page failed\");\n    }\n    return RES_OK;\n\nfail:\n    ESP_LOGE(TAG, \"ff_nand_write failed with error 0x%X\", ret);\n    return RES_ERROR;\n}\n\n#if FF_USE_TRIM\nDRESULT ff_nand_trim(BYTE pdrv, DWORD start_sector, DWORD sector_count)\n{\n    esp_err_t ret;\n    spi_nand_flash_device_t *dev = ff_nand_handles[pdrv];\n    assert(dev);\n\n    uint32_t num_pages;\n    ESP_GOTO_ON_ERROR(spi_nand_flash_get_page_count(dev, &num_pages),\n                      fail, TAG, \"get_page_count failed\");\n\n    if ((start_sector > num_pages) || ((start_sector + sector_count) > num_pages)) {\n        return RES_PARERR;\n    }\n\n    for (uint32_t i = 0; i < sector_count; i++) {\n        ESP_GOTO_ON_ERROR(spi_nand_flash_trim(dev, start_sector + i),\n                          fail, TAG, \"spi_nand_flash_trim failed\");\n    }\n    return RES_OK;\n\nfail:\n    ESP_LOGE(TAG, \"ff_nand_trim failed with error 0x%X\", ret);\n    return RES_ERROR;\n}\n#endif //FF_USE_TRIM\n\nDRESULT ff_nand_ioctl(BYTE pdrv, BYTE cmd, void *buff)\n{\n    spi_nand_flash_device_t *dev = ff_nand_handles[pdrv];\n    assert(dev);\n\n    ESP_LOGV(TAG, \"ff_nand_ioctl: cmd=%i\", cmd);\n    esp_err_t ret = ESP_OK;\n    switch (cmd) {\n    case CTRL_SYNC:\n        ESP_GOTO_ON_ERROR(spi_nand_flash_sync(dev), fail, TAG, \"sync failed\");\n        break;\n    case GET_SECTOR_COUNT: {\n        uint32_t num_pages;\n        ESP_GOTO_ON_ERROR(spi_nand_flash_get_page_count(dev, &num_pages),\n                          fail, TAG, \"get_page_count failed\");\n        *((DWORD *)buff) = num_pages;\n        ESP_LOGV(TAG, \"capacity=%\"PRIu32\" pages\", num_pages);\n        break;\n    }\n    case GET_SECTOR_SIZE: {\n        uint32_t page_size;\n        ESP_GOTO_ON_ERROR(spi_nand_flash_get_page_size(dev, &page_size),\n                          fail, TAG, \"get_page_size failed\");\n\n        *((WORD *)buff) = (WORD)page_size;\n        ESP_LOGV(TAG, \"page size=%u\", (unsigned)page_size);\n        break;\n    }\n#if FF_USE_TRIM\n    case CTRL_TRIM: {\n        DWORD start_sector = *((DWORD *)buff);\n        DWORD end_sector = *((DWORD *)buff + 1) + 1;\n        DWORD sector_count = end_sector - start_sector;\n        return ff_nand_trim(pdrv, start_sector, sector_count);\n    }\n#endif //FF_USE_TRIM\n    default:\n        return RES_ERROR;\n    }\n    return RES_OK;\n\nfail:\n    ESP_LOGE(TAG, \"ff_nand_ioctl cmd=%i, failed with error=0x%X\", cmd, ret);\n    return RES_ERROR;\n}\n\nesp_err_t ff_diskio_register_nand(BYTE pdrv, spi_nand_flash_device_t *device)\n{\n    if (pdrv >= FF_VOLUMES) {\n        return ESP_ERR_INVALID_ARG;\n    }\n\n    static const ff_diskio_impl_t nand_impl = {\n        .init = &ff_nand_initialize,\n        .status = &ff_nand_status,\n        .read = &ff_nand_read,\n        .write = &ff_nand_write,\n        .ioctl = &ff_nand_ioctl\n    };\n    ff_nand_handles[pdrv] = device;\n    ff_diskio_register(pdrv, &nand_impl);\n    return ESP_OK;\n}\n\nBYTE ff_diskio_get_pdrv_nand(const spi_nand_flash_device_t *dev)\n{\n    for (int i = 0; i < FF_VOLUMES; i++) {\n        if (dev == ff_nand_handles[i]) {\n            return i;\n        }\n    }\n    return 0xff;\n}\n\nvoid ff_diskio_clear_pdrv_nand(const spi_nand_flash_device_t *dev)\n{\n    for (int i = 0; i < FF_VOLUMES; i++) {\n        if (dev == ff_nand_handles[i]) {\n            ff_nand_handles[i] = NULL;\n        }\n    }\n}\n"
  },
  {
    "path": "spi_nand_flash_fatfs/src/vfs_fat_spinandflash.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 mikkeldamsgaard project\n *\n * SPDX-License-Identifier: Apache-2.0\n *\n * SPDX-FileContributor: 2015-2023 Espressif Systems (Shanghai) CO LTD\n */\n\n#include <stdlib.h>\n#include <string.h>\n#include <esp_check.h>\n#include \"esp_log.h\"\n#include \"esp_vfs.h\"\n#include \"esp_vfs_fat.h\"\n#include \"spi_nand_flash.h\"\n#include \"vfs_fat_internal.h\"\n#include \"diskio_impl.h\"\n#include \"diskio_nand.h\"\n\nstatic const char *TAG = \"vfs_fat_nand\";\n\nesp_err_t esp_vfs_fat_nand_mount(const char *base_path, spi_nand_flash_device_t *nand_device,\n                                 const esp_vfs_fat_mount_config_t *mount_config)\n{\n    esp_err_t ret = ESP_OK;\n    void *workbuf = NULL;\n    FATFS *fs = NULL;\n    uint32_t page_size;\n    const size_t workbuf_size = 4096;\n\n    // connect driver to FATFS\n    BYTE pdrv = 0xFF;\n    ESP_GOTO_ON_ERROR(ff_diskio_get_drive(&pdrv), fail, TAG, \"the maximum count of volumes is already mounted\");\n    ESP_LOGD(TAG, \"using pdrv=%i\", pdrv);\n    char drv[3] = {(char)('0' + pdrv), ':', 0};\n\n    ESP_GOTO_ON_ERROR(ff_diskio_register_nand(pdrv, nand_device),\n                      fail, TAG, \"ff_diskio_register_nand failed drv=%i\", pdrv);\n\n    ESP_GOTO_ON_ERROR(spi_nand_flash_get_page_size(nand_device, &page_size), fail, TAG, \"\");\n\n#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)\n    esp_vfs_fat_conf_t conf = {\n        .base_path = base_path,\n        .fat_drive = drv,\n        .max_files = mount_config->max_files,\n    };\n    ESP_GOTO_ON_ERROR(esp_vfs_fat_register_cfg(&conf, &fs), fail, TAG, \"esp_vfs_fat_register failed\");\n#else\n    ESP_GOTO_ON_ERROR(esp_vfs_fat_register(base_path, drv, mount_config->max_files, &fs),\n                      fail, TAG, \"esp_vfs_fat_register failed\");\n#endif\n\n    // Try to mount partition\n    FRESULT fresult = f_mount(fs, drv, 1);\n    if (fresult != FR_OK) {\n        ESP_LOGW(TAG, \"f_mount failed (%d)\", fresult);\n        if (!((fresult == FR_NO_FILESYSTEM || fresult == FR_INT_ERR)\n                && mount_config->format_if_mount_failed)) {\n            ret = ESP_FAIL;\n            goto fail;\n        }\n\n        workbuf = ff_memalloc(workbuf_size);\n        if (workbuf == NULL) {\n            ret = ESP_ERR_NO_MEM;\n            goto fail;\n        }\n        size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size(\n                                     page_size,\n                                     mount_config->allocation_unit_size);\n        ESP_LOGI(TAG, \"Formatting FATFS partition, allocation unit size=%d\", alloc_unit_size);\n        const MKFS_PARM opt = {(BYTE)FM_ANY, 0, 0, 0, alloc_unit_size};\n        fresult = f_mkfs(drv, &opt, workbuf, workbuf_size);\n        if (fresult != FR_OK) {\n            ret = ESP_FAIL;\n            ESP_LOGE(TAG, \"f_mkfs failed (%d)\", fresult);\n            goto fail;\n        }\n        free(workbuf);\n        workbuf = NULL;\n        ESP_LOGI(TAG, \"Mounting again\");\n        fresult = f_mount(fs, drv, 0);\n        if (fresult != FR_OK) {\n            ret = ESP_FAIL;\n            ESP_LOGE(TAG, \"f_mount failed after formatting (%d)\", fresult);\n            goto fail;\n        }\n    }\n    return ESP_OK;\n\nfail:\n    if (workbuf) {\n        free(workbuf);\n    }\n    if (fs) {\n        esp_vfs_fat_unregister_path(base_path);\n    }\n    ff_diskio_unregister(pdrv);\n    return ret;\n}\n\nesp_err_t esp_vfs_fat_nand_unmount(const char *base_path, spi_nand_flash_device_t *nand_device)\n{\n    BYTE pdrv = ff_diskio_get_pdrv_nand(nand_device);\n    if (pdrv == 0xff) {\n        return ESP_ERR_INVALID_STATE;\n    }\n\n    char drv[3] = {(char)('0' + pdrv), ':', 0};\n    f_mount(NULL, drv, 0);\n\n    ff_diskio_unregister(pdrv);\n    ff_diskio_clear_pdrv_nand(nand_device);\n\n    esp_err_t err = esp_vfs_fat_unregister_path(base_path);\n    return err;\n}\n\n"
  },
  {
    "path": "supertinycron/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"supertinycron/ccronexpr.c\"\n                    INCLUDE_DIRS \"supertinycron/\")\n\ntarget_compile_definitions(${COMPONENT_TARGET} PRIVATE \"-DCRON_USE_LOCAL_TIME\")\nif(CONFIG_CRON_DISABLE_YEARS)\n    target_compile_definitions(${COMPONENT_TARGET} PRIVATE \"-DCRON_DISABLE_YEARS\")\nendif()\ntarget_compile_options(${COMPONENT_LIB} PRIVATE -Wno-char-subscripts)\n"
  },
  {
    "path": "supertinycron/Kconfig",
    "content": "menu \"CRON Expression Parser\"\n\n    config CRON_DISABLE_YEARS\n        bool \"Disable support for parsing years\"\n        default n\n        help\n            When this option is selected, year parsing support will be disabled,\n            reducing memory footprint for cron_expr by 29 bytes. The library will\n            still accept the year field. However, the field will not be validated\n            and the cron event will be triggered every year.\n\nendmenu\n"
  },
  {
    "path": "supertinycron/LICENSE.txt",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2015, staticlibs.net\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "supertinycron/README.md",
    "content": "## Cron expression parsing in ANSI C\n\nGiven a cron expression and a date, you can get the next date which satisfies the cron expression. The more details please refer to [README.md](https://github.com/espressif/idf-extra-components/blob/master/supertinycron/supertinycron/README.md)\n\n## Usage Example\n\nRefer to [cron_example](https://github.com/espressif/idf-extra-components/blob/master/supertinycron/examples/cron_example)\n\n## API Reference\n\nTo learn more about how to use this component, please check API Documentation from header file [ccronexpr.h](https://github.com/espressif/idf-extra-components/blob/master/supertinycron/supertinycron/ccronexpr.h)\n\n## License\n\nThis project is released under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0).\n"
  },
  {
    "path": "supertinycron/examples/cron_example/CMakeLists.txt",
    "content": "# For more information about build system see\n# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html\n# The following five lines of boilerplate have to be in your project's\n# CMakeLists in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\n\nset(COMPONENTS main)\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nproject(cron_example)\n"
  },
  {
    "path": "supertinycron/examples/cron_example/README.md",
    "content": "# Cron expression parsing example\n\nThis example can be used to run cron expression parsing on an Espressif chip.\n\nThe example doesn't require any special hardware and can run on any development board.\n\n## Building and running\n\nRun the application as usual for an ESP-IDF project. For example, for ESP32-C3:\n```\nidf.py set-target esp32c3\nidf.py -p PORT flash monitor\n```\n\nAfter launching, the benchmark takes a few seconds to run, please be patient.\n"
  },
  {
    "path": "supertinycron/examples/cron_example/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS cron_example_main.c\n                       PRIV_REQUIRES supertinycron)\n"
  },
  {
    "path": "supertinycron/examples/cron_example/main/cron_example_main.c",
    "content": "/*\n * Copyright 2015, alex at staticlibs.net\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * File:   CronExprParser_test.cpp\n * Author: alex\n *\n * Created on February 24, 2015, 9:36 AM\n */\n\n#include <assert.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <limits.h>\n\n#include \"ccronexpr.h\"\n#include \"sdkconfig.h\"\n\n#define MAX_SECONDS 62\n#define CRON_MAX_MINUTES 60\n#define CRON_MAX_HOURS 24\n#define CRON_MAX_DAYS_OF_WEEK 8\n#define CRON_MAX_DAYS_OF_MONTH 32\n#define CRON_MAX_MONTHS 12\n\n#define DATE_FORMAT \"%Y-%m-%d_%H:%M:%S\"\n\n#ifndef ARRAY_LEN\n#define ARRAY_LEN(x) sizeof(x)/sizeof(x[0])\n#endif\n\n/* declared in cronexpr.c */\ntime_t cron_mktime(struct tm *tm);\n\n/**\n * uint8_t* replace char* for storing hit dates, set_bit and get_bit are used as handlers\n */\nuint8_t cron_get_bit(const uint8_t *rbyte, int idx);\nvoid cron_set_bit(uint8_t *rbyte, int idx);\nvoid cron_del_bit(uint8_t *rbyte, int idx);\n\nstatic int crons_equal(cron_expr *cr1, cron_expr *cr2)\n{\n    unsigned int i;\n    for (i = 0; i < ARRAY_LEN(cr1->seconds); i++) {\n        if (cr1->seconds[i] != cr2->seconds[i]) {\n            printf(\"seconds not equal @%d %02x != %02x\", i, cr1->seconds[i], cr2->seconds[i]);\n            return 0;\n        }\n    }\n    for (i = 0; i < ARRAY_LEN(cr1->minutes); i++) {\n        if (cr1->minutes[i] != cr2->minutes[i]) {\n            printf(\"minutes not equal @%d %02x != %02x\", i, cr1->minutes[i], cr2->minutes[i]);\n            return 0;\n        }\n    }\n    for (i = 0; i < ARRAY_LEN(cr1->hours); i++) {\n        if (cr1->hours[i] != cr2->hours[i]) {\n            printf(\"hours not equal @%d %02x != %02x\", i, cr1->hours[i], cr2->hours[i]);\n            return 0;\n        }\n    }\n    for (i = 0; i < ARRAY_LEN(cr1->days_of_week); i++) {\n        if (cr1->days_of_week[i] != cr2->days_of_week[i]) {\n            printf(\"days_of_week not equal @%d %02x != %02x\", i, cr1->days_of_week[i], cr2->days_of_week[i]);\n            return 0;\n        }\n    }\n    for (i = 0; i < ARRAY_LEN(cr1->days_of_month); i++) {\n        if (cr1->days_of_month[i] != cr2->days_of_month[i]) {\n            printf(\"days_of_month not equal @%d %02x != %02x\", i, cr1->days_of_month[i], cr2->days_of_month[i]);\n            return 0;\n        }\n    }\n    for (i = 0; i < ARRAY_LEN(cr1->months); i++) {\n        if (cr1->months[i] != cr2->months[i]) {\n            printf(\"months not equal @%d %02x != %02x\", i, cr1->months[i], cr2->months[i]);\n            return 0;\n        }\n    }\n    return 1;\n}\n\nint one_dec_num(const char ch)\n{\n    switch (ch) {\n    case '0':\n        return 0;\n    case '1':\n        return 1;\n    case '2':\n        return 2;\n    case '3':\n        return 3;\n    case '4':\n        return 4;\n    case '5':\n        return 5;\n    case '6':\n        return 6;\n    case '7':\n        return 7;\n    case '8':\n        return 8;\n    case '9':\n        return 9;\n    default:\n        return -1;\n    }\n}\n\nint extract_digits(const char *str, int *digit_count)\n{\n    int num = 0;\n    if (!str || !digit_count) {\n        return 0;\n    }\n    while (*str) {\n        (*digit_count)++;\n        if (*str >= '0' && *str <= '9') {\n            num = num * 10 + (*str - '0');\n        } else {\n            break;\n        }\n        str++;\n    }\n    return num;\n}\n\n/* strptime is not available in msvc */\n/* 2012-07-01_09:53:50 */\n/* 0123456789012345678 */\nvoid poors_mans_strptime(const char *str, struct tm *cal)\n{\n    int count = 0;\n    assert(cal != NULL);\n    memset(cal, 0, sizeof(struct tm));\n    cal->tm_year = extract_digits(str, &count) - 1900;\n    cal->tm_mon = extract_digits(str + count, &count) - 1;\n    cal->tm_mday = extract_digits(str + count, &count);\n    cal->tm_wday = 0;\n    cal->tm_yday = 0;\n    cal->tm_hour = extract_digits(str + count, &count);\n    cal->tm_min = extract_digits(str + count, &count);\n    cal->tm_sec = extract_digits(str + count, &count);\n    cal->tm_isdst = -1;\n}\n\ntypedef time_t (*cron_find_fn)(cron_expr *, time_t);\n\nint count_fields(const char *str, char del)\n{\n    size_t count = 0;\n    if (!str) {\n        return -1;\n    }\n    while ((str = strchr(str, del)) != NULL) {\n        count++;\n        do {\n            str++;\n        } while (del == *str);\n    }\n    return (int)count + 1;\n}\n\n#define check_fn(fn_fn,pattern,initial,expected) check_fn_line(fn_fn, pattern, initial, expected, __LINE__)\nvoid check_fn_line(cron_find_fn fn, const char *pattern, const char *initial, const char *expected, int line)\n{\n    const char *err = NULL;\n    const int len = count_fields(pattern, ' ');\n    cron_expr parsed1, parsed2;\n    /*printf(\"Pattern: %s\\n\", pattern);**/\n    cron_parse_expr(pattern, &parsed1, &err);\n\n    struct tm calinit;\n    poors_mans_strptime(initial, &calinit);\n    time_t dateinit = cron_mktime(&calinit);\n    assert(-1 != dateinit);\n    time_t datenext = fn(&parsed1, dateinit);\n#ifdef CRON_USE_LOCAL_TIME\n    struct tm *calnext = localtime(&datenext);\n#else\n    struct tm *calnext = gmtime(&datenext);\n#endif\n    assert(calnext);\n    char *buffer = (char *) malloc(512);\n    memset(buffer, 0, 512);\n    strftime(buffer, 512, DATE_FORMAT, calnext);\n    printf(\"parsed: %s\\n\", pattern);\n    if (0 != strcmp(expected, buffer + (buffer[0] == '+' ? 1 : 0))) {\n        printf(\"Line: %d\\n\", line);\n        printf(\"Pattern: %s\\n\", pattern);\n        printf(\"Initial: %s\\n\", initial);\n        printf(\"Expected: %s\\n\", expected);\n        printf(\"Actual: %s\\n\", buffer);\n        assert(0);\n    }\n    assert(cron_generate_expr(&parsed1, buffer, 512, len, &err) > 0);\n    if (0 != strcmp(pattern, buffer)) {\n        printf(\"Line: %d\\n\", line);\n        printf(\"Pattern: %s\\n\", pattern);\n        printf(\"Actual:  %s\\n\", buffer);\n    }\n    cron_parse_expr(buffer, &parsed2, &err);\n    assert(crons_equal(&parsed1, &parsed2));\n    free(buffer);\n}\n\nvoid check_same(const char *expr1, const char *expr2)\n{\n    cron_expr parsed1;\n    cron_parse_expr(expr1, &parsed1, NULL);\n    cron_expr parsed2;\n    cron_parse_expr(expr2, &parsed2, NULL);\n    printf(\"parsed1: %s\\n\", expr1);\n    printf(\"parsed2: %s\\n\", expr2);\n    assert(crons_equal(&parsed1, &parsed2));\n}\n\nvoid check_calc_invalid(void)\n{\n    cron_expr parsed;\n    cron_parse_expr(\"0 0 0 31 6 *\", &parsed, NULL);\n    struct tm calinit;\n    poors_mans_strptime(\"2012-07-01_09:53:50\", &calinit);\n    time_t dateinit = cron_mktime(&calinit);\n    time_t res = cron_next(&parsed, dateinit);\n    assert(CRON_INVALID_INSTANT == res);\n}\n\nvoid check_expr_invalid(const char *pattern)\n{\n    const char *err = NULL;\n    cron_expr parsed1;\n    cron_parse_expr(pattern, &parsed1, &err);\n    printf(\"parsed1: %s\\n\", pattern);\n    if (err) {\n        printf(\"check_expr_invalid: %s\\n\", err);\n    }\n    assert(err);\n}\n\n#define check_expr_valid(pattern) check_expr_valid_line(pattern, __LINE__)\nvoid check_expr_valid_line(const char *pattern, int line)\n{\n    const char *err = NULL;\n    const int len = count_fields(pattern, ' ');\n    cron_expr parsed1, parsed2;\n    cron_parse_expr(pattern, &parsed1, &err);\n    printf(\"parsed1: %s\\n\", pattern);\n    if (err) {\n        printf(\"check_expr_invalid: %s\\n\", err);\n    }\n    char *buffer = (char *) malloc(512);\n    memset(buffer, 0, 512);\n    assert(cron_generate_expr(&parsed1, buffer, 512, len, &err) > 0);\n    if (0 != strcmp(pattern, buffer)) {\n        printf(\"Line: %d\\n\", line);\n        printf(\"Pattern: %s\\n\", pattern);\n        printf(\"Actual:  %s\\n\", buffer);\n    }\n    cron_parse_expr(buffer, &parsed2, &err);\n    assert(crons_equal(&parsed1, &parsed2));\n\n    assert(!err);\n}\n\nvoid test_expr(void)\n{\n    char *tz = getenv(\"TZ\");\n    /*Test leap seconds - nejsou nastavené hodnoty, co se kontrolují */\n    /*Test leap seconds\n    check_fn(cron_next, \"60 0 0 * * *\", \"2015-01-01_15:12:42\", \"2015-06-30_00:00:00\");*/\n    check_fn(cron_next, \"* * * * * *\", \"2100-01-01_15:12:42\", \"2100-01-01_15:12:43\");\n    check_fn(cron_next, \"* * * * * *\", \"2198-01-01_15:12:42\", \"2198-01-01_15:12:43\");\n    check_fn(cron_next, \"* * * * * *\", \"2199-01-01_15:12:42\", \"2199-01-01_15:12:43\");\n    if (tz && !strcmp(\"right/UTC\", tz)) {\n        check_fn(cron_next, \"L59 * * * * *\", \"2016-12-31_23:50:00\", \"2016-12-31_23:50:59\");\n        check_fn(cron_next, \"L60 * * * * *\", \"2016-12-31_23:50:00\", \"2016-12-31_23:59:60\");\n        check_fn(cron_next, \"L60 * * * * *\", \"2016-12-31_23:59:59\", \"2016-12-31_23:59:60\");\n    }\n\n    check_fn(cron_next, \"* * * 1 1 * *\", \"1970-01-01_15:12:42\", \"1970-01-01_15:12:43\");\n\n#ifndef CONFIG_CRON_DISABLE_YEARS\n    check_fn(cron_next, \"* * * 1 1 * 1970,2100,2193,2199\", \"1970-01-01_15:12:42\", \"1970-01-01_15:12:43\");\n    /*check_fn(cron_next, \"* * * 1 1 * 1969,2100,2193,2199\", \"1969-01-01_15:12:42\", \"1969-01-01_15:12:43\");*/\n    check_fn(cron_next, \"* * * 1 1 * 1970,2100,2193,2199\", \"1971-01-01_15:12:42\", \"2100-01-01_00:00:00\");\n    check_fn(cron_next, \"* * * 1 1 * 1970,2100,2193,2199\", \"2195-01-01_15:12:42\", \"2199-01-01_00:00:00\");\n    /*check_fn(cron_next, \"* * * 1 1 * 1970,2100,2193,2200\", \"2195-01-01_15:12:42\", \"2200-01-01_00:00:00\");*/\n    check_fn(cron_next, \"* * * 1 1 * 2020\", \"2011-01-01_15:12:42\", \"2020-01-01_00:00:00\");\n#endif\n\n    check_fn(cron_next, \"* * * 1W * *\", \"2011-01-01_15:12:42\", \"2011-01-03_00:00:00\");\n    check_fn(cron_next, \"* * * 31W * *\", \"2010-01-01_15:12:42\", \"2010-01-29_00:00:00\");\n\n    check_fn(cron_next, \"* * * LW * *\", \"2010-01-01_15:12:42\", \"2010-01-29_00:00:00\");\n    check_fn(cron_next, \"* * * LW * *\", \"2010-02-03_15:12:42\", \"2010-02-26_00:00:00\");\n    check_fn(cron_next, \"* * * LW * *\", \"2010-03-06_15:12:42\", \"2010-03-31_00:00:00\");\n    check_fn(cron_next, \"* * * LW * *\", \"2010-04-09_15:12:42\", \"2010-04-30_00:00:00\");\n    check_fn(cron_next, \"* * * LW * *\", \"2010-05-12_15:12:42\", \"2010-05-31_00:00:00\");\n    check_fn(cron_next, \"* * * LW * *\", \"2010-06-15_15:12:42\", \"2010-06-30_00:00:00\");\n    check_fn(cron_next, \"* * * LW * *\", \"2010-07-18_15:12:42\", \"2010-07-30_00:00:00\");\n    check_fn(cron_next, \"* * * LW * *\", \"2010-08-21_15:12:42\", \"2010-08-31_00:00:00\");\n    check_fn(cron_next, \"* * * LW * *\", \"2010-09-24_15:12:42\", \"2010-09-30_00:00:00\");\n    check_fn(cron_next, \"* * * LW * *\", \"2010-10-27_15:12:42\", \"2010-10-29_00:00:00\");\n    check_fn(cron_next, \"* * * LW * *\", \"2010-11-30_15:12:42\", \"2010-11-30_15:12:43\");\n    check_fn(cron_next, \"* * * LW * *\", \"2010-12-31_15:12:42\", \"2010-12-31_15:12:43\");\n\n    check_fn(cron_next, \"* * * 15W * *\", \"2010-01-01_15:12:42\", \"2010-01-15_00:00:00\");\n    check_fn(cron_next, \"* * * 15W * *\", \"2010-02-03_15:12:42\", \"2010-02-15_00:00:00\");\n    check_fn(cron_next, \"* * * 15W * *\", \"2010-03-06_15:12:42\", \"2010-03-15_00:00:00\");\n    check_fn(cron_next, \"* * * 15W * *\", \"2010-04-09_15:12:42\", \"2010-04-15_00:00:00\");\n    check_fn(cron_next, \"* * * 15W * *\", \"2010-05-12_15:12:42\", \"2010-05-14_00:00:00\");\n    check_fn(cron_next, \"* * * 15W * *\", \"2010-06-15_15:12:42\", \"2010-06-15_15:12:43\");\n    check_fn(cron_next, \"* * * 15W * *\", \"2010-07-18_15:12:42\", \"2010-08-16_00:00:00\");\n    check_fn(cron_next, \"* * * 15W * *\", \"2010-08-21_15:12:42\", \"2010-09-15_00:00:00\");\n    check_fn(cron_next, \"* * * 15W * *\", \"2010-09-24_15:12:42\", \"2010-10-15_00:00:00\");\n    check_fn(cron_next, \"* * * 15W * *\", \"2010-10-27_15:12:42\", \"2010-11-15_00:00:00\");\n    check_fn(cron_next, \"* * * 15W * *\", \"2010-11-30_15:12:42\", \"2010-12-15_00:00:00\");\n    check_fn(cron_next, \"* * * 15W * *\", \"2010-12-31_15:12:42\", \"2011-01-14_00:00:00\");\n\n    check_fn(cron_next, \"* * * L-1 * *\", \"2010-01-01_15:12:42\", \"2010-01-30_00:00:00\");\n    check_fn(cron_next, \"* * * L-1 * *\", \"2010-02-03_15:12:42\", \"2010-02-27_00:00:00\");\n    check_fn(cron_next, \"* * * L-1 * *\", \"2010-03-06_15:12:42\", \"2010-03-30_00:00:00\");\n    check_fn(cron_next, \"* * * L-1 * *\", \"2010-04-09_15:12:42\", \"2010-04-29_00:00:00\");\n    check_fn(cron_next, \"* * * L-1 * *\", \"2010-05-12_15:12:42\", \"2010-05-30_00:00:00\");\n    check_fn(cron_next, \"* * * L-1 * *\", \"2010-06-15_15:12:42\", \"2010-06-29_00:00:00\");\n    check_fn(cron_next, \"* * * L-1 * *\", \"2010-07-18_15:12:42\", \"2010-07-30_00:00:00\");\n    check_fn(cron_next, \"* * * L-1 * *\", \"2010-08-21_15:12:42\", \"2010-08-30_00:00:00\");\n    check_fn(cron_next, \"* * * L-1 * *\", \"2010-09-24_15:12:42\", \"2010-09-29_00:00:00\");\n    check_fn(cron_next, \"* * * L-1 * *\", \"2010-10-27_15:12:42\", \"2010-10-30_00:00:00\");\n    check_fn(cron_next, \"* * * L-1 * *\", \"2010-11-30_15:12:42\", \"2010-12-30_00:00:00\");\n    check_fn(cron_next, \"* * * L-1 * *\", \"2010-12-31_15:12:42\", \"2011-01-30_00:00:00\");\n\n    check_fn(cron_next, \"* * * L * *\", \"2010-01-01_15:12:42\", \"2010-01-31_00:00:00\");\n    check_fn(cron_next, \"* * * L * *\", \"2010-02-03_15:12:42\", \"2010-02-28_00:00:00\");\n    check_fn(cron_next, \"* * * L * *\", \"2010-03-06_15:12:42\", \"2010-03-31_00:00:00\");\n    check_fn(cron_next, \"* * * L * *\", \"2010-04-09_15:12:42\", \"2010-04-30_00:00:00\");\n    check_fn(cron_next, \"* * * L * *\", \"2010-05-12_15:12:42\", \"2010-05-31_00:00:00\");\n    check_fn(cron_next, \"* * * L * *\", \"2010-06-15_15:12:42\", \"2010-06-30_00:00:00\");\n    check_fn(cron_next, \"* * * L * *\", \"2010-07-18_15:12:42\", \"2010-07-31_00:00:00\");\n    check_fn(cron_next, \"* * * L * *\", \"2010-08-21_15:12:42\", \"2010-08-31_00:00:00\");\n    check_fn(cron_next, \"* * * L * *\", \"2010-09-24_15:12:42\", \"2010-09-30_00:00:00\");\n    check_fn(cron_next, \"* * * L * *\", \"2010-10-27_15:12:42\", \"2010-10-31_00:00:00\");\n    check_fn(cron_next, \"* * * L * *\", \"2010-11-30_15:12:42\", \"2010-11-30_15:12:43\");\n    check_fn(cron_next, \"* * * L * *\", \"2010-12-31_15:12:42\", \"2010-12-31_15:12:43\");\n\n    check_fn(cron_next, \"* * * * * 1#-5\", \"2010-09-03_15:12:42\", \"2010-11-01_00:00:00\");\n    check_fn(cron_next, \"* * * * * 1#-4\", \"2010-09-03_15:12:42\", \"2010-09-06_00:00:00\");\n    check_fn(cron_next, \"* * * * * 1#-3\", \"2010-09-03_15:12:42\", \"2010-09-13_00:00:00\");\n    check_fn(cron_next, \"* * * * * 1#-2\", \"2010-09-03_15:12:42\", \"2010-09-20_00:00:00\");\n    check_fn(cron_next, \"* * * * * 1#1\", \"2010-09-03_15:12:42\", \"2010-09-06_00:00:00\");\n    check_fn(cron_next, \"* * * * * 1#2\", \"2010-09-03_15:12:42\", \"2010-09-13_00:00:00\");\n    check_fn(cron_next, \"* * * * * 1#3\", \"2010-09-03_15:12:42\", \"2010-09-20_00:00:00\");\n    check_fn(cron_next, \"* * * * * 1#4\", \"2010-09-03_15:12:42\", \"2010-09-27_00:00:00\");\n    check_fn(cron_next, \"* * * * * 1#5\", \"2010-09-03_15:12:42\", \"2010-11-29_00:00:00\");\n\n    check_fn(cron_next, \"* * * * * 2#-5\", \"2010-09-03_15:12:42\", \"2010-11-02_00:00:00\");\n    check_fn(cron_next, \"* * * * * 2#-4\", \"2010-09-03_15:12:42\", \"2010-09-07_00:00:00\");\n    check_fn(cron_next, \"* * * * * 2#-3\", \"2010-09-03_15:12:42\", \"2010-09-14_00:00:00\");\n    check_fn(cron_next, \"* * * * * 2#-2\", \"2010-09-03_15:12:42\", \"2010-09-21_00:00:00\");\n    check_fn(cron_next, \"* * * * * 2#1\", \"2010-09-03_15:12:42\", \"2010-09-07_00:00:00\");\n    check_fn(cron_next, \"* * * * * 2#2\", \"2010-09-03_15:12:42\", \"2010-09-14_00:00:00\");\n    check_fn(cron_next, \"* * * * * 2#3\", \"2010-09-03_15:12:42\", \"2010-09-21_00:00:00\");\n    check_fn(cron_next, \"* * * * * 2#4\", \"2010-09-03_15:12:42\", \"2010-09-28_00:00:00\");\n    check_fn(cron_next, \"* * * * * 2#5\", \"2010-09-03_15:12:42\", \"2010-11-30_00:00:00\");\n\n    check_fn(cron_next, \"* * * * * 3#-5\", \"2010-09-03_15:12:42\", \"2010-12-01_00:00:00\");\n    check_fn(cron_next, \"* * * * * 3#-4\", \"2010-09-03_15:12:42\", \"2010-09-08_00:00:00\");\n    check_fn(cron_next, \"* * * * * 3#-3\", \"2010-09-03_15:12:42\", \"2010-09-15_00:00:00\");\n    check_fn(cron_next, \"* * * * * 3#-2\", \"2010-09-03_15:12:42\", \"2010-09-22_00:00:00\");\n    check_fn(cron_next, \"* * * * * 3#1\", \"2010-09-03_15:12:42\", \"2010-10-06_00:00:00\");\n    check_fn(cron_next, \"* * * * * 3#2\", \"2010-09-03_15:12:42\", \"2010-09-08_00:00:00\");\n    check_fn(cron_next, \"* * * * * 3#3\", \"2010-09-03_15:12:42\", \"2010-09-15_00:00:00\");\n    check_fn(cron_next, \"* * * * * 3#4\", \"2010-09-03_15:12:42\", \"2010-09-22_00:00:00\");\n    check_fn(cron_next, \"* * * * * 3#5\", \"2010-09-03_15:12:42\", \"2010-09-29_00:00:00\");\n\n    check_fn(cron_next, \"* * * * * 4#-5\", \"2010-09-03_15:12:42\", \"2010-12-02_00:00:00\");\n    check_fn(cron_next, \"* * * * * 4#-4\", \"2010-09-03_15:12:42\", \"2010-09-09_00:00:00\");\n    check_fn(cron_next, \"* * * * * 4#-3\", \"2010-09-03_15:12:42\", \"2010-09-16_00:00:00\");\n    check_fn(cron_next, \"* * * * * 4#-2\", \"2010-09-03_15:12:42\", \"2010-09-23_00:00:00\");\n    check_fn(cron_next, \"* * * * * 4#1\", \"2010-09-03_15:12:42\", \"2010-10-07_00:00:00\");\n    check_fn(cron_next, \"* * * * * 4#2\", \"2010-09-03_15:12:42\", \"2010-09-09_00:00:00\");\n    check_fn(cron_next, \"* * * * * 4#3\", \"2010-09-03_15:12:42\", \"2010-09-16_00:00:00\");\n    check_fn(cron_next, \"* * * * * 4#4\", \"2010-09-03_15:12:42\", \"2010-09-23_00:00:00\");\n    check_fn(cron_next, \"* * * * * 4#5\", \"2010-09-03_15:12:42\", \"2010-09-30_00:00:00\");\n\n    check_fn(cron_next, \"* * * * * 5#-5\", \"2010-09-03_15:12:42\", \"2010-10-01_00:00:00\");\n    check_fn(cron_next, \"* * * * * 5#-4\", \"2010-09-03_15:12:42\", \"2010-09-03_15:12:43\");\n    check_fn(cron_next, \"* * * * * 5#-3\", \"2010-09-03_15:12:42\", \"2010-09-10_00:00:00\");\n    check_fn(cron_next, \"* * * * * 5#-2\", \"2010-09-03_15:12:42\", \"2010-09-17_00:00:00\");\n    check_fn(cron_next, \"* * * * * 5#1\", \"2010-09-03_15:12:42\", \"2010-09-03_15:12:43\");\n    check_fn(cron_next, \"* * * * * 5#2\", \"2010-09-03_15:12:42\", \"2010-09-10_00:00:00\");\n    check_fn(cron_next, \"* * * * * 5#3\", \"2010-09-03_15:12:42\", \"2010-09-17_00:00:00\");\n    check_fn(cron_next, \"* * * * * 5#4\", \"2010-09-03_15:12:42\", \"2010-09-24_00:00:00\");\n    check_fn(cron_next, \"* * * * * 5#5\", \"2010-09-03_15:12:42\", \"2010-10-29_00:00:00\");\n\n    check_fn(cron_next, \"* * * * * 6#-5\", \"2010-09-03_15:12:42\", \"2010-10-02_00:00:00\");\n    check_fn(cron_next, \"* * * * * 6#-4\", \"2010-09-03_15:12:42\", \"2010-09-04_00:00:00\");\n    check_fn(cron_next, \"* * * * * 6#-3\", \"2010-09-03_15:12:42\", \"2010-09-11_00:00:00\");\n    check_fn(cron_next, \"* * * * * 6#-2\", \"2010-09-03_15:12:42\", \"2010-09-18_00:00:00\");\n    check_fn(cron_next, \"* * * * * 6#1\", \"2010-09-03_15:12:42\", \"2010-09-04_00:00:00\");\n    check_fn(cron_next, \"* * * * * 6#2\", \"2010-09-03_15:12:42\", \"2010-09-11_00:00:00\");\n    check_fn(cron_next, \"* * * * * 6#3\", \"2010-09-03_15:12:42\", \"2010-09-18_00:00:00\");\n    check_fn(cron_next, \"* * * * * 6#4\", \"2010-09-03_15:12:42\", \"2010-09-25_00:00:00\");\n    check_fn(cron_next, \"* * * * * 6#5\", \"2010-09-03_15:12:42\", \"2010-10-30_00:00:00\");\n\n    check_fn(cron_next, \"* * * * * 7#-5\", \"2010-09-03_15:12:42\", \"2010-10-03_00:00:00\");\n    check_fn(cron_next, \"* * * * * 7#-4\", \"2010-09-03_15:12:42\", \"2010-09-05_00:00:00\");\n    check_fn(cron_next, \"* * * * * 7#-3\", \"2010-09-03_15:12:42\", \"2010-09-12_00:00:00\");\n    check_fn(cron_next, \"* * * * * 7#-2\", \"2010-09-03_15:12:42\", \"2010-09-19_00:00:00\");\n    check_fn(cron_next, \"* * * * * 7#1\", \"2010-09-03_15:12:42\", \"2010-09-05_00:00:00\");\n    check_fn(cron_next, \"* * * * * 7#2\", \"2010-09-03_15:12:42\", \"2010-09-12_00:00:00\");\n    check_fn(cron_next, \"* * * * * 7#3\", \"2010-09-03_15:12:42\", \"2010-09-19_00:00:00\");\n    check_fn(cron_next, \"* * * * * 7#4\", \"2010-09-03_15:12:42\", \"2010-09-26_00:00:00\");\n    check_fn(cron_next, \"* * * * * 7#5\", \"2010-09-03_15:12:42\", \"2010-10-31_00:00:00\");\n\n    check_fn(cron_next, \"* * * * * 1L\", \"2010-09-30_15:12:42\", \"2010-10-25_00:00:00\");\n    check_fn(cron_next, \"* * * * * 2L\", \"2010-09-30_15:12:42\", \"2010-10-26_00:00:00\");\n    check_fn(cron_next, \"* * * * * 3L\", \"2010-09-30_15:12:42\", \"2010-10-27_00:00:00\");\n    check_fn(cron_next, \"* * * * * 4L\", \"2010-09-30_15:12:42\", \"2010-09-30_15:12:43\");\n    check_fn(cron_next, \"* * * * * 5L\", \"2010-09-30_15:12:42\", \"2010-10-29_00:00:00\");\n    check_fn(cron_next, \"* * * * * 6L\", \"2010-09-30_15:12:42\", \"2010-10-30_00:00:00\");\n    check_fn(cron_next, \"* * * * * 7L\", \"2010-09-30_15:12:42\", \"2010-10-31_00:00:00\");\n    check_fn(cron_next, \"* * * * * 1L\", \"2010-10-27_15:12:42\", \"2010-11-29_00:00:00\");\n    check_fn(cron_next, \"* * * * * 2L\", \"2010-10-27_15:12:42\", \"2010-11-30_00:00:00\");\n    check_fn(cron_next, \"* * * * * 3L\", \"2010-10-27_15:12:42\", \"2010-10-27_15:12:43\");\n    check_fn(cron_next, \"* * * * * 4L\", \"2010-10-27_15:12:42\", \"2010-10-28_00:00:00\");\n    check_fn(cron_next, \"* * * * * 5L\", \"2010-10-27_15:12:42\", \"2010-10-29_00:00:00\");\n    check_fn(cron_next, \"* * * * * 6L\", \"2010-10-27_15:12:42\", \"2010-10-30_00:00:00\");\n    check_fn(cron_next, \"* * * * * 7L\", \"2010-10-27_15:12:42\", \"2010-10-31_00:00:00\");\n\n    check_fn(cron_next, \"* * * * * 1L\", \"2010-10-30_15:12:42\", \"2010-11-29_00:00:00\");\n    check_fn(cron_next, \"* * * * * 2L\", \"2010-10-30_15:12:42\", \"2010-11-30_00:00:00\");\n    check_fn(cron_next, \"* * * * * 3L\", \"2010-10-30_15:12:42\", \"2010-11-24_00:00:00\");\n    check_fn(cron_next, \"* * * * * 4L\", \"2010-10-30_15:12:42\", \"2010-11-25_00:00:00\");\n    check_fn(cron_next, \"* * * * * 5L\", \"2010-10-30_15:12:42\", \"2010-11-26_00:00:00\");\n    check_fn(cron_next, \"* * * * * 6L\", \"2010-10-30_15:12:42\", \"2010-10-30_15:12:43\");\n    check_fn(cron_next, \"* * * * * 7L\", \"2010-10-30_15:12:42\", \"2010-10-31_00:00:00\");\n    check_fn(cron_next, \"* * * * * 1L\", \"2010-11-27_15:12:42\", \"2010-11-29_00:00:00\");\n    check_fn(cron_next, \"* * * * * 2L\", \"2010-11-27_15:12:42\", \"2010-11-30_00:00:00\");\n    check_fn(cron_next, \"* * * * * 3L\", \"2010-11-27_15:12:42\", \"2010-12-29_00:00:00\");\n    check_fn(cron_next, \"* * * * * 4L\", \"2010-11-27_15:12:42\", \"2010-12-30_00:00:00\");\n    check_fn(cron_next, \"* * * * * 5L\", \"2010-11-27_15:12:42\", \"2010-12-31_00:00:00\");\n    check_fn(cron_next, \"* * * * * 6L\", \"2010-11-27_15:12:42\", \"2010-11-27_15:12:43\");\n    check_fn(cron_next, \"* * * * * 7L\", \"2010-11-27_15:12:42\", \"2010-11-28_00:00:00\");\n\n    check_fn(cron_next, \"0 0 7 W * *\", \"2009-09-26_00:42:55\", \"2009-09-28_07:00:00\");\n    check_fn(cron_next, \"0 0 7 W * *\", \"2009-09-28_07:00:00\", \"2009-09-29_07:00:00\");\n    check_fn(cron_next, \"* * * * * L\", \"2010-10-25_15:12:42\", \"2010-10-31_00:00:00\");\n    check_fn(cron_next, \"* * * * * L\", \"2010-10-20_15:12:42\", \"2010-10-24_00:00:00\");\n    check_fn(cron_next, \"* * * * * L\", \"2010-10-27_15:12:42\", \"2010-10-31_00:00:00\");\n\n    check_fn(cron_next, \"* 15 11 * * *\", \"2019-03-09_11:43:00\", \"2019-03-10_11:15:00\");\n    check_fn(cron_next, \"*/15 * 1-4 * * *\", \"2012-07-01_09:53:50\", \"2012-07-02_01:00:00\");\n    check_fn(cron_next, \"*/15 * 1-4 * * *\", \"2012-07-01_09:53:00\", \"2012-07-02_01:00:00\");\n    check_fn(cron_next, \"0,15,30,45 * 1,2,3,4 * * *\", \"2012-07-01_09:53:00\", \"2012-07-02_01:00:00\");\n    check_fn(cron_next, \"0 */2 1-4 * * *\", \"2012-07-01_09:00:00\", \"2012-07-02_01:00:00\");\n    check_fn(cron_next, \"0 */2 * * * *\", \"2012-07-01_09:00:00\", \"2012-07-01_09:02:00\");\n    check_fn(cron_next, \"0 */2 * * * *\", \"2013-07-01_09:00:00\", \"2013-07-01_09:02:00\");\n    check_fn(cron_next, \"0 */2 * * * *\", \"2018-09-14_14:24:00\", \"2018-09-14_14:26:00\");\n    check_fn(cron_next, \"0 */2 * * * *\", \"2018-09-14_14:25:00\", \"2018-09-14_14:26:00\");\n    check_fn(cron_next, \"0 */20 * * * *\", \"2018-09-14_14:24:00\", \"2018-09-14_14:40:00\");\n    check_fn(cron_next, \"* * * * * *\", \"2012-07-01_09:00:00\", \"2012-07-01_09:00:01\");\n    check_fn(cron_next, \"* * * * * *\", \"2012-12-01_09:00:58\", \"2012-12-01_09:00:59\");\n    check_fn(cron_next, \"10 * * * * *\", \"2012-12-01_09:42:09\", \"2012-12-01_09:42:10\");\n    check_fn(cron_next, \"11 * * * * *\", \"2012-12-01_09:42:10\", \"2012-12-01_09:42:11\");\n    check_fn(cron_next, \"10 * * * * *\", \"2012-12-01_09:42:10\", \"2012-12-01_09:43:10\");\n    check_fn(cron_next, \"10-15 * * * * *\", \"2012-12-01_09:42:09\", \"2012-12-01_09:42:10\");\n    check_fn(cron_next, \"10-15 * * * * *\", \"2012-12-01_21:42:14\", \"2012-12-01_21:42:15\");\n    check_fn(cron_next, \"0 * * * * *\", \"2012-12-01_21:10:42\", \"2012-12-01_21:11:00\");\n    check_fn(cron_next, \"0 * * * * *\", \"2012-12-01_21:11:00\", \"2012-12-01_21:12:00\");\n    check_fn(cron_next, \"0 11 * * * *\", \"2012-12-01_21:10:42\", \"2012-12-01_21:11:00\");\n    check_fn(cron_next, \"0 10 * * * *\", \"2012-12-01_21:11:00\", \"2012-12-01_22:10:00\");\n    check_fn(cron_next, \"0 0 * * * *\", \"2012-09-30_11:01:00\", \"2012-09-30_12:00:00\");\n    check_fn(cron_next, \"0 0 * * * *\", \"2012-09-30_12:00:00\", \"2012-09-30_13:00:00\");\n    check_fn(cron_next, \"0 0 * * * *\", \"2012-09-10_23:01:00\", \"2012-09-11_00:00:00\");\n    check_fn(cron_next, \"0 0 * * * *\", \"2012-09-11_00:00:00\", \"2012-09-11_01:00:00\");\n    check_fn(cron_next, \"0 0 0 * * *\", \"2012-09-01_14:42:43\", \"2012-09-02_00:00:00\");\n    check_fn(cron_next, \"0 0 0 * * *\", \"2012-09-02_00:00:00\", \"2012-09-03_00:00:00\");\n    check_fn(cron_next, \"* * * 10 * *\", \"2012-10-09_15:12:42\", \"2012-10-10_00:00:00\");\n    check_fn(cron_next, \"* * * 10 * *\", \"2012-10-11_15:12:42\", \"2012-11-10_00:00:00\");\n    check_fn(cron_next, \"0 0 0 * * *\", \"2012-09-30_15:12:42\", \"2012-10-01_00:00:00\");\n    check_fn(cron_next, \"0 0 0 * * *\", \"2012-10-01_00:00:00\", \"2012-10-02_00:00:00\");\n    check_fn(cron_next, \"0 0 0 * * *\", \"2012-08-30_15:12:42\", \"2012-08-31_00:00:00\");\n    check_fn(cron_next, \"0 0 0 * * *\", \"2012-08-31_00:00:00\", \"2012-09-01_00:00:00\");\n    check_fn(cron_next, \"0 0 0 * * *\", \"2012-10-30_15:12:42\", \"2012-10-31_00:00:00\");\n    check_fn(cron_next, \"0 0 0 * * *\", \"2012-10-31_00:00:00\", \"2012-11-01_00:00:00\");\n    check_fn(cron_next, \"0 0 0 1 * *\", \"2012-10-30_15:12:42\", \"2012-11-01_00:00:00\");\n    check_fn(cron_next, \"0 0 0 1 * *\", \"2012-11-01_00:00:00\", \"2012-12-01_00:00:00\");\n    check_fn(cron_next, \"0 0 0 1 * *\", \"2010-12-31_15:12:42\", \"2011-01-01_00:00:00\");\n    check_fn(cron_next, \"0 0 0 1 * *\", \"2011-01-01_00:00:00\", \"2011-02-01_00:00:00\");\n    check_fn(cron_next, \"0 0 0 31 * *\", \"2011-10-30_15:12:42\", \"2011-10-31_00:00:00\");\n    check_fn(cron_next, \"0 0 0 1 * *\", \"2011-10-30_15:12:42\", \"2011-11-01_00:00:00\");\n    check_fn(cron_next, \"* * * * * 2\", \"2010-10-25_15:12:42\", \"2010-10-26_00:00:00\");\n    check_fn(cron_next, \"* * * * * 2\", \"2010-10-20_15:12:42\", \"2010-10-26_00:00:00\");\n    check_fn(cron_next, \"* * * * * 2\", \"2010-10-27_15:12:42\", \"2010-11-02_00:00:00\");\n    check_fn(cron_next, \"55 5 * * * *\", \"2010-10-27_15:04:54\", \"2010-10-27_15:05:55\");\n    check_fn(cron_next, \"55 5 * * * *\", \"2010-10-27_15:05:55\", \"2010-10-27_16:05:55\");\n    check_fn(cron_next, \"55 * 10 * * *\", \"2010-10-27_09:04:54\", \"2010-10-27_10:00:55\");\n    check_fn(cron_next, \"55 * 10 * * *\", \"2010-10-27_10:00:55\", \"2010-10-27_10:01:55\");\n    check_fn(cron_next, \"* 5 10 * * *\", \"2010-10-27_09:04:55\", \"2010-10-27_10:05:00\");\n    check_fn(cron_next, \"* 5 10 * * *\", \"2010-10-27_10:05:00\", \"2010-10-27_10:05:01\");\n    check_fn(cron_next, \"55 * * 3 * *\", \"2010-10-02_10:05:54\", \"2010-10-03_00:00:55\");\n    check_fn(cron_next, \"55 * * 3 * *\", \"2010-10-03_00:00:55\", \"2010-10-03_00:01:55\");\n    check_fn(cron_next, \"* * * 3 11 *\", \"2010-10-02_14:42:55\", \"2010-11-03_00:00:00\");\n    check_fn(cron_next, \"* * * 3 11 *\", \"2010-11-03_00:00:00\", \"2010-11-03_00:00:01\");\n    check_fn(cron_next, \"0 0 0 29 2 *\", \"2007-02-10_14:42:55\", \"2008-02-29_00:00:00\");\n    check_fn(cron_next, \"0 0 0 29 2 *\", \"2008-02-29_00:00:00\", \"2012-02-29_00:00:00\");\n    check_fn(cron_next, \"0 0 7 ? * MON-FRI\", \"2009-09-26_00:42:55\", \"2009-09-28_07:00:00\");\n    check_fn(cron_next, \"0 0 7 ? * MON-FRI\", \"2009-09-28_07:00:00\", \"2009-09-29_07:00:00\");\n    check_fn(cron_next, \"0 30 23 30 1/3 ?\", \"2010-12-30_00:00:00\", \"2011-01-30_23:30:00\");\n    check_fn(cron_next, \"0 30 23 30 1/3 ?\", \"2011-01-30_23:30:00\", \"2011-04-30_23:30:00\");\n    check_fn(cron_next, \"0 30 23 30 1/3 ?\", \"2011-04-30_23:30:00\", \"2011-07-30_23:30:00\");\n    check_fn(cron_next, \"* * * * * *\", \"2020-12-31_23:59:59\", \"2021-01-01_00:00:00\");\n    check_fn(cron_next, \"0 0 * * * *\", \"2020-02-28_23:00:00\", \"2020-02-29_00:00:00\");\n    check_fn(cron_next, \"0 0 0 * * *\", \"2020-02-29_01:02:03\", \"2020-03-01_00:00:00\");\n\n    check_fn(cron_prev, \"* 15 11 * * *\", \"2019-03-09_11:43:00\", \"2019-03-09_11:15:59\");\n    check_fn(cron_prev, \"*/15 * 1-4 * * *\", \"2012-07-01_09:53:50\", \"2012-07-01_04:59:45\");\n    check_fn(cron_prev, \"*/15 * 1-4 * * *\", \"2012-07-01_01:00:14\", \"2012-07-01_01:00:00\");\n    check_fn(cron_prev, \"*/15 * 1-4 * * *\", \"2012-07-01_01:00:00\", \"2012-06-30_04:59:45\");\n    check_fn(cron_prev, \"* * * * * *\", \"2012-07-01_09:00:00\", \"2012-07-01_08:59:59\");\n    check_fn(cron_prev, \"* * * * * *\", \"2021-01-01_00:00:00\", \"2020-12-31_23:59:59\");\n    check_fn(cron_prev, \"0 0 * * * *\", \"2020-02-29_00:00:00\", \"2020-02-28_23:00:00\");\n    check_fn(cron_prev, \"0 0 0 * * *\", \"2020-03-01_00:00:00\", \"2020-02-29_00:00:00\");\n    check_fn(cron_prev, \"0 0 * * * *\", \"2020-03-01_00:00:00\", \"2020-02-29_23:00:00\");\n\n    check_fn(cron_next, \"0 0 0 ? 11-12 *\", \"2022-05-31_00:00:00\", \"2022-11-01_00:00:00\");\n    check_fn(cron_next, \"0 0 0 ? 11-12 *\", \"2022-07-31_00:00:00\", \"2022-11-01_00:00:00\");\n    check_fn(cron_next, \"0 0 0 ? 11-12 *\", \"2022-08-31_00:00:00\", \"2022-11-01_00:00:00\");\n    check_fn(cron_next, \"0 0 0 ? 11-12 *\", \"2022-10-31_00:00:00\", \"2022-11-01_00:00:00\");\n    check_fn(cron_next, \"0 0 0 ? 6-7 *\", \"2022-05-31_00:00:00\", \"2022-06-01_00:00:00\");\n    check_fn(cron_next, \"0 0 0 ? 8-9 *\", \"2022-07-31_00:00:00\", \"2022-08-01_00:00:00\");\n    check_fn(cron_next, \"0 0 0 ? 9-10 *\", \"2022-08-31_00:00:00\", \"2022-09-01_00:00:00\");\n    check_fn(cron_next, \"0 0 0 ? 2-3 *\", \"2022-01-31_00:00:00\", \"2022-02-01_00:00:00\");\n    check_fn(cron_next, \"0 0 0 ? 4-5 *\", \"2022-03-31_00:00:00\", \"2022-04-01_00:00:00\");\n\n    check_fn(cron_next, \"* * * 29 2 *\", \"2021-12-07_12:00:00\", \"2024-02-29_00:00:00\");\n    check_fn(cron_prev, \"* * * 29 2 *\", \"2021-12-07_12:00:00\", \"2020-02-29_23:59:59\");\n\n    check_fn(cron_prev, \"* * * 1 2 *\", \"2023-11-01_00:00:00\", \"2023-02-01_23:59:59\");\n    check_fn(cron_prev, \"* * * 2 2 *\", \"2023-11-01_00:00:00\", \"2023-02-02_23:59:59\");\n    check_fn(cron_prev, \"* * * 3 2 *\", \"2023-11-01_00:00:00\", \"2023-02-03_23:59:59\");\n    check_fn(cron_prev, \"* * * 4 2 *\", \"2023-11-01_00:00:00\", \"2023-02-04_23:59:59\");\n\n    check_fn(cron_prev, \"* * * 1 4 *\", \"2023-10-01_00:00:00\", \"2023-04-01_23:59:59\");\n    check_fn(cron_prev, \"* * * 2 4 *\", \"2023-10-01_00:00:00\", \"2023-04-02_23:59:59\");\n    check_fn(cron_prev, \"* * * 3 4 *\", \"2023-10-01_00:00:00\", \"2023-04-03_23:59:59\");\n    check_fn(cron_prev, \"* * * 4 4 *\", \"2023-10-01_00:00:00\", \"2023-04-04_23:59:59\");\n\n    check_fn(cron_prev, \"0 0 20 1 2 *\", \"2022-12-30_08:10:23\", \"2022-02-01_20:00:00\");\n    check_fn(cron_prev, \"0 0 20 2 2 *\", \"2022-12-30_08:10:23\", \"2022-02-02_20:00:00\");\n    check_fn(cron_prev, \"0 0 20 3 2 *\", \"2022-12-30_08:10:23\", \"2022-02-03_20:00:00\");\n    check_fn(cron_prev, \"0 0 20 1 2 *\", \"2022-12-31_08:10:23\", \"2022-02-01_20:00:00\");\n    check_fn(cron_prev, \"0 0 20 2 2 *\", \"2022-12-31_08:10:23\", \"2022-02-02_20:00:00\");\n    check_fn(cron_prev, \"0 0 20 3 2 *\", \"2022-12-31_08:10:23\", \"2022-02-03_20:00:00\");\n    check_fn(cron_prev, \"0 0 20 1 2 *\", \"2023-01-01_08:10:23\", \"2022-02-01_20:00:00\");\n    check_fn(cron_prev, \"0 0 20 2 2 *\", \"2023-01-01_08:10:23\", \"2022-02-02_20:00:00\");\n    check_fn(cron_prev, \"0 0 20 3 2 *\", \"2023-01-01_08:10:23\", \"2022-02-03_20:00:00\");\n\n    check_fn(cron_prev, \"0 0 17 * 2 2-4\", \"2023-08-31_18:00:00\", \"2023-02-28_17:00:00\");\n    check_fn(cron_prev, \"0 0 17 * 2 2-4\", \"2023-09-01_18:00:00\", \"2023-02-28_17:00:00\");\n    check_fn(cron_prev, \"0 0 17 * 2 2-4\", \"2023-09-02_18:00:00\", \"2023-02-28_17:00:00\");\n    check_fn(cron_prev, \"0 0 17 * 2 2-4\", \"2023-09-03_18:00:00\", \"2023-02-28_17:00:00\");\n    check_fn(cron_prev, \"0 0 17 * 2 2-4\", \"2023-09-04_18:00:00\", \"2023-02-28_17:00:00\");\n    check_fn(cron_prev, \"0 0 17 * 2 2-4\", \"2023-09-05_18:00:00\", \"2023-02-28_17:00:00\");\n\n    check_fn(cron_prev, \"0 0 17 * 3 1-5\", \"2023-03-02_17:00:00\", \"2023-03-01_17:00:00\");\n    check_fn(cron_prev, \"0 0 17 * 3 1-5\", \"2023-03-02_17:00:01\", \"2023-03-02_17:00:00\");\n    check_fn(cron_prev, \"0 0 17 * 3 1-5\", \"2023-03-02_18:00:00\", \"2023-03-02_17:00:00\");\n    check_fn(cron_prev, \"0 0 17 * 3 1-5\", \"2023-03-03_18:00:00\", \"2023-03-03_17:00:00\");\n    check_fn(cron_prev, \"0 0 17 * 3 1-5\", \"2023-03-04_18:00:00\", \"2023-03-03_17:00:00\");\n    check_fn(cron_prev, \"0 0 17 * 3 1-5\", \"2023-03-05_18:00:00\", \"2023-03-03_17:00:00\");\n    check_fn(cron_prev, \"0 0 17 * 3 1-5\", \"2023-03-06_18:00:00\", \"2023-03-06_17:00:00\");\n\n    check_fn(cron_prev, \"0 30 9 * 4 6\", \"2024-04-05_18:00:00\", \"2023-04-29_09:30:00\");\n    check_fn(cron_prev, \"0 30 9 * 4 6\", \"2024-04-06_09:29:59\", \"2023-04-29_09:30:00\");\n    check_fn(cron_prev, \"0 30 9 * 4 6\", \"2024-04-06_09:30:00\", \"2023-04-29_09:30:00\");\n    check_fn(cron_prev, \"0 30 9 * 4 6\", \"2024-04-06_09:30:01\", \"2024-04-06_09:30:00\");\n    check_fn(cron_prev, \"0 30 9 * 4 6\", \"2024-04-06_18:00:00\", \"2024-04-06_09:30:00\");\n    check_fn(cron_prev, \"0 30 9 * 4 6\", \"2024-04-07_18:00:00\", \"2024-04-06_09:30:00\");\n    check_fn(cron_prev, \"0 30 9 * 4 6\", \"2024-04-26_18:00:00\", \"2024-04-20_09:30:00\");\n    check_fn(cron_prev, \"0 30 9 * 4 6\", \"2024-04-27_18:00:00\", \"2024-04-27_09:30:00\");\n    check_fn(cron_prev, \"0 30 9 * 4 6\", \"2024-04-28_18:00:00\", \"2024-04-27_09:30:00\");\n    check_fn(cron_prev, \"0 30 9 * 4 6\", \"2024-05-01_18:00:00\", \"2024-04-27_09:30:00\");\n\n    check_fn(cron_prev, \"0 30 11 * * 6\", \"2020-02-27_10:00:00\", \"2020-02-22_11:30:00\");\n    check_fn(cron_prev, \"0 30 11 * * 6\", \"2020-02-28_10:00:00\", \"2020-02-22_11:30:00\");\n    check_fn(cron_prev, \"0 30 11 * * 6\", \"2020-02-29_10:00:00\", \"2020-02-22_11:30:00\");\n    check_fn(cron_prev, \"0 30 11 * * 6\", \"2020-02-29_11:31:00\", \"2020-02-29_11:30:00\");\n    check_fn(cron_prev, \"0 30 11 * * 6\", \"2020-03-01_10:00:00\", \"2020-02-29_11:30:00\");\n    check_fn(cron_prev, \"0 30 11 * * 6\", \"2020-03-01_12:00:00\", \"2020-02-29_11:30:00\");\n\n    check_fn(cron_prev, \"0 0 10 * * *\", \"2020-02-29_09:59:59\", \"2020-02-28_10:00:00\");\n    check_fn(cron_prev, \"0 0 10 * * *\", \"2020-02-29_10:00:00\", \"2020-02-28_10:00:00\");\n    check_fn(cron_prev, \"0 0 10 * * *\", \"2020-02-29_10:00:01\", \"2020-02-29_10:00:00\");\n    check_fn(cron_prev, \"0 0 10 * * *\", \"2022-02-28_09:59:59\", \"2022-02-27_10:00:00\");\n    check_fn(cron_prev, \"0 0 10 * * *\", \"2022-02-28_10:00:00\", \"2022-02-27_10:00:00\");\n    check_fn(cron_prev, \"0 0 10 * * *\", \"2022-02-28_10:00:01\", \"2022-02-28_10:00:00\");\n    check_fn(cron_prev, \"0 0 10 * * *\", \"2022-12-31_09:59:59\", \"2022-12-30_10:00:00\");\n    check_fn(cron_prev, \"0 0 10 * * *\", \"2022-12-31_10:00:00\", \"2022-12-30_10:00:00\");\n    check_fn(cron_prev, \"0 0 10 * * *\", \"2022-12-31_10:00:01\", \"2022-12-31_10:00:00\");\n    check_fn(cron_prev, \"0 0 10 * * *\", \"2022-12-31_23:59:59\", \"2022-12-31_10:00:00\");\n    check_fn(cron_prev, \"0 0 10 * * *\", \"2023-01-01_00:00:00\", \"2022-12-31_10:00:00\");\n    check_fn(cron_prev, \"0 0 10 * * *\", \"2023-01-01_00:00:01\", \"2022-12-31_10:00:00\");\n    check_fn(cron_prev, \"0 0 10 * * *\", \"2023-01-01_09:59:59\", \"2022-12-31_10:00:00\");\n    check_fn(cron_prev, \"0 0 10 * * *\", \"2023-01-01_10:00:00\", \"2022-12-31_10:00:00\");\n    check_fn(cron_prev, \"0 0 10 * * *\", \"2023-01-01_10:00:01\", \"2023-01-01_10:00:00\");\n\n    check_fn(cron_prev, \"30 50 23 20,21,22 * *\", \"2023-07-01_12:34:56\", \"2023-06-22_23:50:30\");\n    check_fn(cron_prev, \"30 50 23 20,21,22 * *\", \"2023-07-19_12:34:56\", \"2023-06-22_23:50:30\");\n    check_fn(cron_prev, \"30 50 23 20,21,22 * *\", \"2023-07-20_12:34:56\", \"2023-06-22_23:50:30\");\n    check_fn(cron_prev, \"30 50 23 20,21,22 * *\", \"2023-07-21_12:34:56\", \"2023-07-20_23:50:30\");\n    check_fn(cron_prev, \"30 50 23 20,21,22 * *\", \"2023-07-22_12:34:56\", \"2023-07-21_23:50:30\");\n    check_fn(cron_prev, \"30 50 23 20,21,22 * *\", \"2023-07-23_12:34:56\", \"2023-07-22_23:50:30\");\n}\n\nvoid test_parse(void)\n{\n    check_same(\"* * * W * *\", \"* * * * * 1-5\");\n    check_same(\"* * * * * L\", \"* * * * * 0\");\n    check_same(\"* * * * * 6#-1\", \"* * * * * 6L\");\n    check_same(\"0 0 0 * * *\", \"0 0 * * *\");\n    check_same(\"0 0 0 * * *\", \"0 0 0 * * * *\");\n    check_same(\"* * * * * *\", \"* * * * * * *\");\n\n    check_same(\"@annually\", \"0 0 0 1 1 * *\");\n    check_same(\"@yearly\", \"0 0 0 1 1 * *\");\n    check_same(\"@monthly\", \"0 0 0 1 * * *\");\n    check_same(\"@weekly\", \"0 0 0 * * 0 *\");\n    check_same(\"@daily\", \"0 0 0 * * * *\");\n    check_same(\"@midnight\", \"0 0 0 * * * *\");\n    check_same(\"@hourly\", \"0 0 * * * * *\");\n    check_same(\"@minutely\", \"0 * * * * * *\");\n    check_same(\"@secondly\", \"* * * * * * *\");\n\n    check_same(\"* * * 2 * *\", \"* * * 2 * ?\");\n    check_same(\"* * * 2 * *\", \"* * * 2 * ?\");\n    check_same(\"57,59 * * * * *\", \"57/2 * * * * *\");\n    check_same(\"L57,59,61 * * * * *\", \"L57/2 * * * * *\");\n    check_same(\"1,3,5 * * * * *\", \"1-6/2 * * * * *\");\n    check_same(\"* * 4,8,12,16,20 * * *\", \"* * 4/4 * * *\");\n    check_same(\"* * * * * 0-6\", \"* * * * * TUE,WED,THU,FRI,SAT,SUN,MON\");\n    check_same(\"* * * * * 0\", \"* * * * * SUN\");\n    check_same(\"* * * * * 0\", \"* * * * * 7\");\n    check_same(\"* * * * 1-12 *\", \"* * * * FEB,JAN,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC *\");\n    check_same(\"* * * * 2 *\", \"* * * * Feb *\");\n    check_same(\"*  *  * *  1 *\", \"* * * * 1 *\");\n\n    check_expr_invalid(\"Z * * * * *\");\n    check_expr_invalid(\"* * * * * 1#-6\");\n    check_expr_invalid(\"* * * * * 1#6\");\n\n    check_expr_invalid(\"77 * * * * *\");\n    check_expr_invalid(\"44-77 * * * * *\");\n    check_expr_invalid(\"* 77 * * * *\");\n    check_expr_invalid(\"* 44-77 * * * *\");\n    check_expr_invalid(\"* * 27 * * *\");\n    check_expr_invalid(\"* * 23-28 * * *\");\n    check_expr_invalid(\"* * * 45 * *\");\n    check_expr_invalid(\"* * * 28-45 * *\");\n    check_expr_invalid(\"0 0 0 25 13 ?\");\n    check_expr_invalid(\"0 0 0 25 0 ?\");\n    check_expr_invalid(\"0 0 0 32 12 ?\");\n    check_expr_invalid(\"* * * * 11-13 *\");\n    check_expr_invalid(\"-5 * * * * *\");\n    check_expr_invalid(\"3-2 */5 * * * *\");\n    check_expr_invalid(\"/5 * * * * *\");\n    check_expr_invalid(\"*/0 * * * * *\");\n    check_expr_invalid(\"*/-0 * * * * *\");\n    check_expr_invalid(\"* 1 1 0 * *\");\n\n    /* Source: https://www.freeformatter.com/cron-expression-generator-quartz.html */\n\n    check_expr_valid(\"* * * ? * *\");                /* Every second */\n    check_expr_valid(\"0 * * ? * *\");                /* Every minute */\n    check_expr_valid(\"0 */2 * ? * *\");              /* Every even minute */\n    check_expr_valid(\"0 1/2 * ? * *\");              /* Every uneven minute */\n    check_expr_valid(\"0 */2 * ? * *\");              /* Every 2 minutes */\n    check_expr_valid(\"0 */3 * ? * *\");              /* Every 3 minutes */\n    check_expr_valid(\"0 */4 * ? * *\");              /* Every 4 minutes */\n    check_expr_valid(\"0 */5 * ? * *\");              /* Every 5 minutes */\n    check_expr_valid(\"0 */10 * ? * *\");             /* Every 10 minutes */\n    check_expr_valid(\"0 */15 * ? * *\");             /* Every 15 minutes */\n    check_expr_valid(\"0 */30 * ? * *\");             /* Every 30 minutes */\n    check_expr_valid(\"0 15,30,45 * ? * *\");         /* Every hour at minutes 15, 30 and 45 */\n    check_expr_valid(\"0 0 * ? * *\");                /* Every hour */\n    check_expr_valid(\"0 0 */2 ? * *\");              /* Every hour */\n    check_expr_valid(\"0 0 0/2 ? * *\");              /* Every even hour */\n    check_expr_valid(\"0 0 1/2 ? * *\");              /* Every uneven hour */\n    check_expr_valid(\"0 0 */3 ? * *\");              /* Every three hours */\n    check_expr_valid(\"0 0 */4 ? * *\");              /* Every four hours */\n    check_expr_valid(\"0 0 */6 ? * *\");              /* Every six hours */\n    check_expr_valid(\"0 0 */8 ? * *\");              /* Every eight hours */\n    check_expr_valid(\"0 0 */12 ? * *\");             /* Every twelve hours */\n    check_expr_valid(\"0 0 0 * * ?\");                /* Every day at midnight - 12am */\n    check_expr_valid(\"0 0 1 * * ?\");                /* Every day at 1am */\n    check_expr_valid(\"0 0 6 * * ?\");                /* Every day at 6am */\n    check_expr_valid(\"0 0 12 * * ?\");               /* Every day at noon - 12pm */\n    check_expr_valid(\"0 0 12 * * ?\");               /* Every day at noon - 12pm */\n    check_expr_valid(\"0 0 12 ? * SUN\");             /* Every Sunday at noon */\n    check_expr_valid(\"0 0 12 ? * MON\");             /* Every Monday at noon */\n    check_expr_valid(\"0 0 12 ? * TUE\");             /* Every Tuesday at noon */\n    check_expr_valid(\"0 0 12 ? * WED\");             /* Every Wednesday at noon */\n    check_expr_valid(\"0 0 12 ? * THU\");             /* Every Thursday at noon */\n    check_expr_valid(\"0 0 12 ? * FRI\");             /* Every Friday at noon */\n    check_expr_valid(\"0 0 12 ? * SAT\");             /* Every Saturday at noon */\n    check_expr_valid(\"0 0 12 ? * MON-FRI\");         /* Every Weekday at noon */\n    check_expr_valid(\"0 0 12 ? * SUN,SAT\");         /* Every Saturday and Sunday at noon */\n    check_expr_valid(\"0 0 12 */7 * ?\");             /* Every 7 days at noon */\n    check_expr_valid(\"0 0 12 1 * ?\");               /* Every month on the 1st, at noon */\n    check_expr_valid(\"0 0 12 2 * ?\");               /* Every month on the 2nd, at noon */\n    check_expr_valid(\"0 0 12 15 * ?\");              /* Every month on the 15th, at noon */\n    check_expr_valid(\"0 0 12 1/2 * ?\");             /* Every 2 days starting on the 1st of the month, at noon */\n    check_expr_valid(\"0 0 12 1/4 * ?\");             /* Every 4 days staring on the 1st of the month, at noon */\n    check_expr_valid(\"0 0 12 L * ?\");               /* Every month on the last day of the month, at noon */\n    check_expr_valid(\"0 0 12 L-2 * ?\");             /* Every month on the second to last day of the month, at noon */\n    check_expr_valid(\"0 0 12 LW * ?\");              /* Every month on the last weekday, at noon */\n\n    /*check_expr_valid(\"0 0 12 1L * ?\"); */             /* Every month on the last Sunday, at noon */\n    /*check_expr_valid(\"0 0 12 2L * ?\"); */             /* Every month on the last Monday, at noon */\n    /*check_expr_valid(\"0 0 12 6L * ?\"); */             /* Every month on the last Friday, at noon */\n\n    check_expr_valid(\"0 0 12 ? * 1L\");              /* Every month on the last Sunday, at noon */\n    check_expr_valid(\"0 0 12 ? * 2L\");              /* Every month on the last Monday, at noon */\n    check_expr_valid(\"0 0 12 ? * 6L\");              /* Every month on the last Friday, at noon */\n\n    check_expr_valid(\"0 0 12 1W * ?\");              /* Every month on the nearest Weekday to the 1st of the month, at noon */\n    check_expr_valid(\"0 0 12 15W * ?\");             /* Every month on the nearest Weekday to the 15th of the month, at noon */\n    check_expr_valid(\"0 0 12 ? * 2#1\");             /* Every month on the first Monday of the Month, at noon */\n    check_expr_valid(\"0 0 12 ? * 6#1\");             /* Every month on the first Friday of the Month, at noon */\n    check_expr_valid(\"0 0 12 ? * 2#2\");             /* Every month on the second Monday of the Month, at noon */\n    check_expr_valid(\"0 0 12 ? * 5#3\");             /* Every month on the third Thursday of the Month, at noon - 12pm */\n    check_expr_valid(\"0 0 12 ? JAN *\");             /* Every day at noon in January only */\n    check_expr_valid(\"0 0 12 ? JUN *\");             /* Every day at noon in June only */\n    check_expr_valid(\"0 0 12 ? JAN,JUN *\");         /* Every day at noon in January and June */\n    check_expr_valid(\"0 0 12 ? DEC *\");             /* Every day at noon in December only */\n    check_expr_valid(\"0 0 12 ? JAN,FEB,MAR,APR *\"); /* Every day at noon in January, February, March and April */\n    check_expr_valid(\"0 0 12 ? 9-12 *\");            /* Every day at noon between September and December */\n\n    /* ChatGPT generated inputs for further testing. */\n\n    check_expr_valid(\"0 0 12 * * ?\"); /* Every day at 12 PM (noon). */\n    check_expr_valid(\"0 15 10 ? * *\"); /* Every day at 10:15 AM. */\n    check_expr_valid(\"0 15 10 * * ?\"); /* Every day at 10:15 AM. */\n    check_expr_valid(\"0 15 10 * * ? *\"); /* Every day at 10:15 AM. */\n    check_expr_valid(\"0 15 10 * * ? 2023\"); /* Every day at 10:15 AM during the year 2023. */\n    check_expr_valid(\"0 * 14 * * ?\"); /* Every minute starting at 2 PM and ending at 2:59 PM, every day. */\n    check_expr_valid(\"0 0/5 14 * * ?\"); /* Every 5 minutes starting at 2 PM and ending at 2:55 PM, every day. */\n    check_expr_valid(\"0 0/5 14,18 * * ?\"); /* Every 5 minutes starting at 2 PM and ending at 2:55 PM, AND every 5 minutes starting at 6 PM and ending at 6:55 PM, every day. */\n    check_expr_valid(\"0 0-5 14 * * ?\"); /* Every minute starting at 2 PM and ending at 2:05 PM, every day. */\n    check_expr_valid(\"0 10,44 14 ? 3 WED\"); /* Every Wednesday in March at 2:10 PM and 2:44 PM. */\n    check_expr_valid(\"0 15 10 ? * MON-FRI\"); /* Every weekday at 10:15 AM. */\n    check_expr_valid(\"0 15 10 15 * ?\"); /* Every 15th day of the month at 10:15 AM. */\n    check_expr_valid(\"0 15 10 L * ?\"); /* Last day of every month at 10:15 AM. */\n    check_expr_valid(\"0 15 10 ? * 6L\"); /* Last Friday of every month at 10:15 AM. */\n    check_expr_valid(\"0 15 10 ? * 6L 2022-2025\"); /* Last Friday of every month during the years 2022 through 2025 at 10:15 AM. */\n    check_expr_valid(\"0 15 10 ? * 6#3\"); /* Third Friday of every month at 10:15 AM. */\n    check_expr_valid(\"0 15 10 ? * 2-6\"); /* Every weekday (Monday to Friday) at 10:15 AM. */\n    check_expr_valid(\"0 0/5 14-18 * * ?\"); /* Every 5 minutes from 2 PM to 6:55 PM every day. */\n    check_expr_valid(\"0 0 12 1/5 * ?\"); /* Every 5 days at 12 PM. */\n    check_expr_valid(\"0 11 11 11 11 ?\"); /* Every November 11th at 11:11 AM. */\n    check_expr_valid(\"0 0 12 ? * SUN\"); /* Every Sunday at noon. */\n    check_expr_valid(\"0 0 12 ? * MON\"); /* Every Monday at noon. */\n    check_expr_valid(\"0 0 12 ? * TUE\"); /* Every Tuesday at noon. */\n    check_expr_valid(\"0 0 12 ? * WED\"); /* Every Wednesday at noon. */\n    check_expr_valid(\"0 0 12 ? * THU\"); /* Every Thursday at noon. */\n    check_expr_valid(\"0 0 12 ? * FRI\"); /* Every Friday at noon. */\n    check_expr_valid(\"0 0 12 ? * SAT\"); /* Every Saturday at noon. */\n    check_expr_valid(\"0 0/30 8-9 1 * ?\"); /* Every 30 minutes between 8-9 AM on the 1st of the month. */\n    check_expr_valid(\"0 0 0 1 1 ?\"); /* Every New Year's Day at midnight. */\n    check_expr_valid(\"0 0 0 25 12 ?\"); /* Every Christmas at midnight. */\n    check_expr_valid(\"0 0 6,18 * * ?\"); /* Every day at 6 AM and 6 PM. */\n    check_expr_valid(\"0 0 8-10 ? * 2-6\"); /* Every weekday between 8-10 AM. */\n    check_expr_valid(\"0 0/15 * ? * *\"); /* Every 15 minutes. */\n    check_expr_valid(\"0 0 12 LW * ?\"); /* Last weekday of the month at noon. */\n    check_expr_valid(\"0 0 12 1W * ?\"); /* Nearest weekday to the 1st of the month at noon. */\n    check_expr_valid(\"0 0 12 W * ?\"); /* Every weekday at noon. */\n    check_expr_valid(\"0 0 12 ? JAN,DEC *\"); /* Every day at noon in January and December. */\n    check_expr_valid(\"0 0 12 ? * 1#2\"); /* Second Sunday of every month at noon. */\n    check_expr_valid(\"0 0 12 ? * 2#2\"); /* Second Monday of every month at noon. */\n    check_expr_valid(\"0 0 12 ? * 6#1\"); /* First Friday of every month at noon. */\n    check_expr_valid(\"0 0 8,20 ? * *\"); /* Every day at 8 AM and 8 PM. */\n    check_expr_valid(\"0 30 10-13 ? * WED,FRI\"); /* Every Wednesday and Friday between 10:30 AM and 1:30 PM. */\n    check_expr_valid(\"0 0/10 * * * ?\"); /* Every 10 minutes. */\n    check_expr_valid(\"0 0 12 L-2 * ?\"); /* Two days before the end of the month at noon. */\n    check_expr_valid(\"0 0 12 15W * ?\"); /* Nearest weekday to the 15th of every month at noon. */\n    check_expr_valid(\"0 0 0 * * ?\"); /* Every day at midnight (beginning of the day). */\n    check_expr_valid(\"0 0 23 * * ?\"); /* Every day at 11 PM (end of the day). */\n    check_expr_valid(\"0 30 10 ? * 2-6\"); /* Every weekday at 10:30 AM. */\n    check_expr_valid(\"0 0/10 8-17 ? * MON-FRI\"); /* Every 10 minutes during working hours (8 AM - 5 PM) on weekdays. */\n    /*check_expr_valid(\"0 0 12 1L * ?\"); */ /* Last day of the month at noon. */\n    check_expr_valid(\"0 0 12 ? * SUN,MON\"); /* Every Sunday and Monday at noon. */\n    check_expr_valid(\"0 0/5 9-16 * * ?\"); /* Every 5 minutes from 9 AM to 4:55 PM every day. */\n    check_expr_valid(\"0 0 12 10-15 * ?\"); /* Every day from the 10th to the 15th at noon. */\n    check_expr_valid(\"0 0 0 1 JAN-JUN ?\"); /* First day of the month from January to June at midnight. */\n    check_expr_valid(\"0 0 0 ? * 2L\"); /* Last Monday of the month at midnight. */\n    check_expr_valid(\"0 0 0 ? * 6#4\"); /* Fourth Friday of the month at midnight. */\n    check_expr_valid(\"0 0 12 1/2 * ?\"); /* Every other day at noon. */\n    check_expr_valid(\"0 0 12 ? * 2/2\"); /* Every other Monday at noon. */\n    check_expr_valid(\"0 0 0 29 FEB ?\"); /* Every 29th of February at midnight (Leap Year). */\n    check_expr_valid(\"0 0 12 1,15 * ?\"); /* 1st and 15th of the month at noon. */\n    check_expr_valid(\"0 0 0 1 * ? 2024\"); /* 1st of every month in 2024 at midnight. */\n    check_expr_valid(\"0 30 6 ? * 1-5\"); /* Weekdays at 6:30 AM. */\n    check_expr_valid(\"0 0 0/2 * * ?\"); /* Every 2 hours. */\n    check_expr_valid(\"0 0 12/3 ? * *\"); /* Every 3 hours starting at noon. */\n    check_expr_valid(\"0 15,45 * ? * *\"); /* Every hour at 15 and 45 minutes past. */\n    check_expr_valid(\"0 0 0 ? * SAT,SUN\"); /* Every weekend at midnight. */\n    check_expr_valid(\"0 0 8-10,14-16 * * ?\"); /* Every day from 8-10 AM and 2-4 PM. */\n    check_expr_valid(\"0 0 12 ? 1-6,9-12 *\"); /* Every day at noon excluding July and August. */\n    check_expr_valid(\"0 0 12/4 * * ?\"); /* Every 4 hours starting at noon. */\n    check_expr_valid(\"0 0 9-17 * * ?\"); /* Every hour from 9 AM to 5 PM. */\n    check_expr_valid(\"0 0/20 9-16 * * ?\"); /* Every 20 minutes from 9 AM to 4:40 PM. */\n    check_expr_valid(\"0 0 12 ? * 2-6\"); /* Every weekday at noon. */\n    check_expr_valid(\"0 0 8-11,13-16 * * ?\"); /* Every day from 8-11 AM and 1-4 PM. */\n    check_expr_valid(\"0 0/30 6-18 * * ?\"); /* Every 30 minutes from 6 AM to 6:30 PM. */\n    check_expr_valid(\"0 0 12 ? JAN,MAR,MAY,JUL,SEP,NOV *\"); /* Every alternate month at noon. */\n    check_expr_valid(\"0 15 9 ? * MON,TUE,WED,THU,FRI\"); /* Every weekday at 9:15 AM. */\n    check_expr_valid(\"0 0/40 * ? * *\"); /* Every 40 minutes. */\n    check_expr_valid(\"0 30 10-14 ? * ?\"); /* Every day from 10:30 AM to 2:30 PM. */\n    check_expr_valid(\"0 0 12 * JAN-DEC ?\"); /* Every day of the year at noon. */\n    check_expr_valid(\"0 0 0 25 12 ? *\"); /* Every Christmas at midnight. */\n    check_expr_valid(\"0 0 0/3 * * ?\"); /* Every 3 hours. */\n    check_expr_valid(\"0 0 12 * * ? 2025\"); /* Every day at noon in the year 2025. */\n    check_expr_valid(\"0 0 6 ? * 2-6\"); /* Every weekday at 6 AM. */\n    check_expr_valid(\"0 0 18 ? * 1-5\"); /* Every weekday at 6 PM. */\n    check_expr_valid(\"0 0 0 ? * * 2026\"); /* Every day at midnight in 2026. */\n    check_expr_valid(\"0 0/45 10-14 * * ?\"); /* Every 45 minutes between 10 AM and 2:45 PM. */\n    check_expr_valid(\"0 0 12 1/3 * ?\"); /* Every 3 days at noon. */\n    check_expr_valid(\"0 0 0 1 JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC ?\"); /* Start of every month at midnight. */\n    check_expr_valid(\"0 0 12 10,20,30 * ?\"); /* Every 10th, 20th, and 30th of the month at noon. */\n    check_expr_valid(\"0 0/50 8-16 * * ?\"); /* Every 50 minutes from 8 AM to 4:50 PM. */\n    check_expr_invalid(\"0 0 12 ? * 1#1,3#3,5#5\"); /* First Sunday, third Wednesday, and fifth Friday of every month at noon. */\n    check_expr_valid(\"0 0 0/4 * * ?\"); /* Every 4 hours. */\n    check_expr_valid(\"0 15,30,45 * * * ?\"); /* Every hour at 15, 30, and 45 minutes past. */\n    check_expr_valid(\"0 0 12 ? * 2L\"); /* Last Monday of every month at noon. */\n    check_expr_valid(\"0 0 12 ? * 5L\"); /* Last Thursday of every month at noon. */\n    check_expr_valid(\"0 0 0/6 * * ?\"); /* Every 6 hours. */\n    check_expr_valid(\"0 0 12/2 ? * *\"); /* Every 2 hours starting at noon. */\n    check_expr_valid(\"0 0 12 ? 1,3,5,7,9,11 *\"); /* Every odd month at noon. */\n    check_expr_valid(\"0 0 0 ? 2,4,6,8,10,12 *\"); /* Every even month at midnight. */\n    check_expr_valid(\"0 0 12 * * ? 2027\"); /* Every day at noon in the year 2027. */\n}\n\nvoid test_bits(void)\n{\n\n    uint8_t testbyte[8];\n    memset(testbyte, 0, 8);\n    int err = 0;\n    int i;\n\n    for (i = 0; i <= 63; i++) {\n        cron_set_bit(testbyte, i);\n        if (!cron_get_bit(testbyte, i)) {\n            printf(\"Bit set error! Bit: %d!\\n\", i);\n            err = 1;\n        }\n        cron_del_bit(testbyte, i);\n        if (cron_get_bit(testbyte, i)) {\n            printf(\"Bit clear error! Bit: %d!\\n\", i);\n            err = 1;\n        }\n        assert(!err);\n    }\n\n    for (i = 0; i < 12; i++) {\n        cron_set_bit(testbyte, i);\n    }\n    if (testbyte[0] != 0xff) {\n        err = 1;\n    }\n    if (testbyte[1] != 0x0f) {\n        err = 1;\n    }\n\n    assert(!err);\n}\n\nvoid app_main(void)\n{\n    test_bits();\n    test_expr();\n    test_parse();\n    check_calc_invalid();\n    printf(\"\\nAll OK!\\n\");\n}\n"
  },
  {
    "path": "supertinycron/examples/cron_example/main/idf_component.yml",
    "content": "description: Cron expression parsing in ANSI C.\ndependencies:\n  espressif/supertinycron:\n    version: \"*\"\n    override_path: '../../../'\n"
  },
  {
    "path": "supertinycron/idf_component.yml",
    "content": "version: \"2.0.0~2\"\ndescription: Cron expression parsing in ANSI C.\nurl: https://github.com/espressif/idf-extra-components/tree/master/supertinycron\ndependencies:\n  idf: \">=4.1\"\n"
  },
  {
    "path": "supertinycron/sbom_supertinycron.yml",
    "content": "name: supertinycron\nversion: 2.0.0\ncpe: cpe:2.3:a:supertinycron:supertinycron:{}:*:*:*:*:*:*:*\nsupplier: 'Organization: supertinycron'\ndescription: Cron expression parsing in ANSI C with tinycron tool\nurl: https://github.com/exander77/supertinycron\nhash: 30b9e373234c3c16c279e5a05f65dc07f5be9161\n"
  },
  {
    "path": "thorvg/.build-test-rules.yml",
    "content": "thorvg/examples/thorvg_lottie:\n  disable:\n    - if: IDF_TARGET not in [\"esp32s3\", \"esp32p4\"]\n      reason: Running lottie animation requires a large PSRAM\n    - if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR < 3\n      reason: test version >= 5.3 is sufficient\n"
  },
  {
    "path": "thorvg/CMakeLists.txt",
    "content": "# Set a name for libthorvg library\nset(TVG_LIB libthorvg)\nset(TVG_INC_DIR thorvg/src/bindings/capi)\nset(TVG_SUBDIR \"${CMAKE_CURRENT_SOURCE_DIR}/thorvg\")\nset(TVG_BUILD_DIR \"${CMAKE_CURRENT_BINARY_DIR}/thorvg_build\")\nset(TVG_CROSS_CFG \"${CMAKE_CURRENT_BINARY_DIR}/thorvg_build/cross_file.txt\")\nset(TVG_STATIC_LIB \"${TVG_BUILD_DIR}/src/libthorvg-1.a\")\n\nset(TVG_LOADERS_OPTION \"\")\n\nif(CONFIG_THORVG_LOTTIE_LOADER_SUPPORT)\n    list(APPEND TVG_LOADERS_OPTION \"lottie\")\nendif()\n\nif(CONFIG_THORVG_SVG_LOADER_SUPPORT)\n    list(APPEND TVG_LOADERS_OPTION \"svg\")\nendif()\n\nif(CONFIG_THORVG_PNG_LOADER_SUPPORT)\n    list(APPEND TVG_LOADERS_OPTION \"png\")\nendif()\n\nif(CONFIG_THORVG_JPEG_LOADER_SUPPORT)\n    list(APPEND TVG_LOADERS_OPTION \"jpg\")\nendif()\n\nif(CONFIG_THORVG_WEBP_LOADER_SUPPORT)\n    list(APPEND TVG_LOADERS_OPTION \"webp\")\nendif()\n\nlist(JOIN TVG_LOADERS_OPTION \",\" TVG_LOADERS_OPTION)\n\nif(CONFIG_THORVG_LOG_ENABLED)\n    set(TVG_LOG \"true\")\nelse()\n    set(TVG_LOG \"false\")\nendif()\n\nif(CONFIG_THORVG_THREAD_ENABLED)\n    set(TVG_THREADS \"true\")\nelse()\n    set(TVG_THREADS \"false\")\nendif()\n\nidf_component_register(\n    SRCS dummy.c\n    INCLUDE_DIRS \"${TVG_INC_DIR}\"\n    PRIV_REQUIRES pthread)\n\ntarget_compile_options(${COMPONENT_LIB} INTERFACE\n    $<$<COMPILE_LANGUAGE:C>:-Wno-ignored-qualifiers>\n)\n\n\n# Expands CMake flags that may contain response files (@\"file\" syntax) into a list.\n# ESP-IDF v6 uses @\"file\" syntax for response files, but Meson doesn't support this.\n# We need to expand the response file contents because:\n# 1. CMake expands @\"file\" internally, but Meson passes it literally to GCC\n# 2. GCC only supports @file (without quotes), not @\"file\"\n# 3. We can't just remove quotes because paths may contain spaces (especially on Windows)\nfunction(expand_response_file input_flags output_var)\n    set(flags ${input_flags})\n    if(flags MATCHES \"@\\\"(.+)\\\"\")\n        set(response_file \"${CMAKE_MATCH_1}\")\n        if(EXISTS \"${response_file}\")\n            file(STRINGS \"${response_file}\" flags)\n        else()\n            set(flags \"\")\n        endif()\n    else()\n        separate_arguments(flags)\n    endif()\n    list(FILTER flags EXCLUDE REGEX \"^$\")\n    # Strip surrounding double quotes from each flag e.g. \"-specs=path\" -> -specs=path)\n    # Response files from ESP-IDF v6 may contain quoted flags which cause issues with Meson\n    list(TRANSFORM flags REPLACE \"^\\\"(.*)\\\"$\" \"\\\\1\")\n    set(${output_var} ${flags} PARENT_SCOPE)\nendfunction()\n\nexpand_response_file(\"${CMAKE_CXX_FLAGS}\" compiler_args)\nexpand_response_file(\"${CMAKE_EXE_LINKER_FLAGS}\" linker_args)\n\nmessage(STATUS \"CMAKE_CXX_FLAGS: ${compiler_args}\")\nmessage(STATUS \"CMAKE_EXE_LINKER_FLAGS: ${linker_args}\")\n\n# Add pthread library path to the linker flags if threads are enabled\nif(TVG_THREADS STREQUAL \"true\")\n    idf_component_get_property(pthread_lib \"pthread\" COMPONENT_LIB GENERATOR_EXPRESSION)\n    set(pthread_lib_path_expr \"$<TARGET_FILE_DIR:${pthread_lib}>\")\n    list(APPEND linker_args \"-L${pthread_lib_path_expr}\")\n    set(TVG_REQUIRES pthread)\nendif()\n\n# Convert the list of arguments (arg;arg;arg) to a string \"'arg', 'arg', 'arg'\"\nlist(JOIN compiler_args \"', '\" MESON_CXX_FLAGS)\nset(MESON_CXX_FLAGS \"'${MESON_CXX_FLAGS}'\")\nlist(JOIN linker_args \"', '\" MESON_LINKER_FLAGS)\nset(MESON_LINKER_FLAGS \"'${MESON_LINKER_FLAGS}'\")\n\n# Please note, xtensa is not recognized by Meson, but \"riscv32\" is a safe generic option\n# Always use \"riscv32\" as cpu_family in cross_file.txt to avoid Meson warnings\nset(cpu_family \"riscv32\")\n\n# Two-step generation of cross_file.txt to expand CMake variables...\nconfigure_file(${CMAKE_CURRENT_LIST_DIR}/cross_file.txt.in ${TVG_CROSS_CFG}.tmp)\n# ...and then expand generator expressions\nfile(GENERATE OUTPUT ${TVG_CROSS_CFG} INPUT ${TVG_CROSS_CFG}.tmp)\n\ninclude(ExternalProject)\n\nExternalProject_Add(${TVG_LIB}_target\n    PREFIX ${TVG_BUILD_DIR}\n    SOURCE_DIR ${TVG_SUBDIR}\n    BINARY_DIR ${TVG_BUILD_DIR}\n    CONFIGURE_COMMAND meson setup ${TVG_BUILD_DIR} ${TVG_SUBDIR}\n    --cross-file ${TVG_CROSS_CFG}\n    -Dbindings=capi\n    -Dextra=\n    -Ddefault_library=static # build static library\n    -Db_staticpic=false # no -fPIC\n    -Dthreads=${TVG_THREADS}\n    -Dlog=${TVG_LOG} # allow log output\n    -Dloaders=${TVG_LOADERS_OPTION}   # Pass the loaders option to Meson\n    BUILD_COMMAND ninja -C ${TVG_BUILD_DIR}\n    INSTALL_COMMAND \"\"\n    BUILD_BYPRODUCTS ${TVG_STATIC_LIB}\n)\n\nadd_prebuilt_library(${TVG_LIB} ${TVG_STATIC_LIB} PRIV_REQUIRES ${TVG_REQUIRES})\nadd_dependencies(${TVG_LIB} ${TVG_LIB}_target)\n\nif(TVG_THREADS STREQUAL \"true\")\n    add_dependencies(${TVG_LIB}_target idf::pthread)\nendif()\n\ntarget_link_libraries(${COMPONENT_LIB} INTERFACE ${TVG_LIB})\n"
  },
  {
    "path": "thorvg/Kconfig",
    "content": "menu \"ThorVG Support Options\"\n\n    config THORVG_LOG_ENABLED\n        bool \"Enable ThorVG log\"\n        default n\n        help\n            Enable ThorVG log.\n\n    config THORVG_THREAD_ENABLED\n        bool \"Enable ThorVG threading support\"\n        default y\n        help\n            Enable ThorVG threading support. This option can be disabled if ThorVG is only used from one FreeRTOS task.\n\n    menu \"Loaders Support\"\n\n        config THORVG_LOTTIE_LOADER_SUPPORT\n            bool \"Enable Lottie loader support\"\n            default y\n\n        config THORVG_SVG_LOADER_SUPPORT\n            bool \"Enable svg loader support\"\n            default y\n\n        config THORVG_PNG_LOADER_SUPPORT\n            bool \"Enable png loader support\"\n            default n\n\n        config THORVG_JPEG_LOADER_SUPPORT\n            bool \"Enable jpeg loader support\"\n            default n\n\n        config THORVG_WEBP_LOADER_SUPPORT\n            bool \"Enable webp loader support\"\n            default n\n\n    endmenu\n\nendmenu\n"
  },
  {
    "path": "thorvg/LICENSE",
    "content": "Copyright (c) 2020 - 2024 notice for the ThorVG Project (see AUTHORS)\n\nPermission 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:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE 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.\n"
  },
  {
    "path": "thorvg/README.md",
    "content": "# ThorVG component\n\n[![Component Registry](https://components.espressif.com/components/espressif/thorvg/badge.svg)](https://components.espressif.com/components/espressif/thorvg)\n\nThorVG is an open-source graphics library designed for creating vector-based scenes and animations. Embracing the philosophy of \"Simpler is better,\" the ThorVG project offers intuitive and user-friendly interfaces, all the while maintaining a compact size and minimal software complexity.\n\nThis component is based on [ThorVG](https://github.com/thorvg/thorvg).\n\nTo learn more about how to use this component, please check [README.md](https://github.com/thorvg/thorvg/blob/main/README.md).\n"
  },
  {
    "path": "thorvg/cross_file.txt.in",
    "content": "[binaries]\ncpp = '${CMAKE_CXX_COMPILER}'\nar = '${CMAKE_CXX_COMPILER_AR}'\nas = '${CMAKE_ASM_COMPILER}'\nranlib = '${CMAKE_CXX_COMPILER_RANLIB}'\nld = '${CMAKE_LINKER}'\nstrip = '${CMAKE_STRIP}'\n\n[built-in options]\ncpp_args = ['-D_GNU_SOURCE','-D__linux__','-Wno-format','-Wno-stringop-truncation',${MESON_CXX_FLAGS}]\ncpp_link_args = [${MESON_LINKER_FLAGS}]\n\n[host_machine]\nsystem = 'esp-idf'\ncpu_family = '${cpu_family}'\ncpu = 'esp'\nendian = 'little'\n"
  },
  {
    "path": "thorvg/dummy.c",
    "content": ""
  },
  {
    "path": "thorvg/examples/thorvg_lottie/CMakeLists.txt",
    "content": "# For more information about build system see\n# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html\n# The following five lines of boilerplate have to be in your project's\n# CMakeLists in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(thorvg-example)\n"
  },
  {
    "path": "thorvg/examples/thorvg_lottie/README.md",
    "content": "# ThorVG Lottie Animation Example\n\nThis is a minimalistic display + ThorVG graphics library example that demonstrates how to render Lottie animations on an ESP device. With just a few function calls, it sets up the display and shows Lottie animations using the ThorVG vector graphics engine.\n\n## Overview\n\nThis example demonstrates:\n- Setting up an SPI LCD display (SH8601 controller)\n- Initializing the ThorVG vector graphics engine\n- Loading and rendering a Lottie animation from a JSON file\n- Converting graphics buffers from ARGB8888 to RGB565 format for display\n\n## Hardware Required\n\n- An ESP32 device with PSRAM support (necessary for the graphic buffers)\n- An SPI LCD display (the example uses SH8601 controller by default)\n\n## Building and Running\n\n1. Prepare your project's partition table to include a LittleFS partition named \"storage\"\n2. Place your Lottie animation file (in JSON format) in the project's \"storage\" directory with the name \"emoji-animation.json\"\n3. Build and flash the application as usual for an ESP-IDF project:\n\n```\nidf.py set-target esp32s3\nidf.py -p PORT flash monitor\n```\n\n## Customizing the Example\n\n### Using a Different LCD Display\n\nIf you are using a different LCD controller, you'll need to:\n\n1. Replace the SH8601-specific initialization code in the `main/thorvg_example_main.c` file:\n   - Update the LCD pin configurations\n   - Replace the `esp_lcd_new_panel_sh8601()` call with the appropriate function for your LCD\n   - Modify the LCD initialization commands as required by your display\n\n### Using a Different Lottie File\n\nTo use your own Lottie animation:\n\n1. Ensure your animation file is in JSON format\n2. Update the `EXAMPLE_LOTTIE_FILENAME` macro in the code to match your file path\n3. Adjust the `EXAMPLE_LOTTIE_SIZE_HOR` and `EXAMPLE_LOTTIE_SIZE_VER` macros if your animation has different dimensions\n\n## Memory Usage\n\nThis example allocates graphic buffers in PSRAM:\n- One ARGB8888 buffer (4 bytes per pixel) for ThorVG rendering\n- One RGB565 buffer (2 bytes per pixel) for LCD output\n\nEnsure your device has sufficient PSRAM for these buffers, especially when increasing animation dimensions.\n"
  },
  {
    "path": "thorvg/examples/thorvg_lottie/lottie_files/emoji-animation.json",
    "content": "{\n    \"v\": \"5.5.7\",\n    \"fr\": 24,\n    \"ip\": 0,\n    \"op\": 48,\n    \"w\": 1024,\n    \"h\": 1024,\n    \"nm\": \"party_face\",\n    \"ddd\": 0,\n    \"assets\": [\n        {\n            \"id\": \"comp_0\",\n            \"layers\": [\n                {\n                    \"ddd\": 0,\n                    \"ind\": 1,\n                    \"ty\": 3,\n                    \"nm\": \"Face_CTRL\",\n                    \"parent\": 2,\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": { \"a\": 0, \"k\": 100, \"ix\": 11 },\n                        \"r\": { \"a\": 0, \"k\": 0, \"ix\": 10 },\n                        \"p\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": 0.833, \"y\": 0.833 },\n                                    \"o\": { \"x\": 0.333, \"y\": 0 },\n                                    \"t\": 0,\n                                    \"s\": [0, -286, 0],\n                                    \"to\": [0.092, 3.435, 0],\n                                    \"ti\": [0.627, 6.25, 0]\n                                },\n                                {\n                                    \"i\": { \"x\": 0, \"y\": 1 },\n                                    \"o\": { \"x\": 0.167, \"y\": 0.167 },\n                                    \"t\": 4,\n                                    \"s\": [0.552, -265.39, 0],\n                                    \"to\": [-0.627, -6.25, 0],\n                                    \"ti\": [0.092, 3.435, 0]\n                                },\n                                {\n                                    \"i\": { \"x\": 0, \"y\": 1 },\n                                    \"o\": { \"x\": 0.333, \"y\": 0 },\n                                    \"t\": 18,\n                                    \"s\": [-3.763, -323.5, 0],\n                                    \"to\": [-0.092, -3.435, 0],\n                                    \"ti\": [-0.627, -6.25, 0]\n                                },\n                                { \"t\": 26, \"s\": [0, -286, 0] }\n                            ],\n                            \"ix\": 2\n                        },\n                        \"a\": { \"a\": 0, \"k\": [0, 0, 0], \"ix\": 1 },\n                        \"s\": { \"a\": 0, \"k\": [100, 100, 100], \"ix\": 6 }\n                    },\n                    \"ao\": 0,\n                    \"ef\": [\n                        {\n                            \"ty\": 5,\n                            \"nm\": \"Controller\",\n                            \"np\": 13,\n                            \"mn\": \"Pseudo/DUIK controller\",\n                            \"ix\": 1,\n                            \"en\": 1,\n                            \"ef\": [\n                                {\n                                    \"ty\": 6,\n                                    \"nm\": \"Icon\",\n                                    \"mn\": \"Pseudo/DUIK controller-0001\",\n                                    \"ix\": 1,\n                                    \"v\": 0\n                                },\n                                {\n                                    \"ty\": 2,\n                                    \"nm\": \"Color\",\n                                    \"mn\": \"Pseudo/DUIK controller-0002\",\n                                    \"ix\": 2,\n                                    \"v\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            0.92549020052, 0.0941176489,\n                                            0.0941176489, 1\n                                        ],\n                                        \"ix\": 2\n                                    }\n                                },\n                                {\n                                    \"ty\": 3,\n                                    \"nm\": \"Position\",\n                                    \"mn\": \"Pseudo/DUIK controller-0003\",\n                                    \"ix\": 3,\n                                    \"v\": { \"a\": 0, \"k\": [0, 0], \"ix\": 3 }\n                                },\n                                {\n                                    \"ty\": 0,\n                                    \"nm\": \"Size\",\n                                    \"mn\": \"Pseudo/DUIK controller-0004\",\n                                    \"ix\": 4,\n                                    \"v\": { \"a\": 0, \"k\": 100, \"ix\": 4 }\n                                },\n                                {\n                                    \"ty\": 0,\n                                    \"nm\": \"Orientation\",\n                                    \"mn\": \"Pseudo/DUIK controller-0005\",\n                                    \"ix\": 5,\n                                    \"v\": { \"a\": 0, \"k\": 0, \"ix\": 5 }\n                                },\n                                {\n                                    \"ty\": 0,\n                                    \"nm\": \"Opacity\",\n                                    \"mn\": \"Pseudo/DUIK controller-0006\",\n                                    \"ix\": 6,\n                                    \"v\": { \"a\": 0, \"k\": 100, \"ix\": 6 }\n                                },\n                                {\n                                    \"ty\": 6,\n                                    \"nm\": \"\",\n                                    \"mn\": \"Pseudo/DUIK controller-0007\",\n                                    \"ix\": 7,\n                                    \"v\": 0\n                                },\n                                {\n                                    \"ty\": 6,\n                                    \"nm\": \"Anchor\",\n                                    \"mn\": \"Pseudo/DUIK controller-0008\",\n                                    \"ix\": 8,\n                                    \"v\": 0\n                                },\n                                {\n                                    \"ty\": 2,\n                                    \"nm\": \"Color\",\n                                    \"mn\": \"Pseudo/DUIK controller-0009\",\n                                    \"ix\": 9,\n                                    \"v\": { \"a\": 0, \"k\": [0, 0, 0, 1], \"ix\": 9 }\n                                },\n                                {\n                                    \"ty\": 0,\n                                    \"nm\": \"Size\",\n                                    \"mn\": \"Pseudo/DUIK controller-0010\",\n                                    \"ix\": 10,\n                                    \"v\": { \"a\": 0, \"k\": 100, \"ix\": 10 }\n                                },\n                                {\n                                    \"ty\": 6,\n                                    \"nm\": \"\",\n                                    \"mn\": \"Pseudo/DUIK controller-0011\",\n                                    \"ix\": 11,\n                                    \"v\": 0\n                                }\n                            ]\n                        }\n                    ],\n                    \"ip\": 0,\n                    \"op\": 48,\n                    \"st\": 0,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 2,\n                    \"ty\": 3,\n                    \"nm\": \"Head_CTRL\",\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": { \"a\": 0, \"k\": 100, \"ix\": 11 },\n                        \"r\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": [0], \"y\": [1] },\n                                    \"o\": { \"x\": [0.333], \"y\": [0] },\n                                    \"t\": 0,\n                                    \"s\": [0]\n                                },\n                                {\n                                    \"i\": { \"x\": [0.667], \"y\": [1] },\n                                    \"o\": { \"x\": [0.333], \"y\": [0] },\n                                    \"t\": 18,\n                                    \"s\": [4]\n                                },\n                                {\n                                    \"i\": { \"x\": [0], \"y\": [1] },\n                                    \"o\": { \"x\": [0.333], \"y\": [0] },\n                                    \"t\": 26,\n                                    \"s\": [-1]\n                                },\n                                { \"t\": 48, \"s\": [0] }\n                            ],\n                            \"ix\": 10\n                        },\n                        \"p\": { \"a\": 0, \"k\": [517.24, 850.396, 0], \"ix\": 2 },\n                        \"a\": { \"a\": 0, \"k\": [0, 0, 0], \"ix\": 1 },\n                        \"s\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": {\n                                        \"x\": [0.833, 0.833, 0.833],\n                                        \"y\": [0.833, 0.833, 1]\n                                    },\n                                    \"o\": {\n                                        \"x\": [0.333, 0.333, 0.333],\n                                        \"y\": [0, 0, 0]\n                                    },\n                                    \"t\": 0,\n                                    \"s\": [100, 100, 100]\n                                },\n                                {\n                                    \"i\": { \"x\": [0, 0, 0.667], \"y\": [1, 1, 1] },\n                                    \"o\": {\n                                        \"x\": [0.167, 0.167, 0.167],\n                                        \"y\": [0.167, 0.167, 0]\n                                    },\n                                    \"t\": 4,\n                                    \"s\": [103, 97, 100]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": [0.667, 0.667, 0.667],\n                                        \"y\": [1, 1, 1]\n                                    },\n                                    \"o\": {\n                                        \"x\": [0.333, 0.333, 0.333],\n                                        \"y\": [0, 0, 0]\n                                    },\n                                    \"t\": 18,\n                                    \"s\": [97, 103, 100]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": [0, 0.051, 0.667],\n                                        \"y\": [1, 1, 1]\n                                    },\n                                    \"o\": {\n                                        \"x\": [0.333, 0.333, 0.333],\n                                        \"y\": [0, 0, 0]\n                                    },\n                                    \"t\": 26,\n                                    \"s\": [103, 97, 100]\n                                },\n                                { \"t\": 48, \"s\": [100, 100, 100] }\n                            ],\n                            \"ix\": 6\n                        }\n                    },\n                    \"ao\": 0,\n                    \"ef\": [\n                        {\n                            \"ty\": 5,\n                            \"nm\": \"Controller\",\n                            \"np\": 13,\n                            \"mn\": \"Pseudo/DUIK controller\",\n                            \"ix\": 1,\n                            \"en\": 1,\n                            \"ef\": [\n                                {\n                                    \"ty\": 6,\n                                    \"nm\": \"Icon\",\n                                    \"mn\": \"Pseudo/DUIK controller-0001\",\n                                    \"ix\": 1,\n                                    \"v\": 0\n                                },\n                                {\n                                    \"ty\": 2,\n                                    \"nm\": \"Color\",\n                                    \"mn\": \"Pseudo/DUIK controller-0002\",\n                                    \"ix\": 2,\n                                    \"v\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            0.92549020052, 0.0941176489,\n                                            0.0941176489, 1\n                                        ],\n                                        \"ix\": 2\n                                    }\n                                },\n                                {\n                                    \"ty\": 3,\n                                    \"nm\": \"Position\",\n                                    \"mn\": \"Pseudo/DUIK controller-0003\",\n                                    \"ix\": 3,\n                                    \"v\": { \"a\": 0, \"k\": [0, 0], \"ix\": 3 }\n                                },\n                                {\n                                    \"ty\": 0,\n                                    \"nm\": \"Size\",\n                                    \"mn\": \"Pseudo/DUIK controller-0004\",\n                                    \"ix\": 4,\n                                    \"v\": { \"a\": 0, \"k\": 100, \"ix\": 4 }\n                                },\n                                {\n                                    \"ty\": 0,\n                                    \"nm\": \"Orientation\",\n                                    \"mn\": \"Pseudo/DUIK controller-0005\",\n                                    \"ix\": 5,\n                                    \"v\": { \"a\": 0, \"k\": 0, \"ix\": 5 }\n                                },\n                                {\n                                    \"ty\": 0,\n                                    \"nm\": \"Opacity\",\n                                    \"mn\": \"Pseudo/DUIK controller-0006\",\n                                    \"ix\": 6,\n                                    \"v\": { \"a\": 0, \"k\": 100, \"ix\": 6 }\n                                },\n                                {\n                                    \"ty\": 6,\n                                    \"nm\": \"\",\n                                    \"mn\": \"Pseudo/DUIK controller-0007\",\n                                    \"ix\": 7,\n                                    \"v\": 0\n                                },\n                                {\n                                    \"ty\": 6,\n                                    \"nm\": \"Anchor\",\n                                    \"mn\": \"Pseudo/DUIK controller-0008\",\n                                    \"ix\": 8,\n                                    \"v\": 0\n                                },\n                                {\n                                    \"ty\": 2,\n                                    \"nm\": \"Color\",\n                                    \"mn\": \"Pseudo/DUIK controller-0009\",\n                                    \"ix\": 9,\n                                    \"v\": { \"a\": 0, \"k\": [0, 0, 0, 1], \"ix\": 9 }\n                                },\n                                {\n                                    \"ty\": 0,\n                                    \"nm\": \"Size\",\n                                    \"mn\": \"Pseudo/DUIK controller-0010\",\n                                    \"ix\": 10,\n                                    \"v\": { \"a\": 0, \"k\": 100, \"ix\": 10 }\n                                },\n                                {\n                                    \"ty\": 6,\n                                    \"nm\": \"\",\n                                    \"mn\": \"Pseudo/DUIK controller-0011\",\n                                    \"ix\": 11,\n                                    \"v\": 0\n                                }\n                            ]\n                        }\n                    ],\n                    \"ip\": 0,\n                    \"op\": 49,\n                    \"st\": 0,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 3,\n                    \"ty\": 4,\n                    \"nm\": \"HatStripe\",\n                    \"parent\": 6,\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": { \"a\": 0, \"k\": 100, \"ix\": 11 },\n                        \"r\": { \"a\": 0, \"k\": 0, \"ix\": 10 },\n                        \"p\": { \"a\": 0, \"k\": [0, 0, 0], \"ix\": 2 },\n                        \"a\": { \"a\": 0, \"k\": [0, 0, 0], \"ix\": 1 },\n                        \"s\": { \"a\": 0, \"k\": [100, 100, 100], \"ix\": 6 }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ind\": 0,\n                                    \"ty\": \"sh\",\n                                    \"ix\": 1,\n                                    \"ks\": {\n                                        \"a\": 0,\n                                        \"k\": {\n                                            \"i\": [\n                                                [0, 0],\n                                                [0, 0],\n                                                [0, 0],\n                                                [4.631, 7.095]\n                                            ],\n                                            \"o\": [\n                                                [3.818, 5.331],\n                                                [0, 0],\n                                                [0, 0],\n                                                [0, 0]\n                                            ],\n                                            \"v\": [\n                                                [9.463, -26.924],\n                                                [16.938, -19.632],\n                                                [17.467, -14.328],\n                                                [6.154, -25.348]\n                                            ],\n                                            \"c\": true\n                                        },\n                                        \"ix\": 2\n                                    },\n                                    \"nm\": \"Tracé 1\",\n                                    \"mn\": \"ADBE Vector Shape - Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"gf\",\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 10 },\n                                    \"r\": 1,\n                                    \"bm\": 0,\n                                    \"g\": {\n                                        \"p\": 9,\n                                        \"k\": {\n                                            \"a\": 0,\n                                            \"k\": [\n                                                0.176, 0.91, 0.302, 0.533,\n                                                0.267, 0.9, 0.292, 0.524, 0.359,\n                                                0.89, 0.282, 0.514, 0.474,\n                                                0.863, 0.251, 0.484, 0.588,\n                                                0.835, 0.22, 0.455, 0.715,\n                                                0.792, 0.171, 0.406, 0.842,\n                                                0.749, 0.122, 0.357, 0.921,\n                                                0.714, 0.082, 0.32, 1, 0.678,\n                                                0.043, 0.282\n                                            ],\n                                            \"ix\": 9\n                                        }\n                                    },\n                                    \"s\": {\n                                        \"a\": 0,\n                                        \"k\": [10.307, -30.112],\n                                        \"ix\": 5\n                                    },\n                                    \"e\": {\n                                        \"a\": 0,\n                                        \"k\": [20.858, -18.045],\n                                        \"ix\": 6\n                                    },\n                                    \"t\": 1,\n                                    \"nm\": \"Stripegradienta\",\n                                    \"mn\": \"ADBE Vector Graphic - G-Fill\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": { \"a\": 0, \"k\": [0, 0], \"ix\": 2 },\n                                    \"a\": { \"a\": 0, \"k\": [0, 0], \"ix\": 1 },\n                                    \"s\": { \"a\": 0, \"k\": [100, 100], \"ix\": 3 },\n                                    \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                    \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                    \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"HatStripe\",\n                            \"np\": 2,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 0,\n                    \"op\": 49,\n                    \"st\": 0,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 4,\n                    \"ty\": 4,\n                    \"nm\": \"HatStripe1\",\n                    \"parent\": 6,\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": { \"a\": 0, \"k\": 100, \"ix\": 11 },\n                        \"r\": { \"a\": 0, \"k\": 0, \"ix\": 10 },\n                        \"p\": { \"a\": 0, \"k\": [0, 0, 0], \"ix\": 2 },\n                        \"a\": { \"a\": 0, \"k\": [0, 0, 0], \"ix\": 1 },\n                        \"s\": { \"a\": 0, \"k\": [100, 100, 100], \"ix\": 6 }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ind\": 0,\n                                    \"ty\": \"sh\",\n                                    \"ix\": 1,\n                                    \"ks\": {\n                                        \"a\": 0,\n                                        \"k\": {\n                                            \"i\": [\n                                                [0, 0],\n                                                [0, 0],\n                                                [0, 0],\n                                                [3.103, 1.552],\n                                                [5.313, 8.386]\n                                            ],\n                                            \"o\": [\n                                                [6.646, 8.84],\n                                                [0, 0],\n                                                [-0.334, 0.638],\n                                                [0, 0],\n                                                [0, 0]\n                                            ],\n                                            \"v\": [\n                                                [2.846, -23.771],\n                                                [17.989, -9.078],\n                                                [18.085, -8.12],\n                                                [12.218, -9.919],\n                                                [-0.462, -22.195]\n                                            ],\n                                            \"c\": true\n                                        },\n                                        \"ix\": 2\n                                    },\n                                    \"nm\": \"Tracé 1\",\n                                    \"mn\": \"ADBE Vector Shape - Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"gf\",\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 10 },\n                                    \"r\": 1,\n                                    \"bm\": 0,\n                                    \"g\": {\n                                        \"p\": 9,\n                                        \"k\": {\n                                            \"a\": 0,\n                                            \"k\": [\n                                                0.176, 0.91, 0.302, 0.533,\n                                                0.267, 0.9, 0.292, 0.524, 0.359,\n                                                0.89, 0.282, 0.514, 0.474,\n                                                0.863, 0.251, 0.484, 0.588,\n                                                0.835, 0.22, 0.455, 0.715,\n                                                0.792, 0.171, 0.406, 0.842,\n                                                0.749, 0.122, 0.357, 0.921,\n                                                0.714, 0.082, 0.32, 1, 0.678,\n                                                0.043, 0.282\n                                            ],\n                                            \"ix\": 9\n                                        }\n                                    },\n                                    \"s\": {\n                                        \"a\": 0,\n                                        \"k\": [10.307, -30.112],\n                                        \"ix\": 5\n                                    },\n                                    \"e\": {\n                                        \"a\": 0,\n                                        \"k\": [23.622, -15.706],\n                                        \"ix\": 6\n                                    },\n                                    \"t\": 1,\n                                    \"nm\": \"Stripegradientb\",\n                                    \"mn\": \"ADBE Vector Graphic - G-Fill\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": { \"a\": 0, \"k\": [0, 0], \"ix\": 2 },\n                                    \"a\": { \"a\": 0, \"k\": [0, 0], \"ix\": 1 },\n                                    \"s\": { \"a\": 0, \"k\": [100, 100], \"ix\": 3 },\n                                    \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                    \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                    \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"HatStripe1\",\n                            \"np\": 2,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 0,\n                    \"op\": 49,\n                    \"st\": 0,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 5,\n                    \"ty\": 4,\n                    \"nm\": \"HatStripe2\",\n                    \"parent\": 6,\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": { \"a\": 0, \"k\": 100, \"ix\": 11 },\n                        \"r\": { \"a\": 0, \"k\": 0, \"ix\": 10 },\n                        \"p\": { \"a\": 0, \"k\": [0, 0, 0], \"ix\": 2 },\n                        \"a\": { \"a\": 0, \"k\": [0, 0, 0], \"ix\": 1 },\n                        \"s\": { \"a\": 0, \"k\": [100, 100, 100], \"ix\": 6 }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ind\": 0,\n                                    \"ty\": \"sh\",\n                                    \"ix\": 1,\n                                    \"ks\": {\n                                        \"a\": 0,\n                                        \"k\": {\n                                            \"i\": [\n                                                [0, 0],\n                                                [0, 0],\n                                                [1.385, 2.573]\n                                            ],\n                                            \"o\": [\n                                                [0, 0],\n                                                [0, 0],\n                                                [0, 0]\n                                            ],\n                                            \"v\": [\n                                                [15.906, -29.994],\n                                                [16.41, -24.931],\n                                                [12.732, -28.48]\n                                            ],\n                                            \"c\": true\n                                        },\n                                        \"ix\": 2\n                                    },\n                                    \"nm\": \"Tracé 1\",\n                                    \"mn\": \"ADBE Vector Shape - Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"gf\",\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 10 },\n                                    \"r\": 1,\n                                    \"bm\": 0,\n                                    \"g\": {\n                                        \"p\": 9,\n                                        \"k\": {\n                                            \"a\": 0,\n                                            \"k\": [\n                                                0.176, 0.91, 0.302, 0.533,\n                                                0.267, 0.9, 0.292, 0.524, 0.359,\n                                                0.89, 0.282, 0.514, 0.474,\n                                                0.863, 0.251, 0.484, 0.588,\n                                                0.835, 0.22, 0.455, 0.715,\n                                                0.792, 0.171, 0.406, 0.842,\n                                                0.749, 0.122, 0.357, 0.921,\n                                                0.714, 0.082, 0.32, 1, 0.678,\n                                                0.043, 0.282\n                                            ],\n                                            \"ix\": 9\n                                        }\n                                    },\n                                    \"s\": {\n                                        \"a\": 0,\n                                        \"k\": [10.307, -30.112],\n                                        \"ix\": 5\n                                    },\n                                    \"e\": {\n                                        \"a\": 0,\n                                        \"k\": [18.414, -21.744],\n                                        \"ix\": 6\n                                    },\n                                    \"t\": 1,\n                                    \"nm\": \"Stripegradientc\",\n                                    \"mn\": \"ADBE Vector Graphic - G-Fill\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": { \"a\": 0, \"k\": [0, 0], \"ix\": 2 },\n                                    \"a\": { \"a\": 0, \"k\": [0, 0], \"ix\": 1 },\n                                    \"s\": { \"a\": 0, \"k\": [100, 100], \"ix\": 3 },\n                                    \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                    \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                    \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"HatStripe2\",\n                            \"np\": 2,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 0,\n                    \"op\": 49,\n                    \"st\": 0,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 6,\n                    \"ty\": 4,\n                    \"nm\": \"Hat\",\n                    \"parent\": 21,\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": { \"a\": 0, \"k\": 100, \"ix\": 11 },\n                        \"r\": { \"a\": 0, \"k\": 2, \"ix\": 10 },\n                        \"p\": { \"a\": 0, \"k\": [-230.213, 207.025, 0], \"ix\": 2 },\n                        \"a\": { \"a\": 0, \"k\": [9.386, -12.953, 0], \"ix\": 1 },\n                        \"s\": { \"a\": 0, \"k\": [115.214, 105.229, 100], \"ix\": 6 }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ind\": 0,\n                                    \"ty\": \"sh\",\n                                    \"ix\": 1,\n                                    \"ks\": {\n                                        \"a\": 0,\n                                        \"k\": {\n                                            \"i\": [\n                                                [0, 0],\n                                                [0, 0],\n                                                [-1.048, 1.975]\n                                            ],\n                                            \"o\": [\n                                                [0, 0],\n                                                [-1.045, 1.979],\n                                                [0, 0]\n                                            ],\n                                            \"v\": [\n                                                [15.906, -29.995],\n                                                [18.084, -8.12],\n                                                [-3.275, -20.853]\n                                            ],\n                                            \"c\": true\n                                        },\n                                        \"ix\": 2\n                                    },\n                                    \"nm\": \"Tracé 1\",\n                                    \"mn\": \"ADBE Vector Shape - Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"gf\",\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 10 },\n                                    \"r\": 1,\n                                    \"bm\": 0,\n                                    \"g\": {\n                                        \"p\": 11,\n                                        \"k\": {\n                                            \"a\": 0,\n                                            \"k\": [\n                                                0.115, 0.459, 0.839, 1, 0.198,\n                                                0.451, 0.831, 0.992, 0.282,\n                                                0.443, 0.824, 0.984, 0.372,\n                                                0.418, 0.798, 0.959, 0.461,\n                                                0.392, 0.773, 0.933, 0.555,\n                                                0.349, 0.731, 0.894, 0.648,\n                                                0.306, 0.69, 0.855, 0.743,\n                                                0.247, 0.633, 0.798, 0.838,\n                                                0.188, 0.576, 0.741, 0.919,\n                                                0.125, 0.516, 0.68, 1, 0.063,\n                                                0.455, 0.62\n                                            ],\n                                            \"ix\": 9\n                                        }\n                                    },\n                                    \"s\": {\n                                        \"a\": 0,\n                                        \"k\": [-3.016, -26.005],\n                                        \"ix\": 5\n                                    },\n                                    \"e\": {\n                                        \"a\": 0,\n                                        \"k\": [13.937, -7.054],\n                                        \"ix\": 6\n                                    },\n                                    \"t\": 1,\n                                    \"nm\": \"Hatgradient\",\n                                    \"mn\": \"ADBE Vector Graphic - G-Fill\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": { \"a\": 0, \"k\": [0, 0], \"ix\": 2 },\n                                    \"a\": { \"a\": 0, \"k\": [0, 0], \"ix\": 1 },\n                                    \"s\": { \"a\": 0, \"k\": [100, 100], \"ix\": 3 },\n                                    \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                    \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                    \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"Hat\",\n                            \"np\": 2,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 0,\n                    \"op\": 49,\n                    \"st\": 0,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 7,\n                    \"ty\": 4,\n                    \"nm\": \"Confetti11\",\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": { \"a\": 0, \"k\": 100, \"ix\": 11 },\n                        \"r\": { \"a\": 0, \"k\": -74, \"ix\": 10 },\n                        \"p\": { \"a\": 0, \"k\": [135.111, 329.463, 0], \"ix\": 2 },\n                        \"a\": { \"a\": 0, \"k\": [16.786, 25.814, 0], \"ix\": 1 },\n                        \"s\": { \"a\": 0, \"k\": [1381.996, 1381.996, 100], \"ix\": 6 }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ind\": 0,\n                                    \"ty\": \"sh\",\n                                    \"ix\": 1,\n                                    \"ks\": {\n                                        \"a\": 0,\n                                        \"k\": {\n                                            \"i\": [\n                                                [0, 0],\n                                                [-1.175, -0.325],\n                                                [-0.525, 0.4],\n                                                [-0.469, -0.175],\n                                                [-0.66, 1.01],\n                                                [-1.025, -0.249],\n                                                [-0.1, -0.725]\n                                            ],\n                                            \"o\": [\n                                                [0, 0],\n                                                [1.298, 0.359],\n                                                [0.525, -0.4],\n                                                [1.275, 0.475],\n                                                [0.85, -1.3],\n                                                [1.75, 0.425],\n                                                [0.269, 1.224]\n                                            ],\n                                            \"v\": [\n                                                [8.8, 29.45],\n                                                [12.675, 25.025],\n                                                [14.575, 27.625],\n                                                [16.675, 23.625],\n                                                [19.2, 26.775],\n                                                [22.125, 23.425],\n                                                [24.325, 26.75]\n                                            ],\n                                            \"c\": false\n                                        },\n                                        \"ix\": 2\n                                    },\n                                    \"nm\": \"Tracé 1\",\n                                    \"mn\": \"ADBE Vector Shape - Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tm\",\n                                    \"s\": {\n                                        \"a\": 1,\n                                        \"k\": [\n                                            {\n                                                \"i\": { \"x\": [0.667], \"y\": [1] },\n                                                \"o\": { \"x\": [0.333], \"y\": [0] },\n                                                \"t\": 19,\n                                                \"s\": [100]\n                                            },\n                                            { \"t\": 40, \"s\": [0] }\n                                        ],\n                                        \"ix\": 1\n                                    },\n                                    \"e\": {\n                                        \"a\": 1,\n                                        \"k\": [\n                                            {\n                                                \"i\": { \"x\": [0.667], \"y\": [1] },\n                                                \"o\": { \"x\": [0.333], \"y\": [0] },\n                                                \"t\": 15,\n                                                \"s\": [100]\n                                            },\n                                            { \"t\": 36, \"s\": [0] }\n                                        ],\n                                        \"ix\": 2\n                                    },\n                                    \"o\": { \"a\": 0, \"k\": 0, \"ix\": 3 },\n                                    \"m\": 1,\n                                    \"ix\": 2,\n                                    \"nm\": \"Raccorder les tracés 1\",\n                                    \"mn\": \"ADBE Vector Filter - Trim\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"st\",\n                                    \"c\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            0.650980392157, 0.901960844152,\n                                            0.223529426724, 1\n                                        ],\n                                        \"ix\": 3\n                                    },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 4 },\n                                    \"w\": { \"a\": 0, \"k\": 2, \"ix\": 5 },\n                                    \"lc\": 1,\n                                    \"lj\": 1,\n                                    \"ml\": 4,\n                                    \"bm\": 0,\n                                    \"nm\": \"green\",\n                                    \"mn\": \"ADBE Vector Graphic - Stroke\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": { \"a\": 0, \"k\": [0, 0], \"ix\": 2 },\n                                    \"a\": { \"a\": 0, \"k\": [0, 0], \"ix\": 1 },\n                                    \"s\": { \"a\": 0, \"k\": [100, 100], \"ix\": 3 },\n                                    \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                    \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                    \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"Forme 1\",\n                            \"np\": 3,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 15,\n                    \"op\": 42,\n                    \"st\": 15,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 8,\n                    \"ty\": 4,\n                    \"nm\": \"Confetti10\",\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": { \"a\": 0, \"k\": 100, \"ix\": 11 },\n                        \"r\": { \"a\": 0, \"k\": 0, \"ix\": 10 },\n                        \"p\": { \"a\": 0, \"k\": [873, 522.696, 0], \"ix\": 2 },\n                        \"a\": { \"a\": 0, \"k\": [25.11, 6.511, 0], \"ix\": 1 },\n                        \"s\": { \"a\": 0, \"k\": [1381.996, 1381.996, 100], \"ix\": 6 }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ind\": 0,\n                                    \"ty\": \"sh\",\n                                    \"ix\": 1,\n                                    \"ks\": {\n                                        \"a\": 0,\n                                        \"k\": {\n                                            \"i\": [\n                                                [-3.116, 1.363],\n                                                [0.225, 0.8],\n                                                [-0.35, 1.125],\n                                                [-0.05, 0.35],\n                                                [0.3, 0.675],\n                                                [-0.425, 0.475],\n                                                [1.275, 0]\n                                            ],\n                                            \"o\": [\n                                                [1.6, -0.7],\n                                                [-0.225, -0.8],\n                                                [0.35, -1.125],\n                                                [0.05, -0.35],\n                                                [-0.3, -0.675],\n                                                [0.425, -0.475],\n                                                [-1.275, 0]\n                                            ],\n                                            \"v\": [\n                                                [24.6, 13.6],\n                                                [28.575, 11.15],\n                                                [24.25, 8.375],\n                                                [26.2, 5.125],\n                                                [21.65, 4.95],\n                                                [24.55, 0.35],\n                                                [22.6, -0.675]\n                                            ],\n                                            \"c\": false\n                                        },\n                                        \"ix\": 2\n                                    },\n                                    \"nm\": \"Tracé 1\",\n                                    \"mn\": \"ADBE Vector Shape - Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tm\",\n                                    \"s\": {\n                                        \"a\": 1,\n                                        \"k\": [\n                                            {\n                                                \"i\": { \"x\": [0.667], \"y\": [1] },\n                                                \"o\": { \"x\": [0.333], \"y\": [0] },\n                                                \"t\": 4,\n                                                \"s\": [100]\n                                            },\n                                            { \"t\": 25, \"s\": [0] }\n                                        ],\n                                        \"ix\": 1\n                                    },\n                                    \"e\": {\n                                        \"a\": 1,\n                                        \"k\": [\n                                            {\n                                                \"i\": { \"x\": [0.667], \"y\": [1] },\n                                                \"o\": { \"x\": [0.333], \"y\": [0] },\n                                                \"t\": 0,\n                                                \"s\": [100]\n                                            },\n                                            { \"t\": 21, \"s\": [0] }\n                                        ],\n                                        \"ix\": 2\n                                    },\n                                    \"o\": { \"a\": 0, \"k\": 0, \"ix\": 3 },\n                                    \"m\": 1,\n                                    \"ix\": 2,\n                                    \"nm\": \"Raccorder les tracés 1\",\n                                    \"mn\": \"ADBE Vector Filter - Trim\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"st\",\n                                    \"c\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            0.909803981407, 0.109803929048,\n                                            0.152941176471, 1\n                                        ],\n                                        \"ix\": 3\n                                    },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 4 },\n                                    \"w\": { \"a\": 0, \"k\": 2, \"ix\": 5 },\n                                    \"lc\": 1,\n                                    \"lj\": 1,\n                                    \"ml\": 4,\n                                    \"bm\": 0,\n                                    \"nm\": \"Contour 1\",\n                                    \"mn\": \"ADBE Vector Graphic - Stroke\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": { \"a\": 0, \"k\": [0, 0], \"ix\": 2 },\n                                    \"a\": { \"a\": 0, \"k\": [0, 0], \"ix\": 1 },\n                                    \"s\": { \"a\": 0, \"k\": [100, 100], \"ix\": 3 },\n                                    \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                    \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                    \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"Forme 1\",\n                            \"np\": 3,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 0,\n                    \"op\": 30,\n                    \"st\": 0,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 9,\n                    \"ty\": 4,\n                    \"nm\": \"Layer 10\",\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 1,\n                                    \"s\": [4]\n                                },\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 3,\n                                    \"s\": [100]\n                                },\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 18,\n                                    \"s\": [100]\n                                },\n                                { \"t\": 20, \"s\": [0] }\n                            ],\n                            \"ix\": 11\n                        },\n                        \"r\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 1,\n                                    \"s\": [0]\n                                },\n                                { \"t\": 19, \"s\": [149] }\n                            ],\n                            \"ix\": 10\n                        },\n                        \"p\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": 0.833, \"y\": 0.833 },\n                                    \"o\": { \"x\": 0.167, \"y\": 0.167 },\n                                    \"t\": 1,\n                                    \"s\": [194.929, 367.888, 0],\n                                    \"to\": [0, 46.667, 0],\n                                    \"ti\": [0, -46.667, 0]\n                                },\n                                { \"t\": 20, \"s\": [194.929, 647.888, 0] }\n                            ],\n                            \"ix\": 2\n                        },\n                        \"a\": { \"a\": 0, \"k\": [-270.075, 219.877, 0], \"ix\": 1 },\n                        \"s\": { \"a\": 0, \"k\": [1262, 1262, 100], \"ix\": 6 }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ind\": 0,\n                                    \"ty\": \"sh\",\n                                    \"ix\": 1,\n                                    \"ks\": {\n                                        \"a\": 0,\n                                        \"k\": {\n                                            \"i\": [\n                                                [0, -3.567],\n                                                [0, 3.569]\n                                            ],\n                                            \"o\": [\n                                                [0, 3.569],\n                                                [0, -3.567]\n                                            ],\n                                            \"v\": [\n                                                [-267.399, 219.876],\n                                                [-272.751, 219.876]\n                                            ],\n                                            \"c\": true\n                                        },\n                                        \"ix\": 2\n                                    },\n                                    \"nm\": \"Path 1\",\n                                    \"mn\": \"ADBE Vector Shape - Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"fl\",\n                                    \"c\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            0.058823529631, 0.705882370472,\n                                            0.831372559071, 1\n                                        ],\n                                        \"ix\": 4\n                                    },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 5 },\n                                    \"r\": 1,\n                                    \"bm\": 0,\n                                    \"nm\": \"Fill 1\",\n                                    \"mn\": \"ADBE Vector Graphic - Fill\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": { \"a\": 0, \"k\": [0, 0], \"ix\": 2 },\n                                    \"a\": { \"a\": 0, \"k\": [0, 0], \"ix\": 1 },\n                                    \"s\": { \"a\": 0, \"k\": [100, 100], \"ix\": 3 },\n                                    \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                    \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                    \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"Group 1\",\n                            \"np\": 2,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 1,\n                    \"op\": 20,\n                    \"st\": 0,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 10,\n                    \"ty\": 4,\n                    \"nm\": \"Layer 9\",\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 21,\n                                    \"s\": [4]\n                                },\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 23,\n                                    \"s\": [100]\n                                },\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 38,\n                                    \"s\": [100]\n                                },\n                                { \"t\": 40, \"s\": [0] }\n                            ],\n                            \"ix\": 11\n                        },\n                        \"r\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 21,\n                                    \"s\": [0]\n                                },\n                                { \"t\": 39, \"s\": [-238] }\n                            ],\n                            \"ix\": 10\n                        },\n                        \"p\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": 0.833, \"y\": 0.833 },\n                                    \"o\": { \"x\": 0.167, \"y\": 0.167 },\n                                    \"t\": 21,\n                                    \"s\": [870.597, 174.763, 0],\n                                    \"to\": [0, 46.667, 0],\n                                    \"ti\": [0, -46.667, 0]\n                                },\n                                { \"t\": 40, \"s\": [870.597, 454.763, 0] }\n                            ],\n                            \"ix\": 2\n                        },\n                        \"a\": { \"a\": 0, \"k\": [-216.535, 204.574, 0], \"ix\": 1 },\n                        \"s\": { \"a\": 0, \"k\": [1262, 1262, 100], \"ix\": 6 }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ind\": 0,\n                                    \"ty\": \"sh\",\n                                    \"ix\": 1,\n                                    \"ks\": {\n                                        \"a\": 0,\n                                        \"k\": {\n                                            \"i\": [\n                                                [0, -3.568],\n                                                [0, 3.569]\n                                            ],\n                                            \"o\": [\n                                                [0, 3.569],\n                                                [0, -3.568]\n                                            ],\n                                            \"v\": [\n                                                [-213.859, 204.573],\n                                                [-219.211, 204.573]\n                                            ],\n                                            \"c\": true\n                                        },\n                                        \"ix\": 2\n                                    },\n                                    \"nm\": \"Path 1\",\n                                    \"mn\": \"ADBE Vector Shape - Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"fl\",\n                                    \"c\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            0.65098041296, 0.901960790157,\n                                            0.223529413342, 1\n                                        ],\n                                        \"ix\": 4\n                                    },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 5 },\n                                    \"r\": 1,\n                                    \"bm\": 0,\n                                    \"nm\": \"Fill 1\",\n                                    \"mn\": \"ADBE Vector Graphic - Fill\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": { \"a\": 0, \"k\": [0, 0], \"ix\": 2 },\n                                    \"a\": { \"a\": 0, \"k\": [0, 0], \"ix\": 1 },\n                                    \"s\": { \"a\": 0, \"k\": [100, 100], \"ix\": 3 },\n                                    \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                    \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                    \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"Group 1\",\n                            \"np\": 2,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 21,\n                    \"op\": 40,\n                    \"st\": 20,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 11,\n                    \"ty\": 4,\n                    \"nm\": \"Layer 8\",\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 10,\n                                    \"s\": [4]\n                                },\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 12,\n                                    \"s\": [100]\n                                },\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 27,\n                                    \"s\": [100]\n                                },\n                                { \"t\": 29, \"s\": [0] }\n                            ],\n                            \"ix\": 11\n                        },\n                        \"r\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 10,\n                                    \"s\": [0]\n                                },\n                                { \"t\": 28, \"s\": [-49] }\n                            ],\n                            \"ix\": 10\n                        },\n                        \"p\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": 0.833, \"y\": 0.833 },\n                                    \"o\": { \"x\": 0.167, \"y\": 0.167 },\n                                    \"t\": 10,\n                                    \"s\": [790.435, 694.021, 0],\n                                    \"to\": [0, 46.667, 0],\n                                    \"ti\": [0, -46.667, 0]\n                                },\n                                { \"t\": 29, \"s\": [790.435, 974.021, 0] }\n                            ],\n                            \"ix\": 2\n                        },\n                        \"a\": { \"a\": 0, \"k\": [-222.887, 245.719, 0], \"ix\": 1 },\n                        \"s\": { \"a\": 0, \"k\": [1262, 1262, 100], \"ix\": 6 }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ind\": 0,\n                                    \"ty\": \"sh\",\n                                    \"ix\": 1,\n                                    \"ks\": {\n                                        \"a\": 0,\n                                        \"k\": {\n                                            \"i\": [\n                                                [0, 0],\n                                                [0, 0],\n                                                [0, 0],\n                                                [0, 0]\n                                            ],\n                                            \"o\": [\n                                                [0, 0],\n                                                [0, 0],\n                                                [0, 0],\n                                                [0, 0]\n                                            ],\n                                            \"v\": [\n                                                [-219.674, 244.714],\n                                                [-221.718, 249.449],\n                                                [-226.101, 246.73],\n                                                [-224.056, 241.989]\n                                            ],\n                                            \"c\": true\n                                        },\n                                        \"ix\": 2\n                                    },\n                                    \"nm\": \"Path 1\",\n                                    \"mn\": \"ADBE Vector Shape - Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"fl\",\n                                    \"c\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            0.901960790157, 0.207843139768,\n                                            0.870588243008, 1\n                                        ],\n                                        \"ix\": 4\n                                    },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 5 },\n                                    \"r\": 1,\n                                    \"bm\": 0,\n                                    \"nm\": \"Fill 1\",\n                                    \"mn\": \"ADBE Vector Graphic - Fill\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": { \"a\": 0, \"k\": [0, 0], \"ix\": 2 },\n                                    \"a\": { \"a\": 0, \"k\": [0, 0], \"ix\": 1 },\n                                    \"s\": { \"a\": 0, \"k\": [100, 100], \"ix\": 3 },\n                                    \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                    \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                    \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"Group 1\",\n                            \"np\": 2,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 10,\n                    \"op\": 29,\n                    \"st\": 9,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 12,\n                    \"ty\": 4,\n                    \"nm\": \"Layer 7\",\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 0,\n                                    \"s\": [4]\n                                },\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 2,\n                                    \"s\": [100]\n                                },\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 17,\n                                    \"s\": [100]\n                                },\n                                { \"t\": 19, \"s\": [0] }\n                            ],\n                            \"ix\": 11\n                        },\n                        \"r\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 0,\n                                    \"s\": [0]\n                                },\n                                { \"t\": 18, \"s\": [35] }\n                            ],\n                            \"ix\": 10\n                        },\n                        \"p\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": 0.833, \"y\": 0.833 },\n                                    \"o\": { \"x\": 0.167, \"y\": 0.167 },\n                                    \"t\": 0,\n                                    \"s\": [423.853, 174.764, 0],\n                                    \"to\": [0, 46.667, 0],\n                                    \"ti\": [0, -46.667, 0]\n                                },\n                                { \"t\": 19, \"s\": [423.853, 454.764, 0] }\n                            ],\n                            \"ix\": 2\n                        },\n                        \"a\": { \"a\": 0, \"k\": [-251.935, 204.574, 0], \"ix\": 1 },\n                        \"s\": { \"a\": 0, \"k\": [1262, 1262, 100], \"ix\": 6 }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ind\": 0,\n                                    \"ty\": \"sh\",\n                                    \"ix\": 1,\n                                    \"ks\": {\n                                        \"a\": 0,\n                                        \"k\": {\n                                            \"i\": [\n                                                [0, 0],\n                                                [0, 0],\n                                                [0, 0],\n                                                [0, 0]\n                                            ],\n                                            \"o\": [\n                                                [0, 0],\n                                                [0, 0],\n                                                [0, 0],\n                                                [0, 0]\n                                            ],\n                                            \"v\": [\n                                                [-249.335, 205.209],\n                                                [-252.875, 208.444],\n                                                [-254.535, 203.943],\n                                                [-250.991, 200.703]\n                                            ],\n                                            \"c\": true\n                                        },\n                                        \"ix\": 2\n                                    },\n                                    \"nm\": \"Path 1\",\n                                    \"mn\": \"ADBE Vector Shape - Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"fl\",\n                                    \"c\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            0.058823529631, 0.705882370472,\n                                            0.831372559071, 1\n                                        ],\n                                        \"ix\": 4\n                                    },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 5 },\n                                    \"r\": 1,\n                                    \"bm\": 0,\n                                    \"nm\": \"Fill 1\",\n                                    \"mn\": \"ADBE Vector Graphic - Fill\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": { \"a\": 0, \"k\": [0, 0], \"ix\": 2 },\n                                    \"a\": { \"a\": 0, \"k\": [0, 0], \"ix\": 1 },\n                                    \"s\": { \"a\": 0, \"k\": [100, 100], \"ix\": 3 },\n                                    \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                    \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                    \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"Group 1\",\n                            \"np\": 2,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 0,\n                    \"op\": 19,\n                    \"st\": -1,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 13,\n                    \"ty\": 4,\n                    \"nm\": \"Layer 6\",\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 29,\n                                    \"s\": [4]\n                                },\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 31,\n                                    \"s\": [100]\n                                },\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 46,\n                                    \"s\": [100]\n                                },\n                                { \"t\": 48, \"s\": [0] }\n                            ],\n                            \"ix\": 11\n                        },\n                        \"r\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 29,\n                                    \"s\": [0]\n                                },\n                                { \"t\": 47, \"s\": [-115] }\n                            ],\n                            \"ix\": 10\n                        },\n                        \"p\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": 0.833, \"y\": 0.833 },\n                                    \"o\": { \"x\": 0.167, \"y\": 0.167 },\n                                    \"t\": 29,\n                                    \"s\": [194.479, 190.293, 0],\n                                    \"to\": [0, 46.667, 0],\n                                    \"ti\": [0, -46.667, 0]\n                                },\n                                { \"t\": 48, \"s\": [194.479, 470.293, 0] }\n                            ],\n                            \"ix\": 2\n                        },\n                        \"a\": { \"a\": 0, \"k\": [-270.111, 205.804, 0], \"ix\": 1 },\n                        \"s\": { \"a\": 0, \"k\": [1262, 1262, 100], \"ix\": 6 }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ind\": 0,\n                                    \"ty\": \"sh\",\n                                    \"ix\": 1,\n                                    \"ks\": {\n                                        \"a\": 0,\n                                        \"k\": {\n                                            \"i\": [\n                                                [0, 0],\n                                                [0, 0],\n                                                [0, 0],\n                                                [0, 0]\n                                            ],\n                                            \"o\": [\n                                                [0, 0],\n                                                [0, 0],\n                                                [0, 0],\n                                                [0, 0]\n                                            ],\n                                            \"v\": [\n                                                [-266.857, 204.993],\n                                                [-269.272, 209.164],\n                                                [-273.364, 206.613],\n                                                [-270.943, 202.444]\n                                            ],\n                                            \"c\": true\n                                        },\n                                        \"ix\": 2\n                                    },\n                                    \"nm\": \"Path 1\",\n                                    \"mn\": \"ADBE Vector Shape - Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"fl\",\n                                    \"c\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            0.909803926945, 0.109803922474,\n                                            0.152941182256, 1\n                                        ],\n                                        \"ix\": 4\n                                    },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 5 },\n                                    \"r\": 1,\n                                    \"bm\": 0,\n                                    \"nm\": \"Fill 1\",\n                                    \"mn\": \"ADBE Vector Graphic - Fill\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": { \"a\": 0, \"k\": [0, 0], \"ix\": 2 },\n                                    \"a\": { \"a\": 0, \"k\": [0, 0], \"ix\": 1 },\n                                    \"s\": { \"a\": 0, \"k\": [100, 100], \"ix\": 3 },\n                                    \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                    \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                    \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"Group 1\",\n                            \"np\": 2,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 29,\n                    \"op\": 48,\n                    \"st\": 28,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 14,\n                    \"ty\": 4,\n                    \"nm\": \"Layer 5\",\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 16,\n                                    \"s\": [4]\n                                },\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 18,\n                                    \"s\": [100]\n                                },\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 33,\n                                    \"s\": [100]\n                                },\n                                { \"t\": 35, \"s\": [0] }\n                            ],\n                            \"ix\": 11\n                        },\n                        \"r\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 16,\n                                    \"s\": [0]\n                                },\n                                { \"t\": 34, \"s\": [29] }\n                            ],\n                            \"ix\": 10\n                        },\n                        \"p\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": 0.833, \"y\": 0.833 },\n                                    \"o\": { \"x\": 0.167, \"y\": 0.167 },\n                                    \"t\": 16,\n                                    \"s\": [781.475, 542.889, 0],\n                                    \"to\": [0, 46.667, 0],\n                                    \"ti\": [0, -46.667, 0]\n                                },\n                                { \"t\": 35, \"s\": [781.475, 822.889, 0] }\n                            ],\n                            \"ix\": 2\n                        },\n                        \"a\": { \"a\": 0, \"k\": [-223.597, 233.744, 0], \"ix\": 1 },\n                        \"s\": { \"a\": 0, \"k\": [1262, 1262, 100], \"ix\": 6 }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ind\": 0,\n                                    \"ty\": \"sh\",\n                                    \"ix\": 1,\n                                    \"ks\": {\n                                        \"a\": 0,\n                                        \"k\": {\n                                            \"i\": [\n                                                [0, 0],\n                                                [0, 0],\n                                                [0, 0]\n                                            ],\n                                            \"o\": [\n                                                [0, 0],\n                                                [0, 0],\n                                                [0, 0]\n                                            ],\n                                            \"v\": [\n                                                [-221.09, 235.787],\n                                                [-226.105, 236.067],\n                                                [-223.558, 231.42]\n                                            ],\n                                            \"c\": true\n                                        },\n                                        \"ix\": 2\n                                    },\n                                    \"nm\": \"Path 1\",\n                                    \"mn\": \"ADBE Vector Shape - Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"fl\",\n                                    \"c\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            0.65098041296, 0.901960790157,\n                                            0.223529413342, 1\n                                        ],\n                                        \"ix\": 4\n                                    },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 5 },\n                                    \"r\": 1,\n                                    \"bm\": 0,\n                                    \"nm\": \"Fill 1\",\n                                    \"mn\": \"ADBE Vector Graphic - Fill\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": { \"a\": 0, \"k\": [0, 0], \"ix\": 2 },\n                                    \"a\": { \"a\": 0, \"k\": [0, 0], \"ix\": 1 },\n                                    \"s\": { \"a\": 0, \"k\": [100, 100], \"ix\": 3 },\n                                    \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                    \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                    \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"Group 1\",\n                            \"np\": 2,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 16,\n                    \"op\": 35,\n                    \"st\": 15,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 15,\n                    \"ty\": 4,\n                    \"nm\": \"Layer 4\",\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 5,\n                                    \"s\": [4]\n                                },\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 7,\n                                    \"s\": [100]\n                                },\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 22,\n                                    \"s\": [100]\n                                },\n                                { \"t\": 24, \"s\": [0] }\n                            ],\n                            \"ix\": 11\n                        },\n                        \"r\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 5,\n                                    \"s\": [0]\n                                },\n                                { \"t\": 23, \"s\": [-78] }\n                            ],\n                            \"ix\": 10\n                        },\n                        \"p\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": 0.833, \"y\": 0.833 },\n                                    \"o\": { \"x\": 0.167, \"y\": 0.167 },\n                                    \"t\": 5,\n                                    \"s\": [289.011, 51.812, 0],\n                                    \"to\": [0, 46.667, 0],\n                                    \"ti\": [0, -46.667, 0]\n                                },\n                                { \"t\": 24, \"s\": [289.011, 331.812, 0] }\n                            ],\n                            \"ix\": 2\n                        },\n                        \"a\": { \"a\": 0, \"k\": [-262.62, 194.831, 0], \"ix\": 1 },\n                        \"s\": { \"a\": 0, \"k\": [1262, 1262, 100], \"ix\": 6 }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ind\": 0,\n                                    \"ty\": \"sh\",\n                                    \"ix\": 1,\n                                    \"ks\": {\n                                        \"a\": 0,\n                                        \"k\": {\n                                            \"i\": [\n                                                [0, 0],\n                                                [0, 0],\n                                                [0, 0]\n                                            ],\n                                            \"o\": [\n                                                [0, 0],\n                                                [0, 0],\n                                                [0, 0]\n                                            ],\n                                            \"v\": [\n                                                [-259.364, 196.93],\n                                                [-265.876, 198.066],\n                                                [-263.263, 191.596]\n                                            ],\n                                            \"c\": true\n                                        },\n                                        \"ix\": 2\n                                    },\n                                    \"nm\": \"Path 1\",\n                                    \"mn\": \"ADBE Vector Shape - Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"fl\",\n                                    \"c\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            0.901960790157, 0.207843139768,\n                                            0.870588243008, 1\n                                        ],\n                                        \"ix\": 4\n                                    },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 5 },\n                                    \"r\": 1,\n                                    \"bm\": 0,\n                                    \"nm\": \"Fill 1\",\n                                    \"mn\": \"ADBE Vector Graphic - Fill\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": { \"a\": 0, \"k\": [0, 0], \"ix\": 2 },\n                                    \"a\": { \"a\": 0, \"k\": [0, 0], \"ix\": 1 },\n                                    \"s\": { \"a\": 0, \"k\": [100, 100], \"ix\": 3 },\n                                    \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                    \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                    \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"Group 1\",\n                            \"np\": 2,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 5,\n                    \"op\": 24,\n                    \"st\": 4,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 16,\n                    \"ty\": 4,\n                    \"nm\": \"Mouth\",\n                    \"parent\": 1,\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": { \"a\": 0, \"k\": 100, \"ix\": 11 },\n                        \"r\": { \"a\": 0, \"k\": 0, \"ix\": 10 },\n                        \"p\": { \"a\": 0, \"k\": [1.1, 101.975, 0], \"ix\": 2 },\n                        \"a\": { \"a\": 0, \"k\": [-244.448, 237.823, 0], \"ix\": 1 },\n                        \"s\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": {\n                                        \"x\": [0.667, 0.667, 0.667],\n                                        \"y\": [1, 1, 1]\n                                    },\n                                    \"o\": {\n                                        \"x\": [0.333, 0.333, 0.333],\n                                        \"y\": [0, 0, 0]\n                                    },\n                                    \"t\": 0,\n                                    \"s\": [1262, 1262, 100]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": [0, 0.667, 0.667],\n                                        \"y\": [1, 1, 1]\n                                    },\n                                    \"o\": {\n                                        \"x\": [0.333, 0.333, 0.333],\n                                        \"y\": [0, 0, 0]\n                                    },\n                                    \"t\": 4,\n                                    \"s\": [1299.86, 1262, 100]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": [0, 0.667, 0.667],\n                                        \"y\": [1, 1, 1]\n                                    },\n                                    \"o\": {\n                                        \"x\": [0.333, 0.333, 0.333],\n                                        \"y\": [0, 0, 0]\n                                    },\n                                    \"t\": 18,\n                                    \"s\": [1173.66, 1262, 100]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": [0, 0.667, 0.667],\n                                        \"y\": [1, 1, 1]\n                                    },\n                                    \"o\": {\n                                        \"x\": [0.333, 0.333, 0.333],\n                                        \"y\": [0, 0, 0]\n                                    },\n                                    \"t\": 30,\n                                    \"s\": [1375.58, 1262, 100]\n                                },\n                                { \"t\": 41, \"s\": [1262, 1262, 100] }\n                            ],\n                            \"ix\": 6\n                        }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ind\": 0,\n                                    \"ty\": \"sh\",\n                                    \"ix\": 1,\n                                    \"ks\": {\n                                        \"a\": 0,\n                                        \"k\": {\n                                            \"i\": [\n                                                [-0.296, 0.419],\n                                                [1.111, 0.249],\n                                                [-1.006, 1.535],\n                                                [-1.835, 3.294],\n                                                [0.211, -1.095],\n                                                [-0.41, -1.177],\n                                                [-1.08, -0.51],\n                                                [-1.838, -3.404],\n                                                [1.972, 0.537]\n                                            ],\n                                            \"o\": [\n                                                [0.925, -1.314],\n                                                [-0.841, -0.189],\n                                                [1.132, -1.727],\n                                                [0.507, 3.837],\n                                                [-0.222, 1.148],\n                                                [0.296, 0.85],\n                                                [1.012, 0.479],\n                                                [-3.419, -1.598],\n                                                [-2.499, -0.679]\n                                            ],\n                                            \"v\": [\n                                                [-250.347, 241.811],\n                                                [-251.329, 238.417],\n                                                [-251.856, 235.16],\n                                                [-245.719, 230.892],\n                                                [-249.789, 236.446],\n                                                [-248.06, 239.115],\n                                                [-247.821, 242.498],\n                                                [-241.295, 244.546],\n                                                [-248.775, 244.67]\n                                            ],\n                                            \"c\": true\n                                        },\n                                        \"ix\": 2\n                                    },\n                                    \"nm\": \"Path 1\",\n                                    \"mn\": \"ADBE Vector Shape - Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"fl\",\n                                    \"c\": {\n                                        \"a\": 0,\n                                        \"k\": [\n                                            0.101960785687, 0.086274512112,\n                                            0.149019613862, 1\n                                        ],\n                                        \"ix\": 4\n                                    },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 5 },\n                                    \"r\": 1,\n                                    \"bm\": 0,\n                                    \"nm\": \"Fill 1\",\n                                    \"mn\": \"ADBE Vector Graphic - Fill\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": { \"a\": 0, \"k\": [0, 0], \"ix\": 2 },\n                                    \"a\": { \"a\": 0, \"k\": [0, 0], \"ix\": 1 },\n                                    \"s\": { \"a\": 0, \"k\": [100, 100], \"ix\": 3 },\n                                    \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                    \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                    \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"Group 1\",\n                            \"np\": 2,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 0,\n                    \"op\": 49,\n                    \"st\": 0,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 17,\n                    \"ty\": 4,\n                    \"nm\": \"Wistle 2\",\n                    \"parent\": 18,\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": { \"a\": 0, \"k\": 100, \"ix\": 11 },\n                        \"r\": { \"a\": 0, \"k\": 0, \"ix\": 10 },\n                        \"p\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": 0, \"y\": 0.97 },\n                                    \"o\": { \"x\": 0.167, \"y\": 0.167 },\n                                    \"t\": 19,\n                                    \"s\": [-269.13, 249.354, 0],\n                                    \"to\": [-2.391, 0.777, 0],\n                                    \"ti\": [0, 0, 0]\n                                },\n                                {\n                                    \"i\": { \"x\": 0, \"y\": 0.97 },\n                                    \"o\": { \"x\": 0.333, \"y\": 0 },\n                                    \"t\": 30,\n                                    \"s\": [-283.475, 254.013, 0],\n                                    \"to\": [0, 0, 0],\n                                    \"ti\": [-2.391, 0.777, 0]\n                                },\n                                { \"t\": 41, \"s\": [-269.13, 249.354, 0] }\n                            ],\n                            \"ix\": 2\n                        },\n                        \"a\": { \"a\": 0, \"k\": [-269.13, 249.354, 0], \"ix\": 1 },\n                        \"s\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": {\n                                        \"x\": [0.085, 0.085, 0.582],\n                                        \"y\": [0.783, 0.783, 0.263]\n                                    },\n                                    \"o\": {\n                                        \"x\": [0.24, 0.24, 0.18],\n                                        \"y\": [0.147, 0.147, 0.294]\n                                    },\n                                    \"t\": 19,\n                                    \"s\": [100, 100, 100]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": [0.727, 0.727, 0.667],\n                                        \"y\": [1.024, 1.024, 1.031]\n                                    },\n                                    \"o\": {\n                                        \"x\": [0.261, 0.261, 0.347],\n                                        \"y\": [0.023, 0.023, 0.153]\n                                    },\n                                    \"t\": 23,\n                                    \"s\": [40.348, 40.348, 100]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": [0.727, 0.727, 0.667],\n                                        \"y\": [1, 1, 1]\n                                    },\n                                    \"o\": {\n                                        \"x\": [0.223, 0.223, 0.333],\n                                        \"y\": [5.639, 5.639, -0.218]\n                                    },\n                                    \"t\": 24,\n                                    \"s\": [0, 0, 100]\n                                },\n                                {\n                                    \"i\": { \"x\": [0, 0, 0.667], \"y\": [1, 1, 1] },\n                                    \"o\": {\n                                        \"x\": [0.223, 0.223, 0.333],\n                                        \"y\": [0, 0, 0]\n                                    },\n                                    \"t\": 31,\n                                    \"s\": [0, 0, 100]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": [0.017, 0.017, 0.667],\n                                        \"y\": [0.994, 0.994, 1]\n                                    },\n                                    \"o\": {\n                                        \"x\": [0.401, 0.401, 0.333],\n                                        \"y\": [0, 0, 0]\n                                    },\n                                    \"t\": 32,\n                                    \"s\": [36, 36, 100]\n                                },\n                                { \"t\": 41, \"s\": [100, 100, 100] }\n                            ],\n                            \"ix\": 6\n                        }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ty\": \"gr\",\n                                    \"it\": [\n                                        {\n                                            \"ind\": 0,\n                                            \"ty\": \"sh\",\n                                            \"ix\": 1,\n                                            \"ks\": {\n                                                \"a\": 0,\n                                                \"k\": {\n                                                    \"i\": [\n                                                        [1.349, 0.972],\n                                                        [-1.201, -1.202]\n                                                    ],\n                                                    \"o\": [\n                                                        [-1.227, -0.883],\n                                                        [0.93, 0.929]\n                                                    ],\n                                                    \"v\": [\n                                                        [-270.784, 247.568],\n                                                        [-268.41, 245.193]\n                                                    ],\n                                                    \"c\": true\n                                                },\n                                                \"ix\": 2\n                                            },\n                                            \"nm\": \"Path 1\",\n                                            \"mn\": \"ADBE Vector Shape - Group\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"fl\",\n                                            \"c\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0.160784319043,\n                                                    0.443137258291,\n                                                    0.141176477075, 1\n                                                ],\n                                                \"ix\": 4\n                                            },\n                                            \"o\": { \"a\": 0, \"k\": 100, \"ix\": 5 },\n                                            \"r\": 1,\n                                            \"bm\": 0,\n                                            \"nm\": \"Fill 1\",\n                                            \"mn\": \"ADBE Vector Graphic - Fill\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"tr\",\n                                            \"p\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 2\n                                            },\n                                            \"a\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 1\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [100, 100],\n                                                \"ix\": 3\n                                            },\n                                            \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                            \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                            \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                            \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                            \"nm\": \"Transform\"\n                                        }\n                                    ],\n                                    \"nm\": \"Group 1\",\n                                    \"np\": 2,\n                                    \"cix\": 2,\n                                    \"bm\": 0,\n                                    \"ix\": 1,\n                                    \"mn\": \"ADBE Vector Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"gr\",\n                                    \"it\": [\n                                        {\n                                            \"ind\": 0,\n                                            \"ty\": \"sh\",\n                                            \"ix\": 1,\n                                            \"ks\": {\n                                                \"a\": 0,\n                                                \"k\": {\n                                                    \"i\": [\n                                                        [2.157, 1.555],\n                                                        [-1.921, -1.922]\n                                                    ],\n                                                    \"o\": [\n                                                        [-1.961, -1.409],\n                                                        [1.489, 1.489]\n                                                    ],\n                                                    \"v\": [\n                                                        [-271.896, 248.061],\n                                                        [-268.099, 244.26]\n                                                    ],\n                                                    \"c\": true\n                                                },\n                                                \"ix\": 2\n                                            },\n                                            \"nm\": \"Path 1\",\n                                            \"mn\": \"ADBE Vector Shape - Group\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"fl\",\n                                            \"c\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0.321568638086,\n                                                    0.57647061348, 0.1254902035,\n                                                    1\n                                                ],\n                                                \"ix\": 4\n                                            },\n                                            \"o\": { \"a\": 0, \"k\": 100, \"ix\": 5 },\n                                            \"r\": 1,\n                                            \"bm\": 0,\n                                            \"nm\": \"Fill 1\",\n                                            \"mn\": \"ADBE Vector Graphic - Fill\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"tr\",\n                                            \"p\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 2\n                                            },\n                                            \"a\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 1\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [100, 100],\n                                                \"ix\": 3\n                                            },\n                                            \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                            \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                            \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                            \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                            \"nm\": \"Transform\"\n                                        }\n                                    ],\n                                    \"nm\": \"Group 2\",\n                                    \"np\": 2,\n                                    \"cix\": 2,\n                                    \"bm\": 0,\n                                    \"ix\": 2,\n                                    \"mn\": \"ADBE Vector Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"gr\",\n                                    \"it\": [\n                                        {\n                                            \"ind\": 0,\n                                            \"ty\": \"sh\",\n                                            \"ix\": 1,\n                                            \"ks\": {\n                                                \"a\": 0,\n                                                \"k\": {\n                                                    \"i\": [\n                                                        [2.901, 2.09],\n                                                        [-2.585, -2.583]\n                                                    ],\n                                                    \"o\": [\n                                                        [-2.641, -1.899],\n                                                        [2.003, 2.003]\n                                                    ],\n                                                    \"v\": [\n                                                        [-273.022, 248.652],\n                                                        [-267.914, 243.537]\n                                                    ],\n                                                    \"c\": true\n                                                },\n                                                \"ix\": 2\n                                            },\n                                            \"nm\": \"Path 1\",\n                                            \"mn\": \"ADBE Vector Shape - Group\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"fl\",\n                                            \"c\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0.478431373835,\n                                                    0.709803938866,\n                                                    0.113725490868, 1\n                                                ],\n                                                \"ix\": 4\n                                            },\n                                            \"o\": { \"a\": 0, \"k\": 100, \"ix\": 5 },\n                                            \"r\": 1,\n                                            \"bm\": 0,\n                                            \"nm\": \"Fill 1\",\n                                            \"mn\": \"ADBE Vector Graphic - Fill\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"tr\",\n                                            \"p\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 2\n                                            },\n                                            \"a\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 1\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [100, 100],\n                                                \"ix\": 3\n                                            },\n                                            \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                            \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                            \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                            \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                            \"nm\": \"Transform\"\n                                        }\n                                    ],\n                                    \"nm\": \"Group 3\",\n                                    \"np\": 2,\n                                    \"cix\": 2,\n                                    \"bm\": 0,\n                                    \"ix\": 3,\n                                    \"mn\": \"ADBE Vector Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"gr\",\n                                    \"it\": [\n                                        {\n                                            \"ind\": 0,\n                                            \"ty\": \"sh\",\n                                            \"ix\": 1,\n                                            \"ks\": {\n                                                \"a\": 0,\n                                                \"k\": {\n                                                    \"i\": [\n                                                        [-1.166, 2.21],\n                                                        [2.033, 2.806],\n                                                        [-1.296, -3.921],\n                                                        [-4.548, 2.075],\n                                                        [-0.061, 0.344]\n                                                    ],\n                                                    \"o\": [\n                                                        [0, 0],\n                                                        [-1.537, -2.119],\n                                                        [0.744, 2.244],\n                                                        [-0.055, -0.962],\n                                                        [0.194, -1.095]\n                                                    ],\n                                                    \"v\": [\n                                                        [-267.526, 244.127],\n                                                        [-271.283, 238.679],\n                                                        [-276.315, 243.625],\n                                                        [-268.976, 249.505],\n                                                        [-269.135, 245.865]\n                                                    ],\n                                                    \"c\": true\n                                                },\n                                                \"ix\": 2\n                                            },\n                                            \"nm\": \"Path 1\",\n                                            \"mn\": \"ADBE Vector Shape - Group\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"fl\",\n                                            \"c\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0.65098041296,\n                                                    0.901960790157,\n                                                    0.223529413342, 1\n                                                ],\n                                                \"ix\": 4\n                                            },\n                                            \"o\": { \"a\": 0, \"k\": 100, \"ix\": 5 },\n                                            \"r\": 1,\n                                            \"bm\": 0,\n                                            \"nm\": \"Fill 1\",\n                                            \"mn\": \"ADBE Vector Graphic - Fill\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"tr\",\n                                            \"p\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 2\n                                            },\n                                            \"a\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 1\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [100, 100],\n                                                \"ix\": 3\n                                            },\n                                            \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                            \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                            \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                            \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                            \"nm\": \"Transform\"\n                                        }\n                                    ],\n                                    \"nm\": \"Group 9\",\n                                    \"np\": 2,\n                                    \"cix\": 2,\n                                    \"bm\": 0,\n                                    \"ix\": 4,\n                                    \"mn\": \"ADBE Vector Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": { \"a\": 0, \"k\": [0, 0], \"ix\": 2 },\n                                    \"a\": { \"a\": 0, \"k\": [0, 0], \"ix\": 1 },\n                                    \"s\": { \"a\": 0, \"k\": [100, 100], \"ix\": 3 },\n                                    \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                    \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                    \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"Group 2\",\n                            \"np\": 4,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 0,\n                    \"op\": 49,\n                    \"st\": 0,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 18,\n                    \"ty\": 4,\n                    \"nm\": \"Wistle\",\n                    \"parent\": 16,\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": { \"a\": 0, \"k\": 100, \"ix\": 11 },\n                        \"r\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": [0.667], \"y\": [1] },\n                                    \"o\": { \"x\": [0.333], \"y\": [0] },\n                                    \"t\": 0,\n                                    \"s\": [0]\n                                },\n                                {\n                                    \"i\": { \"x\": [0], \"y\": [1] },\n                                    \"o\": { \"x\": [0.333], \"y\": [0] },\n                                    \"t\": 5,\n                                    \"s\": [2]\n                                },\n                                {\n                                    \"i\": { \"x\": [0], \"y\": [1] },\n                                    \"o\": { \"x\": [0.333], \"y\": [0] },\n                                    \"t\": 18,\n                                    \"s\": [4]\n                                },\n                                {\n                                    \"i\": { \"x\": [0.667], \"y\": [1] },\n                                    \"o\": { \"x\": [0.333], \"y\": [0] },\n                                    \"t\": 30,\n                                    \"s\": [-16]\n                                },\n                                { \"t\": 41, \"s\": [0] }\n                            ],\n                            \"ix\": 10\n                        },\n                        \"p\": { \"a\": 0, \"k\": [-249.704, 239.133, 0], \"ix\": 2 },\n                        \"a\": { \"a\": 0, \"k\": [-249.704, 239.133, 0], \"ix\": 1 },\n                        \"s\": { \"a\": 0, \"k\": [100, 100, 100], \"ix\": 6 }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ty\": \"gr\",\n                                    \"it\": [\n                                        {\n                                            \"ind\": 0,\n                                            \"ty\": \"sh\",\n                                            \"ix\": 1,\n                                            \"ks\": {\n                                                \"a\": 1,\n                                                \"k\": [\n                                                    {\n                                                        \"i\": { \"x\": 0, \"y\": 1 },\n                                                        \"o\": {\n                                                            \"x\": 0.167,\n                                                            \"y\": 0.167\n                                                        },\n                                                        \"t\": 19,\n                                                        \"s\": [\n                                                            {\n                                                                \"i\": [\n                                                                    [\n                                                                        -0.27,\n                                                                        0.114\n                                                                    ],\n                                                                    [\n                                                                        0.522,\n                                                                        -0.162\n                                                                    ],\n                                                                    [0, 0],\n                                                                    [0, 0]\n                                                                ],\n                                                                \"o\": [\n                                                                    [\n                                                                        0.486,\n                                                                        -0.201\n                                                                    ],\n                                                                    [\n                                                                        -0.349,\n                                                                        0.109\n                                                                    ],\n                                                                    [0, 0],\n                                                                    [\n                                                                        -0.001,\n                                                                        0.002\n                                                                    ]\n                                                                ],\n                                                                \"v\": [\n                                                                    [\n                                                                        -265.416,\n                                                                        247.908\n                                                                    ],\n                                                                    [\n                                                                        -266.411,\n                                                                        243.219\n                                                                    ],\n                                                                    [\n                                                                        -269.252,\n                                                                        244.125\n                                                                    ],\n                                                                    [\n                                                                        -269.065,\n                                                                        249.449\n                                                                    ]\n                                                                ],\n                                                                \"c\": true\n                                                            }\n                                                        ]\n                                                    },\n                                                    {\n                                                        \"i\": { \"x\": 0, \"y\": 1 },\n                                                        \"o\": {\n                                                            \"x\": 0.333,\n                                                            \"y\": 0\n                                                        },\n                                                        \"t\": 30,\n                                                        \"s\": [\n                                                            {\n                                                                \"i\": [\n                                                                    [\n                                                                        -0.27,\n                                                                        0.114\n                                                                    ],\n                                                                    [\n                                                                        0.522,\n                                                                        -0.162\n                                                                    ],\n                                                                    [0, 0],\n                                                                    [0, 0]\n                                                                ],\n                                                                \"o\": [\n                                                                    [\n                                                                        0.486,\n                                                                        -0.201\n                                                                    ],\n                                                                    [\n                                                                        -0.349,\n                                                                        0.109\n                                                                    ],\n                                                                    [0, 0],\n                                                                    [\n                                                                        -0.001,\n                                                                        0.002\n                                                                    ]\n                                                                ],\n                                                                \"v\": [\n                                                                    [\n                                                                        -265.416,\n                                                                        247.908\n                                                                    ],\n                                                                    [\n                                                                        -266.411,\n                                                                        243.219\n                                                                    ],\n                                                                    [\n                                                                        -284.873,\n                                                                        249.317\n                                                                    ],\n                                                                    [\n                                                                        -284.686,\n                                                                        254.641\n                                                                    ]\n                                                                ],\n                                                                \"c\": true\n                                                            }\n                                                        ]\n                                                    },\n                                                    {\n                                                        \"t\": 41,\n                                                        \"s\": [\n                                                            {\n                                                                \"i\": [\n                                                                    [\n                                                                        -0.27,\n                                                                        0.114\n                                                                    ],\n                                                                    [\n                                                                        0.522,\n                                                                        -0.162\n                                                                    ],\n                                                                    [0, 0],\n                                                                    [0, 0]\n                                                                ],\n                                                                \"o\": [\n                                                                    [\n                                                                        0.486,\n                                                                        -0.201\n                                                                    ],\n                                                                    [\n                                                                        -0.349,\n                                                                        0.109\n                                                                    ],\n                                                                    [0, 0],\n                                                                    [\n                                                                        -0.001,\n                                                                        0.002\n                                                                    ]\n                                                                ],\n                                                                \"v\": [\n                                                                    [\n                                                                        -265.416,\n                                                                        247.908\n                                                                    ],\n                                                                    [\n                                                                        -266.411,\n                                                                        243.219\n                                                                    ],\n                                                                    [\n                                                                        -269.252,\n                                                                        244.125\n                                                                    ],\n                                                                    [\n                                                                        -269.065,\n                                                                        249.449\n                                                                    ]\n                                                                ],\n                                                                \"c\": true\n                                                            }\n                                                        ]\n                                                    }\n                                                ],\n                                                \"ix\": 2\n                                            },\n                                            \"nm\": \"Path 1\",\n                                            \"mn\": \"ADBE Vector Shape - Group\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"fl\",\n                                            \"c\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0.478431373835,\n                                                    0.709803938866,\n                                                    0.113725490868, 1\n                                                ],\n                                                \"ix\": 4\n                                            },\n                                            \"o\": { \"a\": 0, \"k\": 100, \"ix\": 5 },\n                                            \"r\": 1,\n                                            \"bm\": 0,\n                                            \"nm\": \"Fill 1\",\n                                            \"mn\": \"ADBE Vector Graphic - Fill\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"tr\",\n                                            \"p\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 2\n                                            },\n                                            \"a\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 1\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [100, 100],\n                                                \"ix\": 3\n                                            },\n                                            \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                            \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                            \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                            \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                            \"nm\": \"Transform\"\n                                        }\n                                    ],\n                                    \"nm\": \"Group 4\",\n                                    \"np\": 2,\n                                    \"cix\": 2,\n                                    \"bm\": 0,\n                                    \"ix\": 1,\n                                    \"mn\": \"ADBE Vector Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"gr\",\n                                    \"it\": [\n                                        {\n                                            \"ind\": 0,\n                                            \"ty\": \"sh\",\n                                            \"ix\": 1,\n                                            \"ks\": {\n                                                \"a\": 0,\n                                                \"k\": {\n                                                    \"i\": [\n                                                        [0, 0],\n                                                        [-0.441, 0.168],\n                                                        [0, 0],\n                                                        [0.451, -0.16]\n                                                    ],\n                                                    \"o\": [\n                                                        [0.445, -0.171],\n                                                        [0, 0],\n                                                        [-0.462, 0.162],\n                                                        [0, 0]\n                                                    ],\n                                                    \"v\": [\n                                                        [-261.763, 246.347],\n                                                        [-259.498, 245.484],\n                                                        [-263.556, 242.416],\n                                                        [-265.742, 243.183]\n                                                    ],\n                                                    \"c\": true\n                                                },\n                                                \"ix\": 2\n                                            },\n                                            \"nm\": \"Path 1\",\n                                            \"mn\": \"ADBE Vector Shape - Group\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"fl\",\n                                            \"c\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0.058823529631,\n                                                    0.705882370472,\n                                                    0.831372559071, 1\n                                                ],\n                                                \"ix\": 4\n                                            },\n                                            \"o\": { \"a\": 0, \"k\": 100, \"ix\": 5 },\n                                            \"r\": 1,\n                                            \"bm\": 0,\n                                            \"nm\": \"Fill 1\",\n                                            \"mn\": \"ADBE Vector Graphic - Fill\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"tr\",\n                                            \"p\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 2\n                                            },\n                                            \"a\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 1\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [100, 100],\n                                                \"ix\": 3\n                                            },\n                                            \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                            \"o\": { \"a\": 0, \"k\": 50, \"ix\": 7 },\n                                            \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                            \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                            \"nm\": \"Transform\"\n                                        }\n                                    ],\n                                    \"nm\": \"Group 5\",\n                                    \"np\": 2,\n                                    \"cix\": 2,\n                                    \"bm\": 0,\n                                    \"ix\": 2,\n                                    \"mn\": \"ADBE Vector Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"gr\",\n                                    \"it\": [\n                                        {\n                                            \"ind\": 0,\n                                            \"ty\": \"sh\",\n                                            \"ix\": 1,\n                                            \"ks\": {\n                                                \"a\": 0,\n                                                \"k\": {\n                                                    \"i\": [\n                                                        [0, 0],\n                                                        [-0.717, 0.273],\n                                                        [0, 0],\n                                                        [0.794, -0.273]\n                                                    ],\n                                                    \"o\": [\n                                                        [0.799, -0.307],\n                                                        [0, 0],\n                                                        [-0.764, 0.265],\n                                                        [0, 0]\n                                                    ],\n                                                    \"v\": [\n                                                        [-256.817, 244.455],\n                                                        [-254.535, 243.584],\n                                                        [-258.435, 240.64],\n                                                        [-260.781, 241.459]\n                                                    ],\n                                                    \"c\": true\n                                                },\n                                                \"ix\": 2\n                                            },\n                                            \"nm\": \"Path 1\",\n                                            \"mn\": \"ADBE Vector Shape - Group\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"fl\",\n                                            \"c\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0.058823529631,\n                                                    0.705882370472,\n                                                    0.831372559071, 1\n                                                ],\n                                                \"ix\": 4\n                                            },\n                                            \"o\": { \"a\": 0, \"k\": 100, \"ix\": 5 },\n                                            \"r\": 1,\n                                            \"bm\": 0,\n                                            \"nm\": \"Fill 1\",\n                                            \"mn\": \"ADBE Vector Graphic - Fill\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"tr\",\n                                            \"p\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 2\n                                            },\n                                            \"a\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 1\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [100, 100],\n                                                \"ix\": 3\n                                            },\n                                            \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                            \"o\": { \"a\": 0, \"k\": 50, \"ix\": 7 },\n                                            \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                            \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                            \"nm\": \"Transform\"\n                                        }\n                                    ],\n                                    \"nm\": \"Group 6\",\n                                    \"np\": 2,\n                                    \"cix\": 2,\n                                    \"bm\": 0,\n                                    \"ix\": 3,\n                                    \"mn\": \"ADBE Vector Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"gr\",\n                                    \"it\": [\n                                        {\n                                            \"ind\": 0,\n                                            \"ty\": \"sh\",\n                                            \"ix\": 1,\n                                            \"ks\": {\n                                                \"a\": 0,\n                                                \"k\": {\n                                                    \"i\": [\n                                                        [-1.271, -0.967],\n                                                        [-0.407, 0.148],\n                                                        [1.258, 0.945],\n                                                        [0.803, -0.283]\n                                                    ],\n                                                    \"o\": [\n                                                        [0.988, -0.374],\n                                                        [-1.257, -0.951],\n                                                        [-0.66, 0.232],\n                                                        [1.279, 0.953]\n                                                    ],\n                                                    \"v\": [\n                                                        [-251.812, 242.543],\n                                                        [-249.663, 241.733],\n                                                        [-253.431, 238.887],\n                                                        [-255.637, 239.659]\n                                                    ],\n                                                    \"c\": true\n                                                },\n                                                \"ix\": 2\n                                            },\n                                            \"nm\": \"Path 1\",\n                                            \"mn\": \"ADBE Vector Shape - Group\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"fl\",\n                                            \"c\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0.058823529631,\n                                                    0.705882370472,\n                                                    0.831372559071, 1\n                                                ],\n                                                \"ix\": 4\n                                            },\n                                            \"o\": { \"a\": 0, \"k\": 100, \"ix\": 5 },\n                                            \"r\": 1,\n                                            \"bm\": 0,\n                                            \"nm\": \"Fill 1\",\n                                            \"mn\": \"ADBE Vector Graphic - Fill\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"tr\",\n                                            \"p\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 2\n                                            },\n                                            \"a\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 1\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [100, 100],\n                                                \"ix\": 3\n                                            },\n                                            \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                            \"o\": { \"a\": 0, \"k\": 50, \"ix\": 7 },\n                                            \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                            \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                            \"nm\": \"Transform\"\n                                        }\n                                    ],\n                                    \"nm\": \"Group 7\",\n                                    \"np\": 2,\n                                    \"cix\": 2,\n                                    \"bm\": 0,\n                                    \"ix\": 4,\n                                    \"mn\": \"ADBE Vector Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"gr\",\n                                    \"it\": [\n                                        {\n                                            \"ind\": 0,\n                                            \"ty\": \"sh\",\n                                            \"ix\": 1,\n                                            \"ks\": {\n                                                \"a\": 0,\n                                                \"k\": {\n                                                    \"i\": [\n                                                        [0, 0],\n                                                        [-0.988, 0.359],\n                                                        [0.92, -0.309],\n                                                        [6.715, -2.361]\n                                                    ],\n                                                    \"o\": [\n                                                        [6.81, -2.612],\n                                                        [0.59, -0.214],\n                                                        [-1.177, 0.393],\n                                                        [0, 0]\n                                                    ],\n                                                    \"v\": [\n                                                        [-266.05, 248.005],\n                                                        [-249.399, 241.634],\n                                                        [-250.421, 237.841],\n                                                        [-267.078, 243.648]\n                                                    ],\n                                                    \"c\": true\n                                                },\n                                                \"ix\": 2\n                                            },\n                                            \"nm\": \"Path 1\",\n                                            \"mn\": \"ADBE Vector Shape - Group\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"fl\",\n                                            \"c\": {\n                                                \"a\": 0,\n                                                \"k\": [\n                                                    0.458823531866,\n                                                    0.839215695858, 1, 1\n                                                ],\n                                                \"ix\": 4\n                                            },\n                                            \"o\": { \"a\": 0, \"k\": 100, \"ix\": 5 },\n                                            \"r\": 1,\n                                            \"bm\": 0,\n                                            \"nm\": \"Fill 1\",\n                                            \"mn\": \"ADBE Vector Graphic - Fill\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"tr\",\n                                            \"p\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 2\n                                            },\n                                            \"a\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 1\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [100, 100],\n                                                \"ix\": 3\n                                            },\n                                            \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                            \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                            \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                            \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                            \"nm\": \"Transform\"\n                                        }\n                                    ],\n                                    \"nm\": \"Group 8\",\n                                    \"np\": 2,\n                                    \"cix\": 2,\n                                    \"bm\": 0,\n                                    \"ix\": 5,\n                                    \"mn\": \"ADBE Vector Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": { \"a\": 0, \"k\": [0, 0], \"ix\": 2 },\n                                    \"a\": { \"a\": 0, \"k\": [0, 0], \"ix\": 1 },\n                                    \"s\": { \"a\": 0, \"k\": [100, 100], \"ix\": 3 },\n                                    \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                    \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                    \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"Group 2\",\n                            \"np\": 5,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 0,\n                    \"op\": 49,\n                    \"st\": 0,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 19,\n                    \"ty\": 4,\n                    \"nm\": \"Blush\",\n                    \"parent\": 1,\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 21,\n                                    \"s\": [0]\n                                },\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 27,\n                                    \"s\": [97]\n                                },\n                                {\n                                    \"i\": { \"x\": [0.833], \"y\": [0.833] },\n                                    \"o\": { \"x\": [0.167], \"y\": [0.167] },\n                                    \"t\": 34,\n                                    \"s\": [100]\n                                },\n                                { \"t\": 46, \"s\": [0] }\n                            ],\n                            \"ix\": 11\n                        },\n                        \"r\": { \"a\": 0, \"k\": 0, \"ix\": 10 },\n                        \"p\": { \"a\": 0, \"k\": [-1.651, 60.272, 0], \"ix\": 2 },\n                        \"a\": { \"a\": 0, \"k\": [-244.666, 234.519, 0], \"ix\": 1 },\n                        \"s\": { \"a\": 0, \"k\": [1262, 1262, 100], \"ix\": 6 }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ty\": \"gr\",\n                                    \"it\": [\n                                        {\n                                            \"ind\": 0,\n                                            \"ty\": \"sh\",\n                                            \"ix\": 1,\n                                            \"ks\": {\n                                                \"a\": 0,\n                                                \"k\": {\n                                                    \"i\": [\n                                                        [-5.559, 0],\n                                                        [0, -5.557],\n                                                        [5.557, 0],\n                                                        [0, 5.561]\n                                                    ],\n                                                    \"o\": [\n                                                        [5.557, 0],\n                                                        [0, 5.561],\n                                                        [-5.559, 0],\n                                                        [0, -5.557]\n                                                    ],\n                                                    \"v\": [\n                                                        [-229.286, 224.454],\n                                                        [-219.221, 234.519],\n                                                        [-229.286, 244.583],\n                                                        [-239.35, 234.519]\n                                                    ],\n                                                    \"c\": true\n                                                },\n                                                \"ix\": 2\n                                            },\n                                            \"nm\": \"Path 1\",\n                                            \"mn\": \"ADBE Vector Shape - Group\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"gf\",\n                                            \"o\": { \"a\": 0, \"k\": 100, \"ix\": 10 },\n                                            \"r\": 1,\n                                            \"bm\": 0,\n                                            \"g\": {\n                                                \"p\": 3,\n                                                \"k\": {\n                                                    \"a\": 0,\n                                                    \"k\": [\n                                                        0.1, 1, 0.388, 0.6,\n                                                        0.73, 1, 0.649, 0.351,\n                                                        1, 1, 0.91, 0.102, 0.1,\n                                                        1, 0.73, 0.5, 1, 0\n                                                    ],\n                                                    \"ix\": 9\n                                                }\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [-230, 234],\n                                                \"ix\": 5\n                                            },\n                                            \"e\": {\n                                                \"a\": 0,\n                                                \"k\": [-219.936, 234],\n                                                \"ix\": 6\n                                            },\n                                            \"t\": 2,\n                                            \"h\": { \"a\": 0, \"k\": 0, \"ix\": 7 },\n                                            \"a\": { \"a\": 0, \"k\": 0, \"ix\": 8 },\n                                            \"nm\": \"B1G\",\n                                            \"mn\": \"ADBE Vector Graphic - G-Fill\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"tr\",\n                                            \"p\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 2\n                                            },\n                                            \"a\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 1\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [100, 100],\n                                                \"ix\": 3\n                                            },\n                                            \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                            \"o\": { \"a\": 0, \"k\": 60, \"ix\": 7 },\n                                            \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                            \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                            \"nm\": \"Transform\"\n                                        }\n                                    ],\n                                    \"nm\": \"Group 1\",\n                                    \"np\": 2,\n                                    \"cix\": 2,\n                                    \"bm\": 0,\n                                    \"ix\": 1,\n                                    \"mn\": \"ADBE Vector Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"gr\",\n                                    \"it\": [\n                                        {\n                                            \"ind\": 0,\n                                            \"ty\": \"sh\",\n                                            \"ix\": 1,\n                                            \"ks\": {\n                                                \"a\": 0,\n                                                \"k\": {\n                                                    \"i\": [\n                                                        [-5.559, 0],\n                                                        [0, -5.557],\n                                                        [5.557, 0],\n                                                        [0, 5.561]\n                                                    ],\n                                                    \"o\": [\n                                                        [5.557, 0],\n                                                        [0, 5.561],\n                                                        [-5.559, 0],\n                                                        [0, -5.557]\n                                                    ],\n                                                    \"v\": [\n                                                        [-260.046, 224.454],\n                                                        [-249.983, 234.519],\n                                                        [-260.046, 244.583],\n                                                        [-270.111, 234.519]\n                                                    ],\n                                                    \"c\": true\n                                                },\n                                                \"ix\": 2\n                                            },\n                                            \"nm\": \"Path 1\",\n                                            \"mn\": \"ADBE Vector Shape - Group\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"gf\",\n                                            \"o\": { \"a\": 0, \"k\": 100, \"ix\": 10 },\n                                            \"r\": 1,\n                                            \"bm\": 0,\n                                            \"g\": {\n                                                \"p\": 3,\n                                                \"k\": {\n                                                    \"a\": 0,\n                                                    \"k\": [\n                                                        0.1, 1, 0.388, 0.6,\n                                                        0.73, 1, 0.649, 0.351,\n                                                        1, 1, 0.91, 0.102, 0.1,\n                                                        1, 0.73, 0.5, 1, 0\n                                                    ],\n                                                    \"ix\": 9\n                                                }\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [-261, 234],\n                                                \"ix\": 5\n                                            },\n                                            \"e\": {\n                                                \"a\": 0,\n                                                \"k\": [-250.936, 234],\n                                                \"ix\": 6\n                                            },\n                                            \"t\": 2,\n                                            \"h\": { \"a\": 0, \"k\": 0, \"ix\": 7 },\n                                            \"a\": { \"a\": 0, \"k\": 0, \"ix\": 8 },\n                                            \"nm\": \"B2G\",\n                                            \"mn\": \"ADBE Vector Graphic - G-Fill\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"tr\",\n                                            \"p\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 2\n                                            },\n                                            \"a\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 1\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [100, 100],\n                                                \"ix\": 3\n                                            },\n                                            \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                            \"o\": { \"a\": 0, \"k\": 60, \"ix\": 7 },\n                                            \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                            \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                            \"nm\": \"Transform\"\n                                        }\n                                    ],\n                                    \"nm\": \"Group 2\",\n                                    \"np\": 2,\n                                    \"cix\": 2,\n                                    \"bm\": 0,\n                                    \"ix\": 2,\n                                    \"mn\": \"ADBE Vector Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": { \"a\": 0, \"k\": [0, 0], \"ix\": 2 },\n                                    \"a\": { \"a\": 0, \"k\": [0, 0], \"ix\": 1 },\n                                    \"s\": { \"a\": 0, \"k\": [100, 100], \"ix\": 3 },\n                                    \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                    \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                    \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"Group 3\",\n                            \"np\": 2,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 0,\n                    \"op\": 49,\n                    \"st\": 0,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 20,\n                    \"ty\": 4,\n                    \"nm\": \"Eyes\",\n                    \"parent\": 1,\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": { \"a\": 0, \"k\": 100, \"ix\": 11 },\n                        \"r\": { \"a\": 0, \"k\": 0, \"ix\": 10 },\n                        \"p\": { \"a\": 0, \"k\": [0, -52.396, 0], \"ix\": 2 },\n                        \"a\": { \"a\": 0, \"k\": [-244.535, 225.591, 0], \"ix\": 1 },\n                        \"s\": {\n                            \"a\": 1,\n                            \"k\": [\n                                {\n                                    \"i\": {\n                                        \"x\": [0.667, 0.667, 0.667],\n                                        \"y\": [1, 1, 1]\n                                    },\n                                    \"o\": {\n                                        \"x\": [0.333, 0.333, 0.333],\n                                        \"y\": [0, 0, 0]\n                                    },\n                                    \"t\": 0,\n                                    \"s\": [1262, 1262, 100]\n                                },\n                                {\n                                    \"i\": { \"x\": [0, 0, 0.667], \"y\": [1, 1, 1] },\n                                    \"o\": {\n                                        \"x\": [0.333, 0.333, 0.333],\n                                        \"y\": [0, 0, 0]\n                                    },\n                                    \"t\": 5,\n                                    \"s\": [1262, 1009.6, 100]\n                                },\n                                {\n                                    \"i\": {\n                                        \"x\": [0.667, 0.667, 0.667],\n                                        \"y\": [1, 1, 1]\n                                    },\n                                    \"o\": {\n                                        \"x\": [0.333, 0.333, 0.333],\n                                        \"y\": [0, 0, 0]\n                                    },\n                                    \"t\": 18,\n                                    \"s\": [1262, 1388.2, 100]\n                                },\n                                {\n                                    \"i\": { \"x\": [0, 0, 0.667], \"y\": [1, 1, 1] },\n                                    \"o\": {\n                                        \"x\": [0.333, 0.333, 0.333],\n                                        \"y\": [0, 0, 0]\n                                    },\n                                    \"t\": 26,\n                                    \"s\": [1262, 1009.6, 100]\n                                },\n                                { \"t\": 44, \"s\": [1262, 1262, 100] }\n                            ],\n                            \"ix\": 6\n                        }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ty\": \"gr\",\n                                    \"it\": [\n                                        {\n                                            \"ty\": \"gr\",\n                                            \"it\": [\n                                                {\n                                                    \"ty\": \"gr\",\n                                                    \"it\": [\n                                                        {\n                                                            \"ty\": \"gr\",\n                                                            \"it\": [\n                                                                {\n                                                                    \"ind\": 0,\n                                                                    \"ty\": \"sh\",\n                                                                    \"ix\": 1,\n                                                                    \"ks\": {\n                                                                        \"a\": 0,\n                                                                        \"k\": {\n                                                                            \"i\": [\n                                                                                [\n                                                                                    0.605,\n                                                                                    0.779\n                                                                                ],\n                                                                                [\n                                                                                    3.988,\n                                                                                    -5.154\n                                                                                ],\n                                                                                [\n                                                                                    -0.258,\n                                                                                    0.756\n                                                                                ],\n                                                                                [\n                                                                                    -3.385,\n                                                                                    -9.963\n                                                                                ]\n                                                                            ],\n                                                                            \"o\": [\n                                                                                [\n                                                                                    -3.989,\n                                                                                    -5.154\n                                                                                ],\n                                                                                [\n                                                                                    -0.605,\n                                                                                    0.779\n                                                                                ],\n                                                                                [\n                                                                                    3.385,\n                                                                                    -9.963\n                                                                                ],\n                                                                                [\n                                                                                    0.258,\n                                                                                    0.756\n                                                                                ]\n                                                                            ],\n                                                                            \"v\": [\n                                                                                [\n                                                                                    -248.954,\n                                                                                    223.965\n                                                                                ],\n                                                                                [\n                                                                                    -259.716,\n                                                                                    223.965\n                                                                                ],\n                                                                                [\n                                                                                    -261.3,\n                                                                                    223.408\n                                                                                ],\n                                                                                [\n                                                                                    -247.37,\n                                                                                    223.408\n                                                                                ]\n                                                                            ],\n                                                                            \"c\": true\n                                                                        },\n                                                                        \"ix\": 2\n                                                                    },\n                                                                    \"nm\": \"Path 1\",\n                                                                    \"mn\": \"ADBE Vector Shape - Group\",\n                                                                    \"hd\": false\n                                                                },\n                                                                {\n                                                                    \"ty\": \"fl\",\n                                                                    \"c\": {\n                                                                        \"a\": 0,\n                                                                        \"k\": [\n                                                                            0.101960785687,\n                                                                            0.086274512112,\n                                                                            0.149019613862,\n                                                                            1\n                                                                        ],\n                                                                        \"ix\": 4\n                                                                    },\n                                                                    \"o\": {\n                                                                        \"a\": 0,\n                                                                        \"k\": 100,\n                                                                        \"ix\": 5\n                                                                    },\n                                                                    \"r\": 1,\n                                                                    \"bm\": 0,\n                                                                    \"nm\": \"Fill 1\",\n                                                                    \"mn\": \"ADBE Vector Graphic - Fill\",\n                                                                    \"hd\": false\n                                                                },\n                                                                {\n                                                                    \"ty\": \"tr\",\n                                                                    \"p\": {\n                                                                        \"a\": 0,\n                                                                        \"k\": [\n                                                                            0, 0\n                                                                        ],\n                                                                        \"ix\": 2\n                                                                    },\n                                                                    \"a\": {\n                                                                        \"a\": 0,\n                                                                        \"k\": [\n                                                                            0, 0\n                                                                        ],\n                                                                        \"ix\": 1\n                                                                    },\n                                                                    \"s\": {\n                                                                        \"a\": 0,\n                                                                        \"k\": [\n                                                                            100,\n                                                                            100\n                                                                        ],\n                                                                        \"ix\": 3\n                                                                    },\n                                                                    \"r\": {\n                                                                        \"a\": 0,\n                                                                        \"k\": 0,\n                                                                        \"ix\": 6\n                                                                    },\n                                                                    \"o\": {\n                                                                        \"a\": 0,\n                                                                        \"k\": 100,\n                                                                        \"ix\": 7\n                                                                    },\n                                                                    \"sk\": {\n                                                                        \"a\": 0,\n                                                                        \"k\": 0,\n                                                                        \"ix\": 4\n                                                                    },\n                                                                    \"sa\": {\n                                                                        \"a\": 0,\n                                                                        \"k\": 0,\n                                                                        \"ix\": 5\n                                                                    },\n                                                                    \"nm\": \"Transform\"\n                                                                }\n                                                            ],\n                                                            \"nm\": \"Group 1\",\n                                                            \"np\": 2,\n                                                            \"cix\": 2,\n                                                            \"bm\": 0,\n                                                            \"ix\": 1,\n                                                            \"mn\": \"ADBE Vector Group\",\n                                                            \"hd\": false\n                                                        },\n                                                        {\n                                                            \"ty\": \"gr\",\n                                                            \"it\": [\n                                                                {\n                                                                    \"ind\": 0,\n                                                                    \"ty\": \"sh\",\n                                                                    \"ix\": 1,\n                                                                    \"ks\": {\n                                                                        \"a\": 0,\n                                                                        \"k\": {\n                                                                            \"i\": [\n                                                                                [\n                                                                                    0.605,\n                                                                                    0.779\n                                                                                ],\n                                                                                [\n                                                                                    3.989,\n                                                                                    -5.154\n                                                                                ],\n                                                                                [\n                                                                                    -0.258,\n                                                                                    0.756\n                                                                                ],\n                                                                                [\n                                                                                    -3.387,\n                                                                                    -9.963\n                                                                                ]\n                                                                            ],\n                                                                            \"o\": [\n                                                                                [\n                                                                                    -3.989,\n                                                                                    -5.154\n                                                                                ],\n                                                                                [\n                                                                                    -0.605,\n                                                                                    0.779\n                                                                                ],\n                                                                                [\n                                                                                    3.385,\n                                                                                    -9.963\n                                                                                ],\n                                                                                [\n                                                                                    0.256,\n                                                                                    0.756\n                                                                                ]\n                                                                            ],\n                                                                            \"v\": [\n                                                                                [\n                                                                                    -229.355,\n                                                                                    223.965\n                                                                                ],\n                                                                                [\n                                                                                    -240.117,\n                                                                                    223.965\n                                                                                ],\n                                                                                [\n                                                                                    -241.7,\n                                                                                    223.408\n                                                                                ],\n                                                                                [\n                                                                                    -227.769,\n                                                                                    223.408\n                                                                                ]\n                                                                            ],\n                                                                            \"c\": true\n                                                                        },\n                                                                        \"ix\": 2\n                                                                    },\n                                                                    \"nm\": \"Path 1\",\n                                                                    \"mn\": \"ADBE Vector Shape - Group\",\n                                                                    \"hd\": false\n                                                                },\n                                                                {\n                                                                    \"ty\": \"fl\",\n                                                                    \"c\": {\n                                                                        \"a\": 0,\n                                                                        \"k\": [\n                                                                            0.101960785687,\n                                                                            0.086274512112,\n                                                                            0.149019613862,\n                                                                            1\n                                                                        ],\n                                                                        \"ix\": 4\n                                                                    },\n                                                                    \"o\": {\n                                                                        \"a\": 0,\n                                                                        \"k\": 100,\n                                                                        \"ix\": 5\n                                                                    },\n                                                                    \"r\": 1,\n                                                                    \"bm\": 0,\n                                                                    \"nm\": \"Fill 1\",\n                                                                    \"mn\": \"ADBE Vector Graphic - Fill\",\n                                                                    \"hd\": false\n                                                                },\n                                                                {\n                                                                    \"ty\": \"tr\",\n                                                                    \"p\": {\n                                                                        \"a\": 0,\n                                                                        \"k\": [\n                                                                            0, 0\n                                                                        ],\n                                                                        \"ix\": 2\n                                                                    },\n                                                                    \"a\": {\n                                                                        \"a\": 0,\n                                                                        \"k\": [\n                                                                            0, 0\n                                                                        ],\n                                                                        \"ix\": 1\n                                                                    },\n                                                                    \"s\": {\n                                                                        \"a\": 0,\n                                                                        \"k\": [\n                                                                            100,\n                                                                            100\n                                                                        ],\n                                                                        \"ix\": 3\n                                                                    },\n                                                                    \"r\": {\n                                                                        \"a\": 0,\n                                                                        \"k\": 0,\n                                                                        \"ix\": 6\n                                                                    },\n                                                                    \"o\": {\n                                                                        \"a\": 0,\n                                                                        \"k\": 100,\n                                                                        \"ix\": 7\n                                                                    },\n                                                                    \"sk\": {\n                                                                        \"a\": 0,\n                                                                        \"k\": 0,\n                                                                        \"ix\": 4\n                                                                    },\n                                                                    \"sa\": {\n                                                                        \"a\": 0,\n                                                                        \"k\": 0,\n                                                                        \"ix\": 5\n                                                                    },\n                                                                    \"nm\": \"Transform\"\n                                                                }\n                                                            ],\n                                                            \"nm\": \"Group 2\",\n                                                            \"np\": 2,\n                                                            \"cix\": 2,\n                                                            \"bm\": 0,\n                                                            \"ix\": 2,\n                                                            \"mn\": \"ADBE Vector Group\",\n                                                            \"hd\": false\n                                                        },\n                                                        {\n                                                            \"ty\": \"tr\",\n                                                            \"p\": {\n                                                                \"a\": 0,\n                                                                \"k\": [0, 0],\n                                                                \"ix\": 2\n                                                            },\n                                                            \"a\": {\n                                                                \"a\": 0,\n                                                                \"k\": [0, 0],\n                                                                \"ix\": 1\n                                                            },\n                                                            \"s\": {\n                                                                \"a\": 0,\n                                                                \"k\": [100, 100],\n                                                                \"ix\": 3\n                                                            },\n                                                            \"r\": {\n                                                                \"a\": 0,\n                                                                \"k\": 0,\n                                                                \"ix\": 6\n                                                            },\n                                                            \"o\": {\n                                                                \"a\": 0,\n                                                                \"k\": 100,\n                                                                \"ix\": 7\n                                                            },\n                                                            \"sk\": {\n                                                                \"a\": 0,\n                                                                \"k\": 0,\n                                                                \"ix\": 4\n                                                            },\n                                                            \"sa\": {\n                                                                \"a\": 0,\n                                                                \"k\": 0,\n                                                                \"ix\": 5\n                                                            },\n                                                            \"nm\": \"Transform\"\n                                                        }\n                                                    ],\n                                                    \"nm\": \"Group 1\",\n                                                    \"np\": 2,\n                                                    \"cix\": 2,\n                                                    \"bm\": 0,\n                                                    \"ix\": 1,\n                                                    \"mn\": \"ADBE Vector Group\",\n                                                    \"hd\": false\n                                                },\n                                                {\n                                                    \"ty\": \"tr\",\n                                                    \"p\": {\n                                                        \"a\": 0,\n                                                        \"k\": [0, 0],\n                                                        \"ix\": 2\n                                                    },\n                                                    \"a\": {\n                                                        \"a\": 0,\n                                                        \"k\": [0, 0],\n                                                        \"ix\": 1\n                                                    },\n                                                    \"s\": {\n                                                        \"a\": 0,\n                                                        \"k\": [100, 100],\n                                                        \"ix\": 3\n                                                    },\n                                                    \"r\": {\n                                                        \"a\": 0,\n                                                        \"k\": 0,\n                                                        \"ix\": 6\n                                                    },\n                                                    \"o\": {\n                                                        \"a\": 0,\n                                                        \"k\": 100,\n                                                        \"ix\": 7\n                                                    },\n                                                    \"sk\": {\n                                                        \"a\": 0,\n                                                        \"k\": 0,\n                                                        \"ix\": 4\n                                                    },\n                                                    \"sa\": {\n                                                        \"a\": 0,\n                                                        \"k\": 0,\n                                                        \"ix\": 5\n                                                    },\n                                                    \"nm\": \"Transform\"\n                                                }\n                                            ],\n                                            \"nm\": \"Group 1\",\n                                            \"np\": 1,\n                                            \"cix\": 2,\n                                            \"bm\": 0,\n                                            \"ix\": 1,\n                                            \"mn\": \"ADBE Vector Group\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"tr\",\n                                            \"p\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 2\n                                            },\n                                            \"a\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 1\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [100, 100],\n                                                \"ix\": 3\n                                            },\n                                            \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                            \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                            \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                            \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                            \"nm\": \"Transform\"\n                                        }\n                                    ],\n                                    \"nm\": \"Group 1\",\n                                    \"np\": 1,\n                                    \"cix\": 2,\n                                    \"bm\": 0,\n                                    \"ix\": 1,\n                                    \"mn\": \"ADBE Vector Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": { \"a\": 0, \"k\": [0, 0], \"ix\": 2 },\n                                    \"a\": { \"a\": 0, \"k\": [0, 0], \"ix\": 1 },\n                                    \"s\": { \"a\": 0, \"k\": [100, 100], \"ix\": 3 },\n                                    \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                    \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                    \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"Group 4\",\n                            \"np\": 1,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 0,\n                    \"op\": 49,\n                    \"st\": 0,\n                    \"bm\": 0\n                },\n                {\n                    \"ddd\": 0,\n                    \"ind\": 21,\n                    \"ty\": 4,\n                    \"nm\": \"Face\",\n                    \"parent\": 2,\n                    \"sr\": 1,\n                    \"ks\": {\n                        \"o\": { \"a\": 0, \"k\": 100, \"ix\": 11 },\n                        \"r\": { \"a\": 0, \"k\": 0, \"ix\": 10 },\n                        \"p\": { \"a\": 0, \"k\": [0, -338.396, 0], \"ix\": 2 },\n                        \"a\": { \"a\": 0, \"k\": [-244.535, 225.591, 0], \"ix\": 1 },\n                        \"s\": { \"a\": 0, \"k\": [1262, 1262, 100], \"ix\": 6 }\n                    },\n                    \"ao\": 0,\n                    \"shapes\": [\n                        {\n                            \"ty\": \"gr\",\n                            \"it\": [\n                                {\n                                    \"ty\": \"gr\",\n                                    \"it\": [\n                                        {\n                                            \"ind\": 0,\n                                            \"ty\": \"sh\",\n                                            \"ix\": 1,\n                                            \"ks\": {\n                                                \"a\": 0,\n                                                \"k\": {\n                                                    \"i\": [\n                                                        [15.464, 0],\n                                                        [0, -15.467],\n                                                        [-15.464, 0],\n                                                        [-0.001, 15.459]\n                                                    ],\n                                                    \"o\": [\n                                                        [-15.464, 0],\n                                                        [0, 15.459],\n                                                        [15.464, 0],\n                                                        [0.001, -15.467]\n                                                    ],\n                                                    \"v\": [\n                                                        [-244.535, 197.592],\n                                                        [-272.535, 225.592],\n                                                        [-244.535, 253.59],\n                                                        [-216.535, 225.592]\n                                                    ],\n                                                    \"c\": true\n                                                },\n                                                \"ix\": 2\n                                            },\n                                            \"nm\": \"Path 1\",\n                                            \"mn\": \"ADBE Vector Shape - Group\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"gf\",\n                                            \"o\": { \"a\": 0, \"k\": 100, \"ix\": 10 },\n                                            \"r\": 1,\n                                            \"bm\": 0,\n                                            \"g\": {\n                                                \"p\": 3,\n                                                \"k\": {\n                                                    \"a\": 0,\n                                                    \"k\": [\n                                                        0, 1, 0.584, 0, 0.4, 1,\n                                                        0.747, 0.051, 1, 1,\n                                                        0.91, 0.102\n                                                    ],\n                                                    \"ix\": 9\n                                                }\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [-231.07, 253],\n                                                \"ix\": 5\n                                            },\n                                            \"e\": {\n                                                \"a\": 0,\n                                                \"k\": [-231.07, 198.011],\n                                                \"ix\": 6\n                                            },\n                                            \"t\": 1,\n                                            \"nm\": \"party_face_grad\",\n                                            \"mn\": \"ADBE Vector Graphic - G-Fill\",\n                                            \"hd\": false\n                                        },\n                                        {\n                                            \"ty\": \"tr\",\n                                            \"p\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 2\n                                            },\n                                            \"a\": {\n                                                \"a\": 0,\n                                                \"k\": [0, 0],\n                                                \"ix\": 1\n                                            },\n                                            \"s\": {\n                                                \"a\": 0,\n                                                \"k\": [100, 100],\n                                                \"ix\": 3\n                                            },\n                                            \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                            \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                            \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                            \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                            \"nm\": \"Transform\"\n                                        }\n                                    ],\n                                    \"nm\": \"Group 2\",\n                                    \"np\": 2,\n                                    \"cix\": 2,\n                                    \"bm\": 0,\n                                    \"ix\": 1,\n                                    \"mn\": \"ADBE Vector Group\",\n                                    \"hd\": false\n                                },\n                                {\n                                    \"ty\": \"tr\",\n                                    \"p\": { \"a\": 0, \"k\": [0, 0], \"ix\": 2 },\n                                    \"a\": { \"a\": 0, \"k\": [0, 0], \"ix\": 1 },\n                                    \"s\": { \"a\": 0, \"k\": [100, 100], \"ix\": 3 },\n                                    \"r\": { \"a\": 0, \"k\": 0, \"ix\": 6 },\n                                    \"o\": { \"a\": 0, \"k\": 100, \"ix\": 7 },\n                                    \"sk\": { \"a\": 0, \"k\": 0, \"ix\": 4 },\n                                    \"sa\": { \"a\": 0, \"k\": 0, \"ix\": 5 },\n                                    \"nm\": \"Transform\"\n                                }\n                            ],\n                            \"nm\": \"Group 4\",\n                            \"np\": 1,\n                            \"cix\": 2,\n                            \"bm\": 0,\n                            \"ix\": 1,\n                            \"mn\": \"ADBE Vector Group\",\n                            \"hd\": false\n                        }\n                    ],\n                    \"ip\": 0,\n                    \"op\": 49,\n                    \"st\": 0,\n                    \"bm\": 0\n                }\n            ]\n        }\n    ],\n    \"layers\": [\n        {\n            \"ddd\": 0,\n            \"ind\": 1,\n            \"ty\": 0,\n            \"nm\": \"party_face\",\n            \"refId\": \"comp_0\",\n            \"sr\": 1,\n            \"ks\": {\n                \"o\": { \"a\": 0, \"k\": 100, \"ix\": 11 },\n                \"r\": { \"a\": 0, \"k\": 0, \"ix\": 10 },\n                \"p\": { \"a\": 0, \"k\": [512, 512, 0], \"ix\": 2 },\n                \"a\": { \"a\": 0, \"k\": [512, 512, 0], \"ix\": 1 },\n                \"s\": { \"a\": 0, \"k\": [100, 100, 100], \"ix\": 6 }\n            },\n            \"ao\": 0,\n            \"w\": 1024,\n            \"h\": 1024,\n            \"ip\": 0,\n            \"op\": 48,\n            \"st\": 0,\n            \"bm\": 0\n        }\n    ],\n    \"markers\": []\n}\n"
  },
  {
    "path": "thorvg/examples/thorvg_lottie/main/CMakeLists.txt",
    "content": "idf_component_register(\n    SRCS \"thorvg_example_main.c\"\n    INCLUDE_DIRS \".\"\n    PRIV_REQUIRES esp_lcd pthread)\n\nlittlefs_create_partition_image(storage ../lottie_files FLASH_IN_PROJECT)\n"
  },
  {
    "path": "thorvg/examples/thorvg_lottie/main/idf_component.yml",
    "content": "dependencies:\n  espressif/esp_lcd_sh8601: \"^2.0.0\"\n  joltwallet/littlefs: \"^1.20.0\"\n  espressif/thorvg:\n    version: \"*\"\n    override_path: \"../../..\"\n"
  },
  {
    "path": "thorvg/examples/thorvg_lottie/main/thorvg_example_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n\n#include <stdlib.h>\n#include <dirent.h>\n#include <pthread.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/semphr.h\"\n#include \"freertos/task.h\"\n#include \"esp_log.h\"\n#include \"esp_err.h\"\n#include \"esp_check.h\"\n#include \"esp_pthread.h\"\n#include \"esp_heap_caps.h\"\n#include \"esp_littlefs.h\"\n#include \"esp_lcd_panel_ops.h\"\n#include \"esp_lcd_panel_io.h\"\n#include \"esp_lcd_sh8601.h\"\n#include \"driver/spi_master.h\"\n#include \"thorvg_capi.h\"\n\nstatic const char *TAG = \"example\";\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////// Please update the following configuration according to your LCD spec //////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n#define EXAMPLE_PIN_NUM_LCD_CS      12\n#define EXAMPLE_PIN_NUM_LCD_PCLK    11\n#define EXAMPLE_PIN_NUM_LCD_DATA0   4\n#define EXAMPLE_PIN_NUM_LCD_DATA1   5\n#define EXAMPLE_PIN_NUM_LCD_DATA2   6\n#define EXAMPLE_PIN_NUM_LCD_DATA3   7\n\n#define EXAMPLE_LCD_PCLK_HZ         (20 * 1000 * 1000)\n#define EXAMPLE_LCD_BIT_PER_PIXEL   16  // RGB565\n\n#define EXAMPLE_LCD_SPI_HOST        SPI2_HOST\n\n#define EXAMPLE_FS_MOUNT_POINT     \"/storage\"\n#define EXAMPLE_LOTTIE_FILENAME     EXAMPLE_FS_MOUNT_POINT\"/emoji-animation.json\"\n#define EXAMPLE_LOTTIE_SIZE_HOR     368\n#define EXAMPLE_LOTTIE_SIZE_VER     448\n\n\nstatic const sh8601_lcd_init_cmd_t lcd_init_cmds[] = {\n    {0x11, (uint8_t[]){0x00}, 0, 120},\n    {0x44, (uint8_t[]){0x01, 0xD1}, 2, 0},\n    {0x35, (uint8_t[]){0x00}, 1, 0},\n    {0x53, (uint8_t[]){0x20}, 1, 10},\n    {0x2A, (uint8_t[]){0x00, 0x00, 0x01, 0x6F}, 4, 0},\n    {0x2B, (uint8_t[]){0x00, 0x00, 0x01, 0xBF}, 4, 0},\n    {0x51, (uint8_t[]){0x00}, 1, 10},\n    {0x29, (uint8_t[]){0x00}, 0, 10},\n    {0x51, (uint8_t[]){0xFF}, 1, 0},\n};\n\nstatic void argb888_to_rgb565(const uint32_t *in, uint16_t *out, size_t num_pixels)\n{\n    for (size_t i = 0; i < num_pixels; ++i) {\n        uint32_t argb = in[i];\n        uint8_t r = (argb >> 16) & 0xFF;\n        uint8_t g = (argb >> 8) & 0xFF;\n        uint8_t b = argb & 0xFF;\n        // Convert to RGB565\n        uint16_t rgb565 = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);\n        rgb565 = (rgb565 >> 8) | (rgb565 << 8);\n        out[i] = rgb565;\n    }\n}\n\nstatic void play_lottie(esp_lcd_panel_handle_t lcd_panel, uint32_t *canvas_buf_argb888, uint16_t *canvas_buf_rgb565, SemaphoreHandle_t flush_done_sem)\n{\n    // Initialize ThorVG engine\n    if (tvg_engine_init(0) != TVG_RESULT_SUCCESS) {\n        printf(\"Failed to initialize ThorVG engine\\n\");\n        abort();\n    }\n\n    // Create a software canvas backed by an ARGB8888 buffer.\n    // ThorVG renders into this buffer first, then we convert it to panel RGB565.\n    Tvg_Canvas canvas = tvg_swcanvas_create(TVG_ENGINE_OPTION_DEFAULT);\n    assert(canvas);\n    tvg_swcanvas_set_target(canvas, canvas_buf_argb888, EXAMPLE_LOTTIE_SIZE_HOR, EXAMPLE_LOTTIE_SIZE_HOR, EXAMPLE_LOTTIE_SIZE_VER, TVG_COLORSPACE_ARGB8888);\n    // Flush the background with black.\n    esp_lcd_panel_draw_bitmap(lcd_panel, 0, 0, EXAMPLE_LOTTIE_SIZE_HOR, EXAMPLE_LOTTIE_SIZE_VER, canvas_buf_rgb565);\n\n    // Create an animation object\n    Tvg_Animation animation = tvg_lottie_animation_new();\n    // Get the picture object from animation\n    Tvg_Paint picture = tvg_animation_get_picture(animation);\n\n    // Load the Lottie file (JSON)\n    if (tvg_picture_load(picture, EXAMPLE_LOTTIE_FILENAME) != TVG_RESULT_SUCCESS) {\n        printf(\"Problem with loading a lottie file\\n\");\n        abort();\n    }\n    // Resize the picture\n    tvg_picture_set_size(picture, EXAMPLE_LOTTIE_SIZE_HOR, EXAMPLE_LOTTIE_SIZE_VER);\n    // add the picture to the canvas\n    tvg_canvas_add(canvas, picture);\n\n    // Play the animation frame by frame.\n    float total_frames;\n    tvg_animation_get_total_frame(animation, &total_frames);\n\n    for (float frame = 0.0f; frame < total_frames; frame += 1.0f) {\n        tvg_animation_set_frame(animation, frame);\n        tvg_canvas_update(canvas);\n        // Draw the canvas (renders to the buffer)\n        tvg_canvas_draw(canvas, false);\n        // Sync to ensure drawing is completed\n        tvg_canvas_sync(canvas);\n\n        // Wait until the previous panel transfer is completed before reusing buffers.\n        xSemaphoreTake(flush_done_sem, portMAX_DELAY);\n        // Convert ARGB8888 to RGB565 and flush one full frame to the panel.\n        argb888_to_rgb565(canvas_buf_argb888, canvas_buf_rgb565, EXAMPLE_LOTTIE_SIZE_HOR * EXAMPLE_LOTTIE_SIZE_VER);\n        esp_lcd_panel_draw_bitmap(lcd_panel, 0, 0, EXAMPLE_LOTTIE_SIZE_HOR, EXAMPLE_LOTTIE_SIZE_VER, canvas_buf_rgb565);\n    }\n\n    // Cleanup\n    tvg_animation_del(animation);\n    tvg_canvas_destroy(canvas);\n    tvg_engine_term();\n}\n\ntypedef struct {\n    esp_lcd_panel_handle_t lcd_panel;\n    uint32_t *canvas_buf_argb888;\n    uint16_t *canvas_buf_rgb565;\n    SemaphoreHandle_t flush_done_sem;\n} lottie_render_ctx_t;\n\nstatic void *lottie_render_thread(void *arg)\n{\n    lottie_render_ctx_t *ctx = (lottie_render_ctx_t *)arg;\n    uint32_t *canvas_buf_argb888 = ctx->canvas_buf_argb888;\n    uint16_t *canvas_buf_rgb565 = ctx->canvas_buf_rgb565;\n    esp_lcd_panel_handle_t lcd_panel = ctx->lcd_panel;\n    SemaphoreHandle_t flush_done_sem = ctx->flush_done_sem;\n\n    while (1) {\n        play_lottie(lcd_panel, canvas_buf_argb888, canvas_buf_rgb565, flush_done_sem);\n        vTaskDelay(pdMS_TO_TICKS(100));\n    }\n\n    return NULL;\n}\n\nstatic esp_err_t example_init_fs(void)\n{\n    esp_vfs_littlefs_conf_t conf = {\n        .base_path = EXAMPLE_FS_MOUNT_POINT,\n        .partition_label = \"storage\",\n        .format_if_mount_failed = true,\n    };\n    esp_err_t ret = esp_vfs_littlefs_register(&conf);\n\n    if (ret != ESP_OK) {\n        if (ret == ESP_FAIL) {\n            ESP_LOGE(TAG, \"Failed to mount or format filesystem\");\n        } else if (ret == ESP_ERR_NOT_FOUND) {\n            ESP_LOGE(TAG, \"Failed to find LittleFS partition\");\n        } else {\n            ESP_LOGE(TAG, \"Failed to initialize LittleFS (%s)\", esp_err_to_name(ret));\n        }\n        return ESP_FAIL;\n    }\n\n    size_t total = 0, used = 0;\n    ret = esp_littlefs_info(conf.partition_label, &total, &used);\n    if (ret != ESP_OK) {\n        ESP_LOGE(TAG, \"Failed to get LittleFS partition information (%s)\", esp_err_to_name(ret));\n        esp_littlefs_format(conf.partition_label);\n    } else {\n        ESP_LOGI(TAG, \"Partition size: total: %d, used: %d\", total, used);\n    }\n    return ESP_OK;\n}\n\nstatic bool example_on_color_trans_done(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)\n{\n    SemaphoreHandle_t flush_done_sem = (SemaphoreHandle_t)user_ctx;\n    BaseType_t high_task_wakeup = pdFALSE;\n    xSemaphoreGiveFromISR(flush_done_sem, &high_task_wakeup);\n    return high_task_wakeup == pdTRUE;\n}\n\nvoid app_main(void)\n{\n    // allocate the canvas buffer(s) from PSRAM\n    uint32_t *canvas_buf_argb888 = heap_caps_calloc(EXAMPLE_LOTTIE_SIZE_HOR * EXAMPLE_LOTTIE_SIZE_VER, sizeof(uint32_t), MALLOC_CAP_SPIRAM);\n    uint16_t *canvas_buf_rgb565 = heap_caps_calloc(EXAMPLE_LOTTIE_SIZE_HOR * EXAMPLE_LOTTIE_SIZE_VER, sizeof(uint16_t), MALLOC_CAP_SPIRAM);\n    assert(canvas_buf_argb888 && canvas_buf_rgb565);\n\n    // lottie files are saved in the filesystem, we need to initialize the file system first\n    ESP_ERROR_CHECK(example_init_fs());\n\n    spi_bus_config_t buscfg = {\n        .sclk_io_num = EXAMPLE_PIN_NUM_LCD_PCLK,\n        .data0_io_num = EXAMPLE_PIN_NUM_LCD_DATA0,\n        .data1_io_num = EXAMPLE_PIN_NUM_LCD_DATA1,\n        .data2_io_num = EXAMPLE_PIN_NUM_LCD_DATA2,\n        .data3_io_num = EXAMPLE_PIN_NUM_LCD_DATA3,\n        .max_transfer_sz = EXAMPLE_LOTTIE_SIZE_HOR * EXAMPLE_LOTTIE_SIZE_VER * 3,\n    };\n    ESP_ERROR_CHECK(spi_bus_initialize(EXAMPLE_LCD_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));\n\n    esp_lcd_panel_io_handle_t io_handle = NULL;\n    esp_lcd_panel_io_spi_config_t io_config = {\n        .cs_gpio_num = EXAMPLE_PIN_NUM_LCD_CS,\n        .dc_gpio_num = -1, // no D/C pin for SH8601\n        .spi_mode = 0,\n        .pclk_hz = EXAMPLE_LCD_PCLK_HZ,\n        .trans_queue_depth = 20,\n        .lcd_cmd_bits = 32,  // according to SH8601 spec\n        .lcd_param_bits = 8, // according to SH8601 spec\n        .flags = {\n            .quad_mode = true, // QSPI mode\n        },\n    };\n    ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(EXAMPLE_LCD_SPI_HOST, &io_config, &io_handle));\n\n    esp_lcd_panel_handle_t lcd_panel = NULL;\n    sh8601_vendor_config_t vendor_config = {\n        .init_cmds = lcd_init_cmds,\n        .init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]),\n        .flags = {\n            .use_qspi_interface = 1, // SH8601 support many interfaces, we select QSPI here\n        },\n    };\n    const esp_lcd_panel_dev_config_t panel_config = {\n        .reset_gpio_num = -1,\n        .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,\n        .bits_per_pixel = EXAMPLE_LCD_BIT_PER_PIXEL,\n        .vendor_config = &vendor_config,\n    };\n    ESP_ERROR_CHECK(esp_lcd_new_panel_sh8601(io_handle, &panel_config, &lcd_panel));\n\n    esp_lcd_panel_reset(lcd_panel);\n    esp_lcd_panel_init(lcd_panel);\n    esp_lcd_panel_disp_on_off(lcd_panel, true);\n\n    lottie_render_ctx_t render_ctx = {\n        .lcd_panel = lcd_panel,\n        .canvas_buf_argb888 = canvas_buf_argb888,\n        .canvas_buf_rgb565 = canvas_buf_rgb565,\n        .flush_done_sem = xSemaphoreCreateBinary(),\n    };\n    assert(render_ctx.flush_done_sem);\n\n    esp_lcd_panel_io_callbacks_t cbs = {\n        .on_color_trans_done = example_on_color_trans_done,\n    };\n    // Pass the semaphore as callback user data for frame-complete notification.\n    esp_lcd_panel_io_register_event_callbacks(io_handle, &cbs, render_ctx.flush_done_sem);\n\n    esp_pthread_cfg_t cfg = esp_pthread_get_default_config();\n    cfg.thread_name = \"lottie_render\";\n    cfg.inherit_cfg = false;\n    cfg.stack_size = 30 * 1024;\n    ESP_ERROR_CHECK(esp_pthread_set_cfg(&cfg));\n\n    pthread_t thread;\n    int ret = pthread_create(&thread, NULL, lottie_render_thread, &render_ctx);\n    if (ret != 0) {\n        ESP_LOGE(TAG, \"Failed to create render thread: %d\", ret);\n        abort();\n    }\n    pthread_detach(thread);\n}\n"
  },
  {
    "path": "thorvg/examples/thorvg_lottie/partitions.csv",
    "content": "# Name,   Type, SubType, Offset,  Size, Flags\n# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap\nnvs,      data, nvs,     0x9000,  0x6000,\nphy_init, data, phy,     ,        0x1000,\nfactory,  app,  factory, ,        1M,\nstorage,  data, spiffs,  ,        1M,\n"
  },
  {
    "path": "thorvg/examples/thorvg_lottie/sdkconfig.defaults",
    "content": "# This file was generated using idf.py save-defconfig. It can be edited manually.\n# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration\n#\nCONFIG_ESPTOOLPY_FLASHSIZE_4MB=y\nCONFIG_PARTITION_TABLE_CUSTOM=y\nCONFIG_COMPILER_OPTIMIZATION_PERF=y\n"
  },
  {
    "path": "thorvg/examples/thorvg_lottie/sdkconfig.defaults.esp32p4",
    "content": "CONFIG_IDF_EXPERIMENTAL_FEATURES=y\n\nCONFIG_SPIRAM=y\nCONFIG_SPIRAM_MODE_HEX=y\nCONFIG_SPIRAM_SPEED_200M=y\n"
  },
  {
    "path": "thorvg/examples/thorvg_lottie/sdkconfig.defaults.esp32s3",
    "content": "CONFIG_SPIRAM=y\nCONFIG_SPIRAM_MODE_OCT=y\nCONFIG_SPIRAM_SPEED_80M=y\nCONFIG_SPIRAM_XIP_FROM_PSRAM=y\n\nCONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y\n"
  },
  {
    "path": "thorvg/idf_component.yml",
    "content": "version: \"1.0.1\"\ndescription: \"ThorVG is an open-source graphics library designed for creating vector-based scenes and animations\"\nurl: https://github.com/espressif/idf-extra-components/tree/master/thorvg\nrepository: \"https://github.com/espressif/idf-extra-components.git\"\ndocumentation: \"https://www.thorvg.org/native-apis\"\nissues: \"https://github.com/espressif/idf-extra-components/issues\"\ndependencies:\n  idf: \">=5.1\"\nsbom:\n  manifests:\n    - path: sbom_thorvg.yml\n      dest: thorvg\n"
  },
  {
    "path": "thorvg/project_include.cmake",
    "content": "# ThorVG uses meson as its build system, check if it's installed\nfind_program(MESON_EXECUTABLE meson)\nif(NOT MESON_EXECUTABLE)\n    message(STATUS \"Meson build system not found. Attempting to install it using pip...\")\n\n    # Try to install meson using pip\n    idf_build_get_property(python PYTHON)\n    execute_process(\n        COMMAND ${python} -m pip install -U meson\n        RESULT_VARIABLE result\n        OUTPUT_VARIABLE output\n        ERROR_VARIABLE error\n        OUTPUT_STRIP_TRAILING_WHITESPACE\n        ERROR_STRIP_TRAILING_WHITESPACE\n    )\n\n    if(result)\n        message(FATAL_ERROR \"Failed to install meson using pip. Please install it manually.\\nError: ${error}\")\n    else()\n        message(STATUS \"Meson successfully installed.\")\n    endif()\nelse()\n    message(STATUS \"Meson build system found: ${MESON_EXECUTABLE}\")\nendif()\n"
  },
  {
    "path": "thorvg/sbom_thorvg.yml",
    "content": "name: thorvg\nversion: 1.0.1\ncpe: cpe:2.3:a:thorvg:thorvg:{}:*:*:*:*:*:*:*\nsupplier: 'Organization: thorvg <https://github.com/thorvg/thorvg>'\ndescription: ThorVG is an open-source graphics library designed for creating vector-based scenes and animations.\nurl: https://github.com/thorvg/thorvg\nhash: 6648d791972169d9cd22168f5bd11089bbec56c9\n"
  },
  {
    "path": "touch_element/.build-test-rules.yml",
    "content": "touch_element:\n  disable:\n    - if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR < 3\n      reason: IDF version below v5.3 is not supported\n    - if: IDF_TARGET not in [\"esp32s2\", \"esp32s3\"]\n      reason: only supports esp32s2 and esp32s3\n"
  },
  {
    "path": "touch_element/CHANGELOG.md",
    "content": "## 1.1.2\n\n- Fixed the read stuck issue after deep sleep by resetting the hardware while initializing\n\n## 1.1.1\n\n- Fixed the incorrect interrupt mask\n\n## 1.1.0\n\n- Refactor to remove the dependency on the hal and soc caps in IDF\n- Moved the enums in `touch_pad_intr_mask_t` to ll header, but still keep `touch_pad_intr_mask_t` for backward compatibility\n\n## 1.0.0\n\n- Added test app, examples and documentations for the touch element library\n\n## 0.1.0\n\n- Initial touch element version, based on the legacy Touch Sensor driver\n"
  },
  {
    "path": "touch_element/CMakeLists.txt",
    "content": "idf_build_get_property(target IDF_TARGET)\n\nif(${target} STREQUAL \"linux\")\n    return() # This component is not supported by the POSIX/Linux simulator\nendif()\n\nidf_component_register(SRCS \"touch_element.c\"\n        \"touch_button.c\"\n        \"touch_slider.c\"\n        \"touch_matrix.c\"\n        \"touch_sensor_legacy_hal.c\"\n        INCLUDE_DIRS include\n        PRIV_REQUIRES esp_timer esp_pm esp_driver_gpio)\n"
  },
  {
    "path": "touch_element/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "touch_element/README.md",
    "content": "# Touch Element Library\n\n[![Component Registry](https://components.espressif.com/components/espressif/touch_element/badge.svg)](https://components.espressif.com/components/espressif/touch_element)\n\nThe Touch Element Library is moved from [esp-idf](https://github.com/espressif/esp-idf) to the component registry since v6.0. It can help you design touch applications fast with the common elements like `button`, `slider` and `matrix`. It supports the touch events like `Press`, `Release`, `Long Press` and so on. You can get notified by registering the event callback or subscribe the events in the task.\n\n> **Note**: The touch element library only supports ESP32-S2 and ESP32-S3 with the legacy touch driver. For the new touch driver, please refer to the [Touch Sensor](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/cap_touch_sens.html) documentation.\n\n## Documentation\n\nFor detailed information about the Touch Element Library, including API reference and user guides, please visit:\n\n-   **Programming Guide & API Reference**: [Touch Element Documentation](https://espressif.github.io/idf-extra-components/latest/touch_element/index.html)\n"
  },
  {
    "path": "touch_element/docs/Doxyfile",
    "content": "# Set this to the header file you want\nINPUT = \\\n    ../include/touch_element/\n\n# The output directory for the generated XML documentation\nOUTPUT_DIRECTORY = doxygen_output\n\n# Warning-related settings, it's recommended to keep them enabled\nWARN_IF_UNDOC_ENUM_VAL = YES\nWARN_AS_ERROR = YES\n\n# Other common settings\nFULL_PATH_NAMES = YES\nSTRIP_FROM_PATH = ../\nSTRIP_FROM_INC_PATH = ../\nENABLE_PREPROCESSING   = YES\nMACRO_EXPANSION        = YES\nOPTIMIZE_OUTPUT_FOR_C  = YES\nEXPAND_ONLY_PREDEF     = YES\nEXTRACT_ALL            = YES\nPREDEFINED             = $(ENV_DOXYGEN_DEFINES)\nHAVE_DOT = NO\nGENERATE_XML    = YES\nXML_OUTPUT      = xml\nGENERATE_HTML   = NO\nHAVE_DOT        = NO\nGENERATE_LATEX  = NO\nQUIET = YES\nMARKDOWN_SUPPORT = YES"
  },
  {
    "path": "touch_element/docs/book.toml",
    "content": "[book]\ntitle = \"Touch Element Documentation\"\nlanguage = \"en\"\n\n[output.html]\ndefault-theme = \"light\"\ngit-repository-url = \"https://github.com/espressif/idf-extra-components/tree/master/touch_element\"\nedit-url-template = \"https://github.com/espressif/idf-extra-components/edit/master/touch_element/docs/{path}\"\nmathjax-support = true\n"
  },
  {
    "path": "touch_element/docs/src/SUMMARY.md",
    "content": "# Summary\n\n---\n\n# Programming Guide\n\n- [Touch Element](index.md)\n\n---\n\n# API Reference\n\n- [API Reference](api.md)\n"
  },
  {
    "path": "touch_element/docs/src/api.md",
    "content": "# API Reference\n\n<div class=\"warning\">\n\nThis file is automatically generated by esp-doxybook.\n\nDO NOT edit it manually.\n\n</div>\n"
  },
  {
    "path": "touch_element/docs/src/img/source/te_architecture.drawio",
    "content": "<mxfile host=\"Electron\" modified=\"2021-02-03T06:21:33.748Z\" agent=\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/12.3.2 Chrome/78.0.3904.113 Electron/7.1.2 Safari/537.36\" etag=\"MjaFnCSX-tqnD9erv3wG\" version=\"12.3.2\" type=\"device\" pages=\"1\"><diagram id=\"cdp2F28X_CI_c8RY0vqN\" name=\"第 1 页\">7Vxtc6M2EP41nmk/JIMkEPAxb22v05veNO209ykjg2zTw8gFnDj99ZVA4k3Cdi6AE/dubiYgCwmeXe0+Wq00Qzfr3Y8p2aw+spDGM2iFuxm6nUEIbAhn4r8VPpclHnDLgmUahbJSXXAf/UvLQkcWbqOQZq16OWNxHm3ahQFLEhrkrTKSpuypXW3B4nanG7KkWsF9QGK99M8ozFfyIxyrLv+JRsuV6hlY8pc1UZVlQbYiIXtqFKG7GbpJGcvLq/XuhsYCOwVL+dwPPb9WL5bSJD/mgbvPj27yJVvm948fvqx/fvKu/vrtwpMwP5J4K79Yvm3+rCDgL74RlwFLE5rO0PXTKsrp/YYEovSJi52XrfJ1zO8AvwyjlEsiYgm/T1gqYLgu9AF6lrgUimBjUXMRxfENi1ladIQWC4qDgJdnecq+0MYvoevPLfGwfFua5nTXiwOo0OVaSdma5ukzryIfQPal/GipkUCB8FQL2PWk1FYN4TpKKYlUqmXVeI07v5DQv0QM7mExpGybhFS0Yh2WQRdZL6BmZOeeYzsDIYv9DrJQDYYGskih3UTWVnAPjixQ5qaBJA35EJe3Qj/ZkiUkvqtLr9tY13V+YWwjEf6b5vmzNFdkm7M2/hyx9Pkv8fylB7Aq+MwLLqxLy/JVye1O9lHePTfvPtE04iCIIVcW7qK8bBJxfSnvPxf3vu/L+7o9cfPcuOm2VqIioNgvbY4c26YB3YOxLe0ySZc03ysLZNaflMYkjx7bb2JSBfnoJxbxd2zoHWipHfZgu4nyC+RTTROpNcTFxcG1fOy6NvBRq1kX4ktR6NiyTruT8vO1Tq7SlDw3qm1EhWzPx7jtj3EtuzMIyhbrIVEB+fWjxD4L86OsjUTOdnW7DkzWpyoc3Pro3vV3tg1WvOgupmtayD2O5imRfTUB50DkbVTb6CUsoR2oZRGJo6VwvgHvoHDYAtaIc5or+cM6CsPCzpnE2Bb0EA7X63rcaoA2JWMbPC4czS0gTTIfBFjpdiNksqZZJojh2crE1ny1gwyjBU0qE50E/bOl2zOWggM6MsC6DCYdFqrhpsHirCEVPppt8yg5Y2FABLpmytHFYZoXjDcirNOQV0k01XVJMp29FDMk2aroEwzLLeGx5NL1zdJ9Gbd8KVtDVltlkBzRfQzzQP1x2B000Tsci2GbbUjS0i/8z1YEJMohd5GVY+6KV+Ez+TWJ6wr8ain+3ka8Ul5wGlpxGvpY/C374O9cdlM+sIdZgpczy8UC9oQM8Bw7eBjT4Hsdy1CJseksXTilpdYJzKeUBZy38MJgRZKkiMNlOcl1m/0OEYcmMj8p4rb3/0LchnrwZlrEgeWdxP3VsRvoNEM31Y89UZuxfKDtT+UDXzdA/G9u5nVDsDsns51TD0EHnrnRa+Ht4CpScUKj55/E6Bk5v7uf9DcspfsSQ2kMb49lPR30LqynoxO6b9bzNWPZP/VIdvRp12XxTwP3bGIowOm6MGwIK04a0nJ0VnK9zXOWaFLInqJ1TDSkuZoGAXUWC5MCI4x8FA4DnloEVjMeYFBg37R8MRp2WA8H3sdRKOKBbxs7hA3EaWLsgIbdR5Kn0e7tYYe7SwGm6MaL0ZP9/UaDnCRL/rG1lVDLP3sW6rChOxXzUL2RmNu8hDPPa2HHMk1kA4TOsM5//9iEBdk9B/qrJWzYp3aaWKdB5wS4Fkj0Tz3DwzpLOSvA25bNtMg5LdxYg1uDlSbhlUhdFLwuJlkWBb0BqlZ8qp5o9Uy7qgQiNa2rJmu9U7zZgBOxY8NY2DLLtCE0x0AhVdkrs4mA27WKSGnNS/OJuP51DWw31aQna2gw/3VEYuF7VLeTKYeWy6KlLh6rHHpTFe+aSDlcU8B2QBM/DX1Fls5iXFMYD5kYrOv0q8DrUnqPMPSvyazmalZnVtvCXRaJ1dC3Tb72NInVhhUkY2I19MeSgq7hKgEvaqR7nX1uCwbt1EiMDLTTZDZHDHNrkrmp2GayXc8NQYa3Tzcx9DsW3dVxhgac7dFw1sMQw4WVb7rzg3OJJWtyxMDkUSaVpN+fxbNgBbHQJSl+uMiKNR8hRw7BTpfi1WYTc9NU+JVagmWbPRI8G8OIHM1pmUzjpBFrf+TNQCGh3sI4hHDg0fliGGQdu717AhqSKY1MvfJDwwOr+5y7cg3M4oaMa11azE6zL+/QYjlOz5y1CTfEBns1GvXSPY+O9mKblIT2PSLeNR3Q1U3HxJjrG05+1XnU2VhvbHeU3rBkNqnp9nQLc0+TUIQ0pOr37Sx5+/qOQFffTTYGQMMsezR993Qb8yF55BjwshsSx3MSvEdjrkNtMi3TQu3rJGTKXMzqprEZYU/ssXzXQcLWyo8dDFt7PUKdJn9IbVadVj4D4qxs50Gc/Z7lgYlw1uN65+xiUZdXntrF+noavgrpkeZEtiaZ5yoax4Vdh+wZvIRpx/N40tEDrqaEt3c4fQUGbq+yo5vQdtcKB4yY6uRSxWvC6NEY/5mznQj/RMmyDADNWRrS9IIXHwgDWQELm/G8ooOD4by3K8zu1k5g2Gk7tThNkdkOtGqBaBHTnVyjvT60XPu1CL/dRVcMuuJzMBSnqNg+wq7lebjT5LFLsLbTbbaTYTbyAiyw9GynZqp2OWc8V/+FUPukE9twWpDnTei8wJ7FkmND7MAYYs8FQ3nY7XYPGc0fAjkz/e77Y+PtDWGbRBOwtbACDWVQZ5VB+YY/kHUUC5xviqrQuieJ2MLz8V5WUPMEgwWhIHSoa7IgPnYRGWjOa3fOQoAqXaiVqmXiMqNZaABHVQe5E+NBhoQeUhpQbiTfiVbcgVvnrlcrrkbSCoS9k2vFqTelOtwotoIh8vivrz9PzON+r87QKk4og7MTHigGwLF7tmyz9ox76INrtbNKJzmiCxiOLBpm/fc25UilxxqdF7H9/nyjvgylIXhF22S4agXmUBbSeFQf9O+MHsKRbEgouMU3x9FcGlLL+NWRY0cG0L/CcfDb+hjXcrzXZ+Giu/8A</diagram></mxfile>\n"
  },
  {
    "path": "touch_element/docs/src/index.md",
    "content": "# Touch Element\n\n## Overview\n\nThe Touch Element Library is a highly abstracted element library designed on the basis of the touch sensor driver. The library provides a unified and user-friendly software interface to quickly build capacitive touch sensor applications.\n\n> WARNING: The Touch Element Library is only usable for the ESP32-S2 and ESP32-S3 chips.\n\n> WARNING: The Touch Element Library currently is still based on the legacy touch driver. Please refer to the [new driver of Capacitive Touch Sensor](https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32s3/api-reference/peripherals/cap_touch_sens.html) if you don't need the Touch Element Library.\n\n### Architecture\n\nThe Touch Element library configures touch sensor peripherals via the touch sensor driver. However, some necessary hardware parameters should be passed to [touch_element_install](api.md#function-touch_element_install) and will be configured automatically only after calling [touch_element_start](api.md#function-touch_element_start). This sequential order is essential because configuring these parameters has a significant impact on the run-time system. Therefore, they must be configured after calling the start function to ensure the system functions properly.\n\nThese parameters include touch channel threshold, driver-level of waterproof shield sensor, etc. The Touch Element library sets the touch sensor interrupt and the esp_timer routine up, and the hardware information of the touch sensor (channel state, channel number) will be obtained in the touch sensor interrupt service routine. When the specified channel event occurs, the hardware information is passed to the esp_timer callback routine, which then dispatches the touch sensor channel information to the touch elements (such as button, slider, etc.). The library then runs a specified algorithm to update the touch element's state or calculate its position and dispatches the result accordingly.\n\nSo when using the Touch Element library, you are relieved from the implementation details of the touch sensor peripheral. The library handles most of the hardware information and passes the more meaningful messages to the event handler routine.\n\nThe workflow of the Touch Element library is illustrated in the picture below.\n\n![Touch Element architecture](img/te_architecture.svg)\n\nThe features in relation to the Touch Element library in ESP32-S2 / ESP32-S3 are given in the table below.\n\n| Touch Element waterproof | Touch Element button | Touch Element slider | Touch Element matrix button |\n| :-----------------------: | :------------------: | :------------------: | :-------------------------: |\n| ✔ | ✔ | ✔ | ✔ |\n\n\n### Peripheral\n\nESP32-S2 / ESP32-S3 integrates one touch sensor peripheral with several physical channels.\n\n- 14 physical capacitive touch channels\n- Timer or software FSM trigger mode\n- Up to 5 kinds of interrupt (Upper threshold and lower threshold interrupt, measure one channel finish and measure all channels finish interrupt, measurement timeout interrupt)\n- Sleep mode wakeup source\n- Hardware internal de-noise\n- Hardware filter\n- Hardware waterproof sensor\n- Hardware proximity sensor\n\nThe channels are located as follows:\n\n| Channel | GPIO |\n|:-------:|:----:|\n| CH0 | GPIO0 (internal) |\n| CH1 | GPIO1 |\n| CH2 | GPIO2 |\n| CH3 | GPIO3 |\n| CH4 | GPIO4 |\n| CH5 | GPIO5 |\n| CH6 | GPIO6 |\n| CH7 | GPIO7 |\n| CH8 | GPIO8 |\n| CH9 | GPIO9 |\n| CH10 | GPIO10 |\n| CH11 | GPIO11 |\n| CH12 | GPIO12 |\n| CH13 | GPIO13 |\n| CH14 | GPIO14 |\n\n## Terminology\n\nThe terms used in relation to the Touch Element library are given below.\n\n**Touch sensor**\n- Touch sensor peripheral inside the chip\n\n**Touch channel**\n- Touch sensor channels inside the touch sensor peripheral\n\n**Touch pad**\n- Off-chip physical solder pad, generally inside the PCB\n\n**De-noise channel**\n- Internal de-noise channel, which is always Channel 0 and is reserved\n\n**Shield sensor**\n- One of the waterproof sensors for detecting droplets in small areas and compensating for the influence of water drops on measurements\n\n**Guard sensor**\n- One of the waterproof sensors for detecting extensive wading and to temporarily disable the touch sensor\n\n**Shield channel**\n- The channel that waterproof shield sensor connected to, which is always Channel 14\n\n**Guard channel**\n- The channel that waterproof guard sensor connected to\n\n**Shield pad**\n- Off-chip physical solder pad, generally is grids, and is connected to shield the sensor\n\n**Guard pad**\n- Off-chip physical solder pad, usually a ring, and is connected to the guard sensor\n\n![Touch sensor application system components](img/te_component.svg)\n\n### Touch Sensor Signal\n\nEach touch sensor is able to provide the following types of signals:\n\n- Raw: The Raw signal is the unfiltered signal from the touch sensor.\n- Smooth: The Smooth signal is a filtered version of the Raw signal via an internal hardware filter.\n- Benchmark: The Benchmark signal is also a filtered signal that filters out extremely low-frequency noise.\n\nAll of these signals can be obtained using touch sensor driver API.\n\n![Touch sensor signals](img/te_signal.png)\n\n### Touch Sensor Signal Threshold\n\nThe Touch Sensor Threshold value is a configurable threshold value used to determine when a touch sensor is touched or not. When the difference between the Smooth signal and the Benchmark signal becomes greater than the threshold value (i.e., ``(smooth - benchmark) > threshold``), the touch channel's state will be changed and a touch interrupt will be triggered simultaneously.\n\n![Touch sensor signal threshold](img/te_threshold.svg)\n\n### Sensitivity\n\nImportant performance parameter of the touch sensor, the larger it is, the better touch the sensor performs. It could be calculated by the format below:\n\n$$\nSensitivity = \\frac{Signal_{press} - Signal_{release}}{Signal_{release}} = \\frac{Signal_{delta}}{Signal_{benchmark}}\n$$\n\n### Waterproof\n\nWaterproof is the hardware feature of a touch sensor which has a guard sensor and shield sensor (always connect to Channel 14) that has the ability to resist a degree of influence of water drop and detect the water stream.\n\n\n### Touch Button\n\nThe touch button consumes one channel of the touch sensor, and it looks like as the picture below:\n\n\n![Touch button](img/te_button.svg)\n\n### Touch Slider\n\nThe touch slider consumes several channels (at least three channels) of the touch sensor, the more channels consumed, the higher resolution and accuracy position it performs. The touch slider looks like as the picture below:\n\n![Touch slider](img/te_slider.svg)\n\n### Touch Matrix\n\nThe touch matrix button consumes several channels (at least 2 + 2 = 4 channels), and it gives a solution to use fewer channels and get more buttons. ESP32-S2 / ESP32-S3 supports up to 49 buttons. The touch matrix button looks like as the picture below:\n\n![Touch matrix](img/te_matrix.svg)\n\n## Touch Element Library Usage\n\nUsing this library should follow the initialization flow below:\n\n1. To initialize the Touch Element library by calling [touch_element_install](api.md#function-touch_element_install).\n2. To initialize touch elements (button/slider etc) by calling [touch_button_install](api.md#function-touch_button_install), [touch_slider_install](api.md#function-touch_slider_install) or [touch_matrix_install](api.md#function-touch_matrix_install).\n3. To create a new element instance by calling [touch_button_create](api.md#function-touch_button_create), [touch_slider_create](api.md#function-touch_slider_create) or [touch_matrix_create](api.md#function-touch_matrix_create).\n4. To subscribe events by calling [touch_button_subscribe_event](api.md#function-touch_button_subscribe_event), [touch_slider_subscribe_event](api.md#function-touch_slider_subscribe_event) or [touch_matrix_subscribe_event](api.md#function-touch_matrix_subscribe_event).\n5. To choose a dispatch method by calling [touch_button_set_dispatch_method](api.md#function-touch_button_set_dispatch_method), [touch_slider_set_dispatch_method](api.md#function-touch_slider_set_dispatch_method) or [touch_matrix_set_dispatch_method](api.md#function-touch_matrix_set_dispatch_method) that tells the library how to notify you while the subscribed event occurs.\n6. If dispatch by callback, call [touch_button_set_callback](api.md#function-touch_button_set_callback), [touch_slider_set_callback](api.md#function-touch_slider_set_callback) or [touch_matrix_set_callback](api.md#function-touch_matrix_set_callback) to set the event handler function.\n7. To start the Touch Element library by calling [touch_element_start](api.md#function-touch_element_start).\n8. If dispatch by callback, the callback will be called by the driver core when an event happens, no need to do anything; If dispatch by event task, create an event task and call [touch_element_message_receive](api.md#function-touch_element_message_receive) to obtain messages in a loop.\n9. (Optional) If you want to suspend the Touch Element run-time system or for some reason that could not obtain the touch element message, [touch_element_stop](api.md#function-touch_element_stop) should be called to suspend the Touch Element system and then resume it by calling [touch_element_start](api.md#function-touch_element_start) again.\n\nIn code, the flow above may look like as follows:\n\n```c\n\n    static touch_button_handle_t element_handle; //Declare a touch element handle\n\n    //Define the subscribed event handler\n    void event_handler(touch_button_handle_t out_handle, touch_button_message_t out_message, void *arg)\n    {\n        //Event handler logic\n    }\n\n    void app_main()\n    {\n        //Using the default initializer to config Touch Element library\n        touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();\n        touch_element_install(&global_config);\n\n        //Using the default initializer to config Touch elements\n        touch_slider_global_config_t elem_global_config = TOUCH_SLIDER_GLOBAL_DEFAULT_CONFIG();\n        touch_slider_install(&elem_global_config);\n\n        //Create a new instance\n        touch_slider_config_t element_config = {\n            ...\n            ...\n        };\n        touch_button_create(&element_config, &element_handle);\n\n        //Subscribe the specified events by using the event mask\n        touch_button_subscribe_event(element_handle, TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE, NULL);\n\n        //Choose CALLBACK as the dispatch method\n        touch_button_set_dispatch_method(element_handle, TOUCH_ELEM_DISP_CALLBACK);\n\n        //Register the callback routine\n        touch_button_set_callback(element_handle, event_handler);\n\n        //Start Touch Element library processing\n        touch_element_start();\n    }\n```\n\n\n### Initialization\n\n1. To initialize the Touch Element library, you have to configure the touch sensor peripheral and Touch Element library by calling [touch_element_install](api.md#function-touch_element_install) with [touch_elem_global_config_t](api.md#struct-touch_elem_global_config_t), the default initializer is available in [TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG](api.md#define-touch_elem_global_default_config) and this default configuration is suitable for the most general application scene, and it is suggested not to change the default configuration before fully understanding Touch Sensor peripheral because some changes might bring several impacts to the system.\n\n2. To initialize the specified element, all the elements will not work before its constructor [touch_button_install](api.md#function-touch_button_install), [touch_slider_install](api.md#function-touch_slider_install) or [touch_matrix_install](api.md#function-touch_matrix_install) is called so as to save memory, so you have to call the constructor of each used touch element respectively, to set up the specified element.\n\n\n### Touch Element Instance Startup\n\n1. To create a new touch element instance, call [touch_button_create](api.md#function-touch_button_create), [touch_slider_create](api.md#function-touch_slider_create) or [touch_matrix_create](api.md#function-touch_matrix_create), select a channel, and provide its `Sensitivity`_ value for the new element instance.\n\n2. To subscribe to events, call [touch_button_subscribe_event](api.md#function-touch_button_subscribe_event), [touch_slider_subscribe_event](api.md#function-touch_slider_subscribe_event) or [touch_matrix_subscribe_event](api.md#function-touch_matrix_subscribe_event). The Touch Element library offers several events, and the event mask is available in [touch_element.h](https://github.com/espressif/idf-extra-components/tree/master/touch_element/include/touch_element/touch_element.h). You can use these event masks to subscribe to specific events individually or combine them to subscribe to multiple events.\n\n3. To configure the dispatch method, use [touch_button_set_dispatch_method](api.md#function-touch_button_set_dispatch_method), [touch_slider_set_dispatch_method](api.md#function-touch_slider_set_dispatch_method) or [touch_matrix_set_dispatch_method](api.md#function-touch_matrix_set_dispatch_method). The Touch Element library provides two dispatch methods defined in [touch_elem_dispatch_t](api.md#enum-touch_elem_dispatch_t): `TOUCH_ELEM_DISP_EVENT` and `TOUCH_ELEM_DISP_CALLBACK`. These methods allow you to obtain the touch element message and handle it using different approaches.\n\n### Events Processing\n\nIf `TOUCH_ELEM_DISP_EVENT` dispatch method is configured, you need to start up an event handler task to obtain the touch element message, all the elements' raw message could be obtained by calling [touch_element_message_receive](api.md#function-touch_element_message_receive), then extract the element-class-specific message by calling the corresponding message decoder with [touch_button_get_message](api.md#function-touch_button_set_callback), [touch_slider_get_message](api.md#function-touch_slider_get_message) to get the touch element's extracted message; If `TOUCH_ELEM_DISP_CALLBACK` dispatch method is configured, you need to pass an event handler by calling [touch_slider_set_callback](api.md#function-touch_slider_set_callback) or [touch_matrix_get_message](api.md#function-touch_matrix_get_message) to get the touch element's extracted message; If `TOUCH_ELEM_DISP_CALLBACK` dispatch method is configured, you need to pass an event handler by calling [touch_matrix_set_callback](api.md#function-touch_matrix_set_callback) before the touch element starts working, all the element's extracted message will be passed to the event handler function.\n\n> WARNING: Since the event handler function runs on the core of the element library, i.e., in the esp_timer callback routine, please avoid performing operations that may cause blocking or delays, such as calling `vTaskDelay`.\n\nIn code, the events handle procedure may look like as follows:\n\n```c\n\n    /* ---------------------------------------------- TOUCH_ELEM_DISP_EVENT ----------------------------------------------- */\n    void element_handler_task(void *arg)\n    {\n        touch_elem_message_t element_message;\n        while(1) {\n            if (touch_element_message_receive(&element_message, Timeout) == ESP_OK) {\n                const touch_matrix_message_t *extracted_message = touch_matrix_get_message(&element_message); //Decode message\n                ... //Event handler logic\n            }\n        }\n    }\n    void app_main()\n    {\n        ...\n\n        touch_matrix_set_dispatch_method(element_handle, TOUCH_ELEM_DISP_EVENT);  //Set TOUCH_ELEM_DISP_EVENT as the dispatch method\n        xTaskCreate(&element_handler_task, \"element_handler_task\", 2048, NULL, 5, NULL);  //Create a handler task\n\n        ...\n    }\n    /* -------------------------------------------------------------------------------------------------------------- */\n\n    ...\n    /* ---------------------------------------------- TOUCH_ELEM_DISP_CALLBACK ----------------------------------------------- */\n    void element_handler(touch_matrix_handle_t out_handle, touch_matrix_message_t out_message, void *arg)\n    {\n        //Event handler logic\n    }\n\n    void app_main()\n    {\n        ...\n\n        touch_matrix_set_dispatch_method(element_handle, TOUCH_ELEM_DISP_CALLBACK);  //Set TOUCH_ELEM_DISP_CALLBACK as the dispatch method\n        touch_matrix_set_callback(element_handle, element_handler);  //Register an event handler function\n\n        ...\n    }\n    /* -------------------------------------------------------------------------------------------------------------- */\n```\n\n\n### Waterproof Usage\n\n1. The waterproof shield sensor is always-on after Touch Element waterproof is initialized, however, the waterproof guard sensor is optional, hence if the you do not need the guard sensor, ``TOUCH_WATERPROOF_GUARD_NOUSE`` has to be passed to [touch_element_waterproof_install](api.md#function-touch_element_waterproof_install) by the configuration struct.\n\n2. To associate the touch element with the guard sensor, pass the touch element's handle to the Touch Element waterproof's masked list by calling [touch_element_waterproof_add](api.md#function-touch_element_waterproof_add). By associating a touch element with the Guard sensor, the touch element will be disabled when the guard sensor is triggered by a stream of water so as to protect the touch element.\n\nThe Touch Element Waterproof example is available under the `examples/touch_element_waterproof` directory.\n\nIn code, the waterproof configuration may look as follows:\n\n```c\n\n    void app_main()\n    {\n        ...\n\n        touch_button_install();                 //Initialize instance (button, slider, etc)\n        touch_button_create(&element_handle);   //Create a new Touch element\n\n        ...\n\n        touch_element_waterproof_install();              //Initialize Touch Element waterproof\n        touch_element_waterproof_add(element_handle);   //Let an element associate with the guard sensor\n\n        ...\n    }\n```\n\n### Wakeup from Light/Deep-sleep Mode\n\nOnly Touch Button can be configured as a wake-up source.\n\nLight- or Deep-sleep modes are both supported to be wakened up by a touch sensor. For the Light-sleep mode, any installed touch button can wake it up. But only the sleep button can wake up from Deep-sleep mode, and the touch sensor will do a calibration immediately, the reference value will be calibrated to a wrong value if our finger does not remove timely. Though the wrong reference value recovers after the finger removes away and has no effect on the driver logic, if you do not want to see a wrong reference value while waking up from Deep-sleep mode, you can call [touch_element_sleep_enable_wakeup_calibration](api.md#function-touch_element_sleep_enable_wakeup_calibration) to disable the wakeup calibration.\n\n```c\n\n    void app_main()\n    {\n        ...\n        touch_element_install();\n        touch_button_install();                 //Initialize the touch button\n        touch_button_create(&element_handle);  //Create a new Touch element\n\n        ...\n\n        // ESP_ERROR_CHECK(touch_element_enable_light_sleep(&sleep_config));\n        ESP_ERROR_CHECK(touch_element_enable_deep_sleep(button_handle[0], &sleep_config));\n        // ESP_ERROR_CHECK(touch_element_sleep_enable_wakeup_calibration(button_handle[0], false)); // (optional) Disable wakeup calibration to prevent updating the benchmark to a wrong value\n\n        touch_element_start();\n\n        ...\n    }\n```\n"
  },
  {
    "path": "touch_element/examples/touch_button/CMakeLists.txt",
    "content": "# The following lines of boilerplate have to be in your project's CMakeLists\n# in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\n# \"Trim\" the build. Include the minimal set of components, main, and anything it depends on.\nidf_build_set_property(MINIMAL_BUILD ON)\nproject(touch_button)\n"
  },
  {
    "path": "touch_element/examples/touch_button/README.md",
    "content": "# Touch button example\n\n(See the README.md file in the upper level 'examples' directory for more information about examples.)\n\nThis example demonstrates how to use the Touch Element library of capacitive touch sensor and set up touch button.\n\n## How to use example\n\n### Hardware Required\n\n* A development board with ESP32-S2 or ESP32-S3 chip\n* A touch extension board like [esp32-s2-touch-devkit-1](https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32s2/esp32-s2-touch-devkit-1/user_guide.html)\n\n### Configure the project\n\n* Set the target of the build by following command, where TARGET can be `esp32s2` or `esp32s3`.\n```\nidf.py set-target TARGET\n```\n* Run `idf.py menuconfig` to select a dispatch method for the example.\n\n### Build and Flash\n\nBuild the project and flash it to the board, then run monitor tool to view serial output:\n\n```\nidf.py -p PORT flash monitor\n```\n\n(Replace PORT with the name of the serial port to use.)\n\n(To exit the serial monitor, type ``Ctrl-]``.)\n\nSee the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.\n\n## Example Output\n\n```\nI (331) Touch Button Example: Touch element library installed\nI (331) Touch Button Example: Touch button installed\nI (341) Touch Button Example: Touch buttons created\nI (341) Touch Button Example: Touch element library start\nI (1481) Touch Button Example: Button[1] Press\nI (1701) Touch Button Example: Button[1] Release\nI (2731) Touch Button Example: Button[2] Press\nI (2921) Touch Button Example: Button[2] Release\nI (3581) Touch Button Example: Button[5] Press\nI (3781) Touch Button Example: Button[5] Release\nI (3931) Touch Button Example: Button[4] Press\nI (4121) Touch Button Example: Button[4] Release\nI (4271) Touch Button Example: Button[3] Press\nI (4491) Touch Button Example: Button[3] Release\nI (4671) Touch Button Example: Button[6] Press\nI (4891) Touch Button Example: Button[6] Release\nI (5091) Touch Button Example: Button[7] Press\nI (5311) Touch Button Example: Button[7] Release\nI (5491) Touch Button Example: Button[8] Press\nI (5741) Touch Button Example: Button[8] Release\nI (5991) Touch Button Example: Button[9] Press\nI (7991) Touch Button Example: Button[9] LongPress\nI (9991) Touch Button Example: Button[9] LongPress\nI (11991) Touch Button Example: Button[9] LongPress\nI (12881) Touch Button Example: Button[9] Release\n```\n\n## Troubleshooting\n\nFor any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.\n"
  },
  {
    "path": "touch_element/examples/touch_button/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"touch_button_example_main.c\"\n                    INCLUDE_DIRS \".\")\n"
  },
  {
    "path": "touch_element/examples/touch_button/main/Kconfig.projbuild",
    "content": "menu \"Example Configuration\"\n\n    choice TOUCH_SENSOR_EXAMPLE_TYPE\n        bool \"Select touch element dispatch method\"\n        default TOUCH_ELEM_EVENT\n        help\n            Select touch element dispatch method (event task or callback) for this example.\n\n        config TOUCH_ELEM_EVENT\n            bool \"Dispatch by event task\"\n        config TOUCH_ELEM_CALLBACK\n            bool \"Dispatch by callback\"\n    endchoice\n\nendmenu\n"
  },
  {
    "path": "touch_element/examples/touch_button/main/idf_component.yml",
    "content": "dependencies:\n  espressif/touch_element:\n    version: '*'\n    override_path: '../../../'\n"
  },
  {
    "path": "touch_element/examples/touch_button/main/touch_button_example_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"touch_element/touch_button.h\"\n#include \"esp_log.h\"\n\nstatic const char *TAG = \"Touch Button Example\";\n#define TOUCH_BUTTON_NUM     14\n\n/* Touch buttons handle */\nstatic touch_button_handle_t button_handle[TOUCH_BUTTON_NUM];\n\n/* Touch buttons channel array */\nstatic const touch_pad_t channel_array[TOUCH_BUTTON_NUM] = {\n    TOUCH_PAD_NUM1,\n    TOUCH_PAD_NUM2,\n    TOUCH_PAD_NUM3,\n    TOUCH_PAD_NUM4,\n    TOUCH_PAD_NUM5,\n    TOUCH_PAD_NUM6,\n    TOUCH_PAD_NUM7,\n    TOUCH_PAD_NUM8,\n    TOUCH_PAD_NUM9,\n    TOUCH_PAD_NUM10,\n    TOUCH_PAD_NUM11,\n    TOUCH_PAD_NUM12,\n    TOUCH_PAD_NUM13,\n    TOUCH_PAD_NUM14,\n};\n\n/* Touch buttons channel sensitivity array */\nstatic const float channel_sens_array[TOUCH_BUTTON_NUM] = {\n    0.1F,\n    0.1F,\n    0.1F,\n    0.1F,\n    0.1F,\n    0.1F,\n    0.1F,\n    0.1F,\n    0.1F,\n    0.1F,\n    0.1F,\n    0.1F,\n    0.1F,\n    0.1F,\n};\n\n#ifdef CONFIG_TOUCH_ELEM_EVENT\n/* Button event handler task */\nstatic void button_handler_task(void *arg)\n{\n    (void) arg; //Unused\n    touch_elem_message_t element_message;\n    while (1) {\n        /* Waiting for touch element messages */\n        touch_element_message_receive(&element_message, portMAX_DELAY);\n        if (element_message.element_type != TOUCH_ELEM_TYPE_BUTTON) {\n            continue;\n        }\n        /* Decode message */\n        const touch_button_message_t *button_message = touch_button_get_message(&element_message);\n        if (button_message->event == TOUCH_BUTTON_EVT_ON_PRESS) {\n            ESP_LOGI(TAG, \"Button[%d] Press\", (int)element_message.arg);\n        } else if (button_message->event == TOUCH_BUTTON_EVT_ON_RELEASE) {\n            ESP_LOGI(TAG, \"Button[%d] Release\", (int)element_message.arg);\n        } else if (button_message->event == TOUCH_BUTTON_EVT_ON_LONGPRESS) {\n            ESP_LOGI(TAG, \"Button[%d] LongPress\", (int)element_message.arg);\n        }\n    }\n}\n#elif CONFIG_TOUCH_ELEM_CALLBACK\n/* Button callback routine */\nstatic void button_handler(touch_button_handle_t out_handle, touch_button_message_t *out_message, void *arg)\n{\n    (void) out_handle; //Unused\n    if (out_message->event == TOUCH_BUTTON_EVT_ON_PRESS) {\n        ESP_LOGI(TAG, \"Button[%d] Press\", (int)arg);\n    } else if (out_message->event == TOUCH_BUTTON_EVT_ON_RELEASE) {\n        ESP_LOGI(TAG, \"Button[%d] Release\", (int)arg);\n    } else if (out_message->event == TOUCH_BUTTON_EVT_ON_LONGPRESS) {\n        ESP_LOGI(TAG, \"Button[%d] LongPress\", (int)arg);\n    }\n}\n#endif\n\nvoid app_main(void)\n{\n    /* Initialize Touch Element library */\n    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();\n    ESP_ERROR_CHECK(touch_element_install(&global_config));\n    ESP_LOGI(TAG, \"Touch element library installed\");\n\n    touch_button_global_config_t button_global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();\n    ESP_ERROR_CHECK(touch_button_install(&button_global_config));\n    ESP_LOGI(TAG, \"Touch button installed\");\n    for (int i = 0; i < TOUCH_BUTTON_NUM; i++) {\n        touch_button_config_t button_config = {\n            .channel_num = channel_array[i],\n            .channel_sens = channel_sens_array[i]\n        };\n        /* Create Touch buttons */\n        ESP_ERROR_CHECK(touch_button_create(&button_config, &button_handle[i]));\n        /* Subscribe touch button events (On Press, On Release, On LongPress) */\n        ESP_ERROR_CHECK(touch_button_subscribe_event(button_handle[i],\n                        TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE | TOUCH_ELEM_EVENT_ON_LONGPRESS,\n                        (void *)channel_array[i]));\n#ifdef CONFIG_TOUCH_ELEM_EVENT\n        /* Set EVENT as the dispatch method */\n        ESP_ERROR_CHECK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_EVENT));\n#elif CONFIG_TOUCH_ELEM_CALLBACK\n        /* Set EVENT as the dispatch method */\n        ESP_ERROR_CHECK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_CALLBACK));\n        /* Register a handler function to handle event messages */\n        ESP_ERROR_CHECK(touch_button_set_callback(button_handle[i], button_handler));\n#endif\n        /* Set LongPress event trigger threshold time */\n        ESP_ERROR_CHECK(touch_button_set_longpress(button_handle[i], 2000));\n    }\n    ESP_LOGI(TAG, \"Touch buttons created\");\n\n#ifdef CONFIG_TOUCH_ELEM_EVENT\n    /* Create a handler task to handle event messages */\n    xTaskCreate(&button_handler_task, \"button_handler_task\", 4 * 1024, NULL, 5, NULL);\n#endif\n\n    touch_element_start();\n    ESP_LOGI(TAG, \"Touch element library start\");\n}\n"
  },
  {
    "path": "touch_element/examples/touch_button/pytest_touch_button.py",
    "content": "# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nfrom pathlib import Path\nimport glob\n\n\n@pytest.mark.generic\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that not build\"\n)\ndef test_touch_button(dut: Dut) -> None:\n    dut.expect_exact('Touch Button Example: Touch element library installed')\n    dut.expect_exact('Touch Button Example: Touch button installed')\n    dut.expect_exact('Touch Button Example: Touch buttons created')\n    dut.expect_exact('Touch Button Example: Touch element library start')\n"
  },
  {
    "path": "touch_element/examples/touch_element_waterproof/CMakeLists.txt",
    "content": "# The following lines of boilerplate have to be in your project's CMakeLists\n# in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\n# \"Trim\" the build. Include the minimal set of components, main, and anything it depends on.\nidf_build_set_property(MINIMAL_BUILD ON)\nproject(touch_element_waterproof)\n"
  },
  {
    "path": "touch_element/examples/touch_element_waterproof/README.md",
    "content": "# Touch Element waterproof Example\n\n(See the README.md file in the upper level 'examples' directory for more information about examples.)\n\nThis example demonstrates how to use the Touch Element library of capacitive Touch Sensor and setup the touch elements with touch element waterproof protection.\n\n## How to use example\n\n### Hardware Required\n\n* A development board with ESP32-S2 or ESP32-S3 chip\n* A touch extension board like [esp32-s2-touch-devkit-1](https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32s2/esp32-s2-touch-devkit-1/user_guide.html)\n\n### Configure the project\n\n* Set the target of the build by following command, where TARGET can be `esp32s2` or `esp32s3`.\n```\nidf.py set-target TARGET\n```\n* Run `idf.py menuconfig` to select weather to enable waterproof function.\n\n### Build and Flash\n\nBuild the project and flash it to the board, then run monitor tool to view serial output:\n\n```\nidf.py -p PORT flash monitor\n```\n\n(Replace PORT with the name of the serial port to use.)\n\n(To exit the serial monitor, type ``Ctrl-]``.)\n\nSee the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.\n\n## Example Output\n\nThis example's output maybe could not give a strong feeling to user since the waterproof function works\nautomatically and silently inside the Touch Element library\n\n```\nI (331) Touch Element Waterproof Example: Touch Element library install\nI (331) Touch Element Waterproof Example: Touch Element waterproof install\nI (341) Touch Element Waterproof Example: Touch button install\nI (351) Touch Element Waterproof Example: Touch buttons create\nI (3191) Touch Element Waterproof Example: Button[7] Press\nI (4191) Touch Element Waterproof Example: Button[7] LongPress\nI (5191) Touch Element Waterproof Example: Button[7] LongPress\nI (5671) Touch Element Waterproof Example: Button[7] Release\nI (12561) Touch Element Waterproof Example: Button[9] Press\nI (12811) Touch Element Waterproof Example: Button[9] Release\n```\n\n## Troubleshooting\n\nFor any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.\n"
  },
  {
    "path": "touch_element/examples/touch_element_waterproof/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"waterproof_example_main.c\"\n                    INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES touch_element)\n"
  },
  {
    "path": "touch_element/examples/touch_element_waterproof/main/Kconfig.projbuild",
    "content": "menu \"Example Configuration\"\n\n    config TOUCH_WATERPROOF_GUARD_ENABLE\n        bool \"Enable touch sense waterproof guard sensor\"\n        default y\n        help\n                This option enables touch sense waterproof guard sensor,\n                while the shield sensor is not optional.\n\nendmenu\n"
  },
  {
    "path": "touch_element/examples/touch_element_waterproof/main/idf_component.yml",
    "content": "dependencies:\n  espressif/touch_element:\n    version: '*'\n    override_path: '../../../'\n"
  },
  {
    "path": "touch_element/examples/touch_element_waterproof/main/waterproof_example_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"esp_log.h\"\n#include \"touch_element/touch_button.h\"\n\nstatic const char *TAG = \"Touch Element Waterproof Example\";\n#define TOUCH_BUTTON_NUM     3\n\n/*< Touch buttons handle */\nstatic touch_button_handle_t button_handle[TOUCH_BUTTON_NUM]; //Button handler\n\n/* Touch buttons channel array */\nstatic const touch_pad_t channel_array[TOUCH_BUTTON_NUM] = {\n    TOUCH_PAD_NUM7,\n    TOUCH_PAD_NUM9,\n    TOUCH_PAD_NUM11,\n};\n\n/* Touch buttons channel sensitivity array */\nstatic const float channel_sens_array[TOUCH_BUTTON_NUM] = {\n    0.15F,\n    0.15F,\n    0.15F,\n};\n\nstatic void button_handler_task(void *arg)\n{\n    touch_elem_message_t element_message;\n    while (1) {\n        touch_element_message_receive(&element_message, portMAX_DELAY); //Block take\n        const touch_button_message_t *button_message = touch_button_get_message(&element_message);\n        if (button_message->event == TOUCH_BUTTON_EVT_ON_PRESS) {\n            ESP_LOGI(TAG, \"Button[%d] Press\", (int)element_message.arg);\n        } else if (button_message->event == TOUCH_BUTTON_EVT_ON_RELEASE) {\n            ESP_LOGI(TAG, \"Button[%d] Release\", (int)element_message.arg);\n        } else if (button_message->event == TOUCH_BUTTON_EVT_ON_LONGPRESS) {\n            ESP_LOGI(TAG, \"Button[%d] LongPress\", (int)element_message.arg);\n        }\n    }\n}\n\nvoid app_main(void)\n{\n    /*< Initialize Touch Element library */\n    touch_elem_global_config_t element_global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();\n    ESP_ERROR_CHECK(touch_element_install(&element_global_config));\n    ESP_LOGI(TAG, \"Touch Element library install\");\n    /*< Create and configure touch element waterproof */\n    touch_elem_waterproof_config_t waterproof_config = {\n#ifdef CONFIG_TOUCH_WATERPROOF_GUARD_ENABLE\n        .guard_channel = TOUCH_PAD_NUM13,\n#else\n        .guard_channel = TOUCH_WATERPROOF_GUARD_NOUSE,\n#endif\n        .guard_sensitivity = 0.05F  //The guard sensor sensitivity has to be explored in experiments\n    };\n    ESP_ERROR_CHECK(touch_element_waterproof_install(&waterproof_config));\n    ESP_LOGI(TAG, \"Touch Element waterproof install\");\n\n    touch_button_global_config_t button_global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();\n    ESP_ERROR_CHECK(touch_button_install(&button_global_config));\n    ESP_LOGI(TAG, \"Touch button install\");\n    for (int i = 0; i < TOUCH_BUTTON_NUM; i++) {\n        touch_button_config_t button_config = {\n            .channel_num = channel_array[i],\n            .channel_sens = channel_sens_array[i]\n        };\n        /* Create touch button */\n        ESP_ERROR_CHECK(touch_button_create(&button_config, &button_handle[i]));\n        /* Subscribe touch button event(Press, Release, LongPress) */\n        ESP_ERROR_CHECK(touch_button_subscribe_event(button_handle[i],\n                        TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE | TOUCH_ELEM_EVENT_ON_LONGPRESS,\n                        (void *)channel_array[i]));\n        /* Button set dispatch method */\n        ESP_ERROR_CHECK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_EVENT));\n#ifdef CONFIG_TOUCH_WATERPROOF_GUARD_ENABLE\n        /* Add button element into waterproof guard sensor's protection */\n        ESP_ERROR_CHECK(touch_element_waterproof_add(button_handle[i]));\n#endif\n    }\n    ESP_LOGI(TAG, \"Touch buttons create\");\n    /*< Create a monitor task to take Touch Button event */\n    xTaskCreate(&button_handler_task, \"button_handler_task\", 4 * 1024, NULL, 5, NULL);\n    touch_element_start();\n}\n"
  },
  {
    "path": "touch_element/examples/touch_element_waterproof/pytest_touch_element_waterproof.py",
    "content": "# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nfrom pathlib import Path\nimport glob\n\n\n@pytest.mark.generic\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that not build\"\n)\ndef test_touch_element_waterproof(dut: Dut) -> None:\n    dut.expect_exact('Touch Element Waterproof Example: Touch Element library install')\n    dut.expect_exact('Touch Element Waterproof Example: Touch Element waterproof install')\n    dut.expect_exact('Touch Element Waterproof Example: Touch button install')\n    dut.expect_exact('Touch Element Waterproof Example: Touch buttons create')\n"
  },
  {
    "path": "touch_element/examples/touch_elements_combination/CMakeLists.txt",
    "content": "# The following lines of boilerplate have to be in your project's CMakeLists\n# in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\n# \"Trim\" the build. Include the minimal set of components, main, and anything it depends on.\nidf_build_set_property(MINIMAL_BUILD ON)\nproject(touch_elements_combination)\n"
  },
  {
    "path": "touch_element/examples/touch_elements_combination/README.md",
    "content": "# Touch button example\n\n(See the README.md file in the upper level 'examples' directory for more information about examples.)\n\nThis example demonstrates how to use the Touch Element library of capacitive touch sensor and set up more than one type of touch elements and handle all the event messages in one task.\n\n## How to use example\n\n### Hardware Required\n\n* A development board with ESP32-S2 or ESP32-S3 chip\n* A touch extension board like [esp32-s2-touch-devkit-1](https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32s2/esp32-s2-touch-devkit-1/user_guide.html)\n\n### Configure the project\n\n* Set the target of the build by following command, where TARGET can be `esp32s2` or `esp32s3`.\n```\nidf.py set-target TARGET\n```\n\n### Build and Flash\n\nBuild the project and flash it to the board, then run monitor tool to view serial output:\n\n```\nidf.py -p PORT flash monitor\n```\n\n(Replace PORT with the name of the serial port to use.)\n\n(To exit the serial monitor, type ``Ctrl-]``.)\n\nSee the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.\n\n## Example Output\n\n```\nI (331) Touch Elements Combination Example: Touch element library installed\nI (331) Touch Elements Combination Example: Touch button installed\nI (341) Touch Elements Combination Example: Touch buttons created\nI (351) Touch Elements Combination Example: Touch slider installed\nI (351) Touch Elements Combination Example: Touch slider created\nI (361) Touch Elements Combination Example: Touch element library start\nI (1841) Touch Elements Combination Example: Button[6] Press\nI (1971) Touch Elements Combination Example: Button[6] Release\nI (2201) Touch Elements Combination Example: Button[8] Press\nI (2351) Touch Elements Combination Example: Button[8] Release\nI (2561) Touch Elements Combination Example: Button[10] Press\nI (2721) Touch Elements Combination Example: Button[10] Release\nI (3431) Touch Elements Combination Example: Slider Press, position: 0\nI (3441) Touch Elements Combination Example: Slider Calculate, position: 0\nI (3451) Touch Elements Combination Example: Slider Calculate, position: 0\nI (3461) Touch Elements Combination Example: Slider Calculate, position: 0\nI (3471) Touch Elements Combination Example: Slider Calculate, position: 0\nI (3481) Touch Elements Combination Example: Slider Calculate, position: 0\nI (3491) Touch Elements Combination Example: Slider Calculate, position: 0\nI (3501) Touch Elements Combination Example: Slider Calculate, position: 1\nI (3511) Touch Elements Combination Example: Slider Calculate, position: 1\nI (3521) Touch Elements Combination Example: Slider Calculate, position: 2\nI (3531) Touch Elements Combination Example: Slider Calculate, position: 2\nI (3541) Touch Elements Combination Example: Slider Calculate, position: 3\nI (3551) Touch Elements Combination Example: Slider Calculate, position: 4\nI (3561) Touch Elements Combination Example: Slider Calculate, position: 5\nI (3571) Touch Elements Combination Example: Slider Calculate, position: 6\nI (3581) Touch Elements Combination Example: Slider Calculate, position: 7\nI (3591) Touch Elements Combination Example: Slider Calculate, position: 8\nI (3601) Touch Elements Combination Example: Slider Calculate, position: 10\nI (3611) Touch Elements Combination Example: Slider Calculate, position: 11\nI (3621) Touch Elements Combination Example: Slider Calculate, position: 12\nI (3631) Touch Elements Combination Example: Slider Calculate, position: 13\nI (3641) Touch Elements Combination Example: Slider Calculate, position: 15\nI (3651) Touch Elements Combination Example: Slider Calculate, position: 16\nI (3661) Touch Elements Combination Example: Slider Calculate, position: 17\nI (3671) Touch Elements Combination Example: Slider Calculate, position: 19\nI (3681) Touch Elements Combination Example: Slider Calculate, position: 20\nI (3691) Touch Elements Combination Example: Slider Calculate, position: 21\nI (3701) Touch Elements Combination Example: Slider Calculate, position: 23\nI (3711) Touch Elements Combination Example: Slider Calculate, position: 24\nI (3721) Touch Elements Combination Example: Slider Calculate, position: 26\nI (3731) Touch Elements Combination Example: Slider Calculate, position: 27\nI (3741) Touch Elements Combination Example: Slider Calculate, position: 28\nI (3751) Touch Elements Combination Example: Slider Calculate, position: 29\nI (3761) Touch Elements Combination Example: Slider Calculate, position: 31\nI (3771) Touch Elements Combination Example: Slider Calculate, position: 32\nI (3781) Touch Elements Combination Example: Slider Calculate, position: 33\nI (3791) Touch Elements Combination Example: Slider Calculate, position: 34\nI (3801) Touch Elements Combination Example: Slider Calculate, position: 36\nI (3811) Touch Elements Combination Example: Slider Calculate, position: 37\nI (3821) Touch Elements Combination Example: Slider Calculate, position: 38\nI (3831) Touch Elements Combination Example: Slider Calculate, position: 39\nI (3841) Touch Elements Combination Example: Slider Calculate, position: 41\nI (3851) Touch Elements Combination Example: Slider Calculate, position: 42\nI (3861) Touch Elements Combination Example: Slider Calculate, position: 43\nI (3871) Touch Elements Combination Example: Slider Calculate, position: 45\nI (3881) Touch Elements Combination Example: Slider Calculate, position: 47\nI (3891) Touch Elements Combination Example: Slider Calculate, position: 48\nI (3901) Touch Elements Combination Example: Slider Calculate, position: 50\nI (3911) Touch Elements Combination Example: Slider Calculate, position: 52\nI (3921) Touch Elements Combination Example: Slider Calculate, position: 53\nI (3931) Touch Elements Combination Example: Slider Calculate, position: 55\nI (3941) Touch Elements Combination Example: Slider Calculate, position: 57\nI (3951) Touch Elements Combination Example: Slider Calculate, position: 58\nI (3961) Touch Elements Combination Example: Slider Calculate, position: 60\nI (3971) Touch Elements Combination Example: Slider Calculate, position: 61\nI (3981) Touch Elements Combination Example: Slider Calculate, position: 62\nI (3991) Touch Elements Combination Example: Slider Calculate, position: 64\nI (4001) Touch Elements Combination Example: Slider Calculate, position: 65\nI (4011) Touch Elements Combination Example: Slider Calculate, position: 66\nI (4021) Touch Elements Combination Example: Slider Calculate, position: 68\nI (4031) Touch Elements Combination Example: Slider Calculate, position: 69\nI (4041) Touch Elements Combination Example: Slider Calculate, position: 70\nI (4051) Touch Elements Combination Example: Slider Calculate, position: 72\nI (4061) Touch Elements Combination Example: Slider Calculate, position: 73\nI (4071) Touch Elements Combination Example: Slider Calculate, position: 75\nI (4081) Touch Elements Combination Example: Slider Calculate, position: 76\nI (4091) Touch Elements Combination Example: Slider Calculate, position: 77\nI (4101) Touch Elements Combination Example: Slider Calculate, position: 79\nI (4111) Touch Elements Combination Example: Slider Calculate, position: 80\nI (4121) Touch Elements Combination Example: Slider Calculate, position: 81\nI (4131) Touch Elements Combination Example: Slider Calculate, position: 83\nI (4141) Touch Elements Combination Example: Slider Calculate, position: 84\nI (4151) Touch Elements Combination Example: Slider Calculate, position: 85\nI (4161) Touch Elements Combination Example: Slider Calculate, position: 86\nI (4171) Touch Elements Combination Example: Slider Calculate, position: 88\nI (4181) Touch Elements Combination Example: Slider Calculate, position: 89\nI (4191) Touch Elements Combination Example: Slider Calculate, position: 90\nI (4201) Touch Elements Combination Example: Slider Calculate, position: 91\nI (4211) Touch Elements Combination Example: Slider Calculate, position: 92\nI (4221) Touch Elements Combination Example: Slider Calculate, position: 93\nI (4231) Touch Elements Combination Example: Slider Calculate, position: 94\nI (4241) Touch Elements Combination Example: Slider Calculate, position: 95\nI (4251) Touch Elements Combination Example: Slider Calculate, position: 96\nI (4261) Touch Elements Combination Example: Slider Calculate, position: 96\nI (4271) Touch Elements Combination Example: Slider Calculate, position: 97\nI (4281) Touch Elements Combination Example: Slider Calculate, position: 98\nI (4291) Touch Elements Combination Example: Slider Calculate, position: 99\nI (4301) Touch Elements Combination Example: Slider Calculate, position: 99\nI (4311) Touch Elements Combination Example: Slider Calculate, position: 100\nI (4321) Touch Elements Combination Example: Slider Calculate, position: 100\nI (4331) Touch Elements Combination Example: Slider Calculate, position: 100\nI (4341) Touch Elements Combination Example: Slider Calculate, position: 101\nI (4351) Touch Elements Combination Example: Slider Release, position: 101\n```\n\n## Troubleshooting\n\nFor any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.\n"
  },
  {
    "path": "touch_element/examples/touch_elements_combination/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"touch_elements_example_main.c\"\n                    INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES touch_element)\n"
  },
  {
    "path": "touch_element/examples/touch_elements_combination/main/idf_component.yml",
    "content": "dependencies:\n  espressif/touch_element:\n    version: '*'\n    override_path: '../../../'\n"
  },
  {
    "path": "touch_element/examples/touch_elements_combination/main/touch_elements_example_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n\n#include <inttypes.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"touch_element/touch_button.h\"\n#include \"touch_element/touch_slider.h\"\n#include \"esp_log.h\"\n\nstatic const char *TAG = \"Touch Elements Combination Example\";\n#define TOUCH_BUTTON_NUM     3\n#define TOUCH_SLIDER_CHANNEL_NUM     5\n\nstatic touch_button_handle_t button_handle[TOUCH_BUTTON_NUM]; //Touch buttons handle\nstatic touch_slider_handle_t slider_handle; //Touch slider handle\n\n/* Touch buttons channel array */\nstatic const touch_pad_t button_channel_array[TOUCH_BUTTON_NUM] = {\n    TOUCH_PAD_NUM6,\n    TOUCH_PAD_NUM8,\n    TOUCH_PAD_NUM10\n};\n\n/* Touch buttons channel sensitivity array */\nstatic const float button_channel_sens_array[TOUCH_BUTTON_NUM] = {\n    0.1F,\n    0.1F,\n    0.1F\n};\n\n/* Touch slider channels array */\nstatic const touch_pad_t slider_channel_array[TOUCH_SLIDER_CHANNEL_NUM] = {\n    TOUCH_PAD_NUM5,\n    TOUCH_PAD_NUM7,\n    TOUCH_PAD_NUM9,\n    TOUCH_PAD_NUM11,\n    TOUCH_PAD_NUM12,\n};\n\n/* Touch slider channels sensitivity array */\nstatic const float slider_channel_sens_array[TOUCH_SLIDER_CHANNEL_NUM] = {\n    0.252F,\n    0.246F,\n    0.277F,\n    0.250F,\n    0.257F,\n};\n\nstatic void button_handler(touch_elem_message_t element_message)\n{\n    const touch_button_message_t *button_message = touch_button_get_message(&element_message);\n    if (button_message->event == TOUCH_BUTTON_EVT_ON_PRESS) {\n        ESP_LOGI(TAG, \"Button[%d] Press\", (int)element_message.arg);\n    } else if (button_message->event == TOUCH_BUTTON_EVT_ON_RELEASE) {\n        ESP_LOGI(TAG, \"Button[%d] Release\", (int)element_message.arg);\n    } else if (button_message->event == TOUCH_BUTTON_EVT_ON_LONGPRESS) {\n        ESP_LOGI(TAG, \"Button[%d] LongPress\", (int)element_message.arg);\n    }\n}\n\nstatic void slider_handler(touch_elem_message_t element_message)\n{\n    const touch_slider_message_t *slider_message = touch_slider_get_message(&element_message);\n    if (slider_message->event == TOUCH_SLIDER_EVT_ON_PRESS) {\n        ESP_LOGI(TAG, \"Slider Press, position: %\"PRIu32, slider_message->position);\n    } else if (slider_message->event == TOUCH_SLIDER_EVT_ON_RELEASE) {\n        ESP_LOGI(TAG, \"Slider Release, position: %\"PRIu32, slider_message->position);\n    } else if (slider_message->event == TOUCH_SLIDER_EVT_ON_CALCULATION) {\n        ESP_LOGI(TAG, \"Slider Calculate, position: %\"PRIu32, slider_message->position);\n    }\n}\n\nstatic void event_handler_task(void *arg)\n{\n    (void) arg; //Unused\n    touch_elem_message_t element_message;\n    while (1) {\n        /* Waiting for touch element messages */\n        touch_element_message_receive(&element_message, portMAX_DELAY);\n        switch (element_message.element_type) {\n        case TOUCH_ELEM_TYPE_BUTTON:\n            button_handler(element_message);\n            break;\n        case TOUCH_ELEM_TYPE_SLIDER:\n            slider_handler(element_message);\n            break;\n        default:\n            ESP_LOGW(TAG, \"Unknown element message\");\n            break;\n        }\n    }\n}\n\nvoid button_example_init(void)\n{\n    touch_button_global_config_t global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();\n    ESP_ERROR_CHECK(touch_button_install(&global_config));\n    ESP_LOGI(TAG, \"Touch button installed\");\n    for (int i = 0; i < TOUCH_BUTTON_NUM; i++) {\n        touch_button_config_t button_config = {\n            .channel_num = button_channel_array[i],\n            .channel_sens = button_channel_sens_array[i]\n        };\n        /* Create Touch buttons */\n        ESP_ERROR_CHECK(touch_button_create(&button_config, &button_handle[i]));\n        /* Subscribe touch button events (On Press, On Release, On LongPress) */\n        ESP_ERROR_CHECK(touch_button_subscribe_event(button_handle[i],\n                        TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE | TOUCH_ELEM_EVENT_ON_LONGPRESS,\n                        (void *)button_channel_array[i]));\n        /* Set EVENT as the dispatch method */\n        ESP_ERROR_CHECK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_EVENT));\n        /* Set LongPress event trigger threshold time */\n        ESP_ERROR_CHECK(touch_button_set_longpress(button_handle[i], 2000));\n    }\n    ESP_LOGI(TAG, \"Touch buttons created\");\n}\n\nvoid slider_example_init(void)\n{\n    touch_slider_global_config_t global_config = TOUCH_SLIDER_GLOBAL_DEFAULT_CONFIG();\n    ESP_ERROR_CHECK(touch_slider_install(&global_config));\n    ESP_LOGI(TAG, \"Touch slider installed\");\n    /* Create Touch slider */\n    touch_slider_config_t slider_config = {\n        .channel_array = slider_channel_array,\n        .sensitivity_array = slider_channel_sens_array,\n        .channel_num = (sizeof(slider_channel_array) / sizeof(slider_channel_array[0])),\n        .position_range = 101\n    };\n    ESP_ERROR_CHECK(touch_slider_create(&slider_config, &slider_handle));\n    /* Subscribe touch slider events (On Press, On Release, On Calculation) */\n    ESP_ERROR_CHECK(touch_slider_subscribe_event(slider_handle,\n                    TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE | TOUCH_ELEM_EVENT_ON_CALCULATION, NULL));\n    /* Set EVENT as the dispatch method */\n    ESP_ERROR_CHECK(touch_slider_set_dispatch_method(slider_handle, TOUCH_ELEM_DISP_EVENT));\n    ESP_LOGI(TAG, \"Touch slider created\");\n}\n\nvoid app_main(void)\n{\n    /* Initialize Touch Element library */\n    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();\n    ESP_ERROR_CHECK(touch_element_install(&global_config));\n    ESP_LOGI(TAG, \"Touch element library installed\");\n\n    button_example_init();\n    slider_example_init();\n\n    touch_element_start();\n    ESP_LOGI(TAG, \"Touch element library start\");\n    /* Create a handler task to handle event messages */\n    xTaskCreate(&event_handler_task, \"event_handler_task\", 4 * 1024, NULL, 5, NULL);\n}\n"
  },
  {
    "path": "touch_element/examples/touch_elements_combination/pytest_touch_elements_combination.py",
    "content": "# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nimport glob\nfrom pathlib import Path\n\n\n@pytest.mark.generic\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that not build\"\n)\ndef test_touch_elements_combination(dut: Dut) -> None:\n    dut.expect_exact('Touch Elements Combination Example: Touch element library installed')\n    dut.expect_exact('Touch Elements Combination Example: Touch button installed')\n    dut.expect_exact('Touch Elements Combination Example: Touch buttons created')\n    dut.expect_exact('Touch Elements Combination Example: Touch slider installed')\n    dut.expect_exact('Touch Elements Combination Example: Touch slider created')\n    dut.expect_exact('Touch Elements Combination Example: Touch element library start')\n"
  },
  {
    "path": "touch_element/examples/touch_matrix/CMakeLists.txt",
    "content": "# The following lines of boilerplate have to be in your project's CMakeLists\n# in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\n# \"Trim\" the build. Include the minimal set of components, main, and anything it depends on.\nidf_build_set_property(MINIMAL_BUILD ON)\nproject(touch_matrix)\n"
  },
  {
    "path": "touch_element/examples/touch_matrix/README.md",
    "content": "# Touch Element matrix example\n\n(See the README.md file in the upper level 'examples' directory for more information about examples.)\n\nThis example demonstrates how to use the Touch Element library of capacitive touch sensor and set up touch matrix.\n\n## How to use example\n\n### Hardware Required\n\n* A development board with ESP32-S2 or ESP32-S3 chip\n* A touch extension board like [esp32-s2-touch-devkit-1](https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32s2/esp32-s2-touch-devkit-1/user_guide.html)\n\n### Configure the project\n\n* Set the target of the build by following command, where TARGET can be `esp32s2` or `esp32s3`.\n```\nidf.py set-target TARGET\n```\n* Run `idf.py menuconfig` to select a dispatch method for the example.\n\n### Build and Flash\n\nBuild the project and flash it to the board, then run monitor tool to view serial output:\n\n```\nidf.py -p PORT flash monitor\n```\n\n(Replace PORT with the name of the serial port to use.)\n\n(To exit the serial monitor, type ``Ctrl-]``.)\n\nSee the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.\n\n## Example Output\n\n```\nI (331) Touch Matrix Example: Touch element library installed\nI (331) Touch Matrix Example: Touch matrix installed\nI (341) Touch Matrix Example: Touch matrix created\nI (341) Touch Matrix Example: Touch element library start\nI (1951) Touch Matrix Example: Matrix Press, axis: (0, 0) index: 0\nI (2131) Touch Matrix Example: Matrix Release, axis: (0, 0) index: 0\nI (3121) Touch Matrix Example: Matrix Press, axis: (1, 1) index: 4\nI (3281) Touch Matrix Example: Matrix Release, axis: (1, 1) index: 4\nI (4621) Touch Matrix Example: Matrix Press, axis: (2, 0) index: 6\nI (4801) Touch Matrix Example: Matrix Release, axis: (2, 0) index: 6\nI (5381) Touch Matrix Example: Matrix Press, axis: (2, 2) index: 8\nI (5571) Touch Matrix Example: Matrix Release, axis: (2, 2) index: 8\nI (6221) Touch Matrix Example: Matrix Press, axis: (0, 2) index: 2\nI (6441) Touch Matrix Example: Matrix Release, axis: (0, 2) index: 2\nI (7551) Touch Matrix Example: Matrix Press, axis: (1, 1) index: 4\nI (8551) Touch Matrix Example: Matrix LongPress, axis: (1, 1) index: 4\nI (9551) Touch Matrix Example: Matrix LongPress, axis: (1, 1) index: 4\nI (10551) Touch Matrix Example: Matrix LongPress, axis: (1, 1) index: 4\nI (11031) Touch Matrix Example: Matrix Release, axis: (1, 1) index: 4\n```\n\n## Troubleshooting\n\nFor any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.\n"
  },
  {
    "path": "touch_element/examples/touch_matrix/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"touch_matrix_example_main.c\"\n                    INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES touch_element)\n"
  },
  {
    "path": "touch_element/examples/touch_matrix/main/Kconfig.projbuild",
    "content": "menu \"Example Configuration\"\n\n    choice TOUCH_SENSOR_EXAMPLE_TYPE\n        bool \"Select touch element dispatch method\"\n        default TOUCH_ELEM_EVENT\n        help\n            Select touch element dispatch method (event task or callback) for this example.\n\n        config TOUCH_ELEM_EVENT\n            bool \"Dispatch by event task\"\n        config TOUCH_ELEM_CALLBACK\n            bool \"Dispatch by callback\"\n    endchoice\n\nendmenu\n"
  },
  {
    "path": "touch_element/examples/touch_matrix/main/idf_component.yml",
    "content": "dependencies:\n  espressif/touch_element:\n    version: '*'\n    override_path: '../../../'\n"
  },
  {
    "path": "touch_element/examples/touch_matrix/main/touch_matrix_example_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n\n#include <inttypes.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"touch_element/touch_matrix.h\"\n#include \"esp_log.h\"\n\nstatic const char *TAG = \"Touch Matrix Example\";\n#define X_AXIS_CHANNEL_NUM     3\n#define Y_AXIS_CHANNEL_NUM     3\n\nstatic touch_matrix_handle_t matrix_handle;\n\n/* Touch Matrix Button x-axis channels array */\nstatic const touch_pad_t x_axis_channel[X_AXIS_CHANNEL_NUM] = {\n    TOUCH_PAD_NUM5,\n    TOUCH_PAD_NUM7,\n    TOUCH_PAD_NUM9,\n};\n\n/* Touch Matrix Button y-axis channels array */\nstatic const touch_pad_t y_axis_channel[Y_AXIS_CHANNEL_NUM] = {\n    TOUCH_PAD_NUM11,\n    TOUCH_PAD_NUM12,\n    TOUCH_PAD_NUM14,\n};\n\n/* Touch Matrix Button x-axis channels sensitivity array */\nstatic const float x_axis_channel_sens[X_AXIS_CHANNEL_NUM] = {\n    0.1F,\n    0.1F,\n    0.1F,\n};\n\n/* Touch Matrix Button y-axis channel sensitivity array */\nstatic const float y_axis_channel_sens[Y_AXIS_CHANNEL_NUM] = {\n    0.1F,\n    0.1F,\n    0.1F,\n};\n\n#ifdef CONFIG_TOUCH_ELEM_EVENT\n/* Matrix event handler task */\nstatic void matrix_handler_task(void *arg)\n{\n    (void) arg; //Unused\n    touch_elem_message_t element_message;\n    while (1) {\n        /* Waiting for touch element messages */\n        touch_element_message_receive(&element_message, portMAX_DELAY); //Block take\n        if (element_message.element_type != TOUCH_ELEM_TYPE_MATRIX) {\n            continue;\n        }\n        /* Decode message */\n        const touch_matrix_message_t *matrix_message = touch_matrix_get_message(&element_message);\n        if (matrix_message->event == TOUCH_MATRIX_EVT_ON_PRESS) {\n            ESP_LOGI(TAG, \"Matrix Press, axis: (%\"PRIu8\", %\"PRIu8\") index: %\"PRIu8, matrix_message->position.x_axis,\n                     matrix_message->position.y_axis, matrix_message->position.index);\n        } else if (matrix_message->event == TOUCH_MATRIX_EVT_ON_RELEASE) {\n            ESP_LOGI(TAG, \"Matrix Release, axis: (%\"PRIu8\", %\"PRIu8\") index: %\"PRIu8, matrix_message->position.x_axis,\n                     matrix_message->position.y_axis, matrix_message->position.index);\n        } else if (matrix_message->event == TOUCH_MATRIX_EVT_ON_LONGPRESS) {\n            ESP_LOGI(TAG, \"Matrix LongPress, axis: (%\"PRIu8\", %\"PRIu8\") index: %\"PRIu8, matrix_message->position.x_axis,\n                     matrix_message->position.y_axis, matrix_message->position.index);\n        }\n    }\n}\n#elif CONFIG_TOUCH_ELEM_CALLBACK\n/* Matrix callback routine */\nvoid matrix_handler(touch_matrix_handle_t out_handle, touch_matrix_message_t *out_message, void *arg)\n{\n    (void) arg; //Unused\n    if (out_handle != matrix_handle) {\n        return;\n    }\n    if (out_message->event == TOUCH_MATRIX_EVT_ON_PRESS) {\n        ESP_LOGI(TAG, \"Matrix Press, axis: (%\"PRIu8\", %\"PRIu8\") index: %\"PRIu8, out_message->position.x_axis,\n                 out_message->position.y_axis, out_message->position.index);\n    } else if (out_message->event == TOUCH_MATRIX_EVT_ON_RELEASE) {\n        ESP_LOGI(TAG, \"Matrix Release, axis: (%\"PRIu8\", %\"PRIu8\") index: %\"PRIu8, out_message->position.x_axis,\n                 out_message->position.y_axis, out_message->position.index);\n    } else if (out_message->event == TOUCH_MATRIX_EVT_ON_LONGPRESS) {\n        ESP_LOGI(TAG, \"Matrix LongPress, axis: (%\"PRIu8\", %\"PRIu8\") index: %\"PRIu8, out_message->position.x_axis,\n                 out_message->position.y_axis, out_message->position.index);\n    }\n}\n#endif\n\nvoid app_main(void)\n{\n    /* Initialize Touch Element library */\n    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();\n    ESP_ERROR_CHECK(touch_element_install(&global_config));\n    ESP_LOGI(TAG, \"Touch element library installed\");\n\n    touch_matrix_global_config_t matrix_global_config = TOUCH_MATRIX_GLOBAL_DEFAULT_CONFIG();\n    ESP_ERROR_CHECK(touch_matrix_install(&matrix_global_config));\n    ESP_LOGI(TAG, \"Touch matrix installed\");\n    /* Create Touch Matrix Button */\n    touch_matrix_config_t matrix_config = {\n        .x_channel_array = x_axis_channel,\n        .y_channel_array = y_axis_channel,\n        .x_sensitivity_array = x_axis_channel_sens,\n        .y_sensitivity_array = y_axis_channel_sens,\n        .x_channel_num = (sizeof(x_axis_channel) / sizeof(x_axis_channel[0])),\n        .y_channel_num = (sizeof(y_axis_channel) / sizeof(y_axis_channel[0]))\n    };\n    ESP_ERROR_CHECK(touch_matrix_create(&matrix_config, &matrix_handle));\n    /* Subscribe touch matrix events (On Press, On Release, On LongPress) */\n    ESP_ERROR_CHECK(touch_matrix_subscribe_event(matrix_handle,\n                    TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE | TOUCH_ELEM_EVENT_ON_LONGPRESS, NULL));\n#ifdef CONFIG_TOUCH_ELEM_EVENT\n    /* Set EVENT as the dispatch method */\n    ESP_ERROR_CHECK(touch_matrix_set_dispatch_method(matrix_handle, TOUCH_ELEM_DISP_EVENT));\n    /* Create a handler task to handle event messages */\n    xTaskCreate(&matrix_handler_task, \"matrix_handler_task\", 4 * 1024, NULL, 5, NULL);\n#elif CONFIG_TOUCH_ELEM_CALLBACK\n    /* Set CALLBACK as the dispatch method */\n    ESP_ERROR_CHECK(touch_matrix_set_dispatch_method(matrix_handle, TOUCH_ELEM_DISP_CALLBACK));\n    /* Register a handler function to handle event messages */\n    ESP_ERROR_CHECK(touch_matrix_set_callback(matrix_handle, matrix_handler));\n#endif\n    ESP_LOGI(TAG, \"Touch matrix created\");\n\n    touch_element_start();\n    ESP_LOGI(TAG, \"Touch element library start\");\n}\n"
  },
  {
    "path": "touch_element/examples/touch_matrix/pytest_touch_matrix.py",
    "content": "# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nimport glob\nfrom pathlib import Path\n\n\n@pytest.mark.generic\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that not build\"\n)\ndef test_touch_matrix(dut: Dut) -> None:\n    dut.expect_exact('Touch Matrix Example: Touch element library installed')\n    dut.expect_exact('Touch Matrix Example: Touch matrix installed')\n    dut.expect_exact('Touch Matrix Example: Touch matrix created')\n    dut.expect_exact('Touch Matrix Example: Touch element library start')\n"
  },
  {
    "path": "touch_element/examples/touch_slider/CMakeLists.txt",
    "content": "# The following lines of boilerplate have to be in your project's CMakeLists\n# in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\n# \"Trim\" the build. Include the minimal set of components, main, and anything it depends on.\nidf_build_set_property(MINIMAL_BUILD ON)\nproject(touch_slider)\n"
  },
  {
    "path": "touch_element/examples/touch_slider/README.md",
    "content": "# Touch Element slider example\n\n(See the README.md file in the upper level 'examples' directory for more information about examples.)\n\nThis example demonstrates how to use the Touch Element library of capacitive touch sensor and set up touch slider.\n\n## How to use example\n\n### Hardware Required\n\n* A development board with ESP32-S2 or ESP32-S3 chip\n* A touch extension board like [esp32-s2-touch-devkit-1](https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32s2/esp32-s2-touch-devkit-1/user_guide.html)\n\n### Configure the project\n\n* Set the target of the build by following command, where TARGET can be `esp32s2` or `esp32s3`.\n```\nidf.py set-target TARGET\n```\n* Run `idf.py menuconfig` to select a dispatch method for the example.\n\n### Build and Flash\n\nBuild the project and flash it to the board, then run monitor tool to view serial output:\n\n```\nidf.py -p PORT flash monitor\n```\n\n(Replace PORT with the name of the serial port to use.)\n\n(To exit the serial monitor, type ``Ctrl-]``.)\n\nSee the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.\n\n## Example Output\n\n```\nI (331) Touch Slider Example: Touch element library installed\nI (331) Touch Slider Example: Touch slider installed\nI (341) Touch Slider Example: Touch slider created\nI (341) Touch Slider Example: Touch element library start\nI (1911) Touch Slider Example: Slider Press, position: 0\nI (1921) Touch Slider Example: Slider Calculate, position: 0\nI (1931) Touch Slider Example: Slider Calculate, position: 0\nI (1941) Touch Slider Example: Slider Calculate, position: 0\nI (1951) Touch Slider Example: Slider Calculate, position: 0\nI (1961) Touch Slider Example: Slider Calculate, position: 0\nI (1971) Touch Slider Example: Slider Calculate, position: 0\nI (1981) Touch Slider Example: Slider Calculate, position: 0\nI (1991) Touch Slider Example: Slider Calculate, position: 0\nI (2001) Touch Slider Example: Slider Calculate, position: 0\nI (2011) Touch Slider Example: Slider Calculate, position: 0\nI (2021) Touch Slider Example: Slider Calculate, position: 1\nI (2031) Touch Slider Example: Slider Calculate, position: 1\nI (2041) Touch Slider Example: Slider Calculate, position: 2\nI (2051) Touch Slider Example: Slider Calculate, position: 2\nI (2061) Touch Slider Example: Slider Calculate, position: 4\nI (2071) Touch Slider Example: Slider Calculate, position: 5\nI (2081) Touch Slider Example: Slider Calculate, position: 6\nI (2091) Touch Slider Example: Slider Calculate, position: 8\nI (2101) Touch Slider Example: Slider Calculate, position: 10\nI (2111) Touch Slider Example: Slider Calculate, position: 12\nI (2121) Touch Slider Example: Slider Calculate, position: 15\nI (2131) Touch Slider Example: Slider Calculate, position: 17\nI (2141) Touch Slider Example: Slider Calculate, position: 19\nI (2151) Touch Slider Example: Slider Calculate, position: 22\nI (2161) Touch Slider Example: Slider Calculate, position: 24\nI (2171) Touch Slider Example: Slider Calculate, position: 26\nI (2181) Touch Slider Example: Slider Calculate, position: 29\nI (2191) Touch Slider Example: Slider Calculate, position: 31\nI (2201) Touch Slider Example: Slider Calculate, position: 33\nI (2211) Touch Slider Example: Slider Calculate, position: 35\nI (2221) Touch Slider Example: Slider Calculate, position: 37\nI (2231) Touch Slider Example: Slider Calculate, position: 40\nI (2241) Touch Slider Example: Slider Calculate, position: 42\nI (2251) Touch Slider Example: Slider Calculate, position: 44\nI (2261) Touch Slider Example: Slider Calculate, position: 46\nI (2271) Touch Slider Example: Slider Calculate, position: 48\nI (2281) Touch Slider Example: Slider Calculate, position: 50\nI (2291) Touch Slider Example: Slider Calculate, position: 52\nI (2301) Touch Slider Example: Slider Calculate, position: 54\nI (2311) Touch Slider Example: Slider Calculate, position: 56\nI (2321) Touch Slider Example: Slider Calculate, position: 57\nI (2331) Touch Slider Example: Slider Calculate, position: 59\nI (2341) Touch Slider Example: Slider Calculate, position: 60\nI (2351) Touch Slider Example: Slider Calculate, position: 61\nI (2361) Touch Slider Example: Slider Release, position: 61\n```\n\n## Troubleshooting\n\nFor any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.\n"
  },
  {
    "path": "touch_element/examples/touch_slider/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"touch_slider_example_main.c\"\n                    INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES touch_element)\n"
  },
  {
    "path": "touch_element/examples/touch_slider/main/Kconfig.projbuild",
    "content": "menu \"Example Configuration\"\n\n    choice TOUCH_SENSOR_EXAMPLE_TYPE\n        bool \"Select touch element dispatch method\"\n        default TOUCH_ELEM_EVENT\n        help\n            Select touch element dispatch method (event task or callback) for this example.\n\n        config TOUCH_ELEM_EVENT\n            bool \"Dispatch by event task\"\n        config TOUCH_ELEM_CALLBACK\n            bool \"Dispatch by callback\"\n    endchoice\n\nendmenu\n"
  },
  {
    "path": "touch_element/examples/touch_slider/main/idf_component.yml",
    "content": "dependencies:\n  espressif/touch_element:\n    version: '*'\n    override_path: '../../../'\n"
  },
  {
    "path": "touch_element/examples/touch_slider/main/touch_slider_example_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: CC0-1.0\n */\n\n#include <inttypes.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"touch_element/touch_slider.h\"\n#include \"esp_log.h\"\n\nstatic const char *TAG = \"Touch Slider Example\";\n#define TOUCH_SLIDER_CHANNEL_NUM     5\n\nstatic touch_slider_handle_t slider_handle; //Touch slider handle\n\nstatic const touch_pad_t channel_array[TOUCH_SLIDER_CHANNEL_NUM] = { //Touch slider channels array\n    TOUCH_PAD_NUM5,\n    TOUCH_PAD_NUM7,\n    TOUCH_PAD_NUM9,\n    TOUCH_PAD_NUM11,\n    TOUCH_PAD_NUM12,\n};\n\n/**\n * Using finger slide from slider's beginning to the ending, and output the RAW channel signal, then calculate all the\n * channels sensitivity of the slider, and you can decrease or increase the detection sensitivity by adjusting the threshold divider\n * which locates in touch_slider_global_config_t. Please keep in mind that the real sensitivity totally depends on the\n * physical characteristics, if you want to decrease or increase the detection sensitivity, keep the ratio of those channels the same.\n */\nstatic const float channel_sens_array[TOUCH_SLIDER_CHANNEL_NUM] = {  //Touch slider channels sensitivity array\n    0.252F,\n    0.246F,\n    0.277F,\n    0.250F,\n    0.257F,\n};\n\n#ifdef CONFIG_TOUCH_ELEM_EVENT\n/* Slider event handler task */\nstatic void slider_handler_task(void *arg)\n{\n    (void) arg; //Unused\n    touch_elem_message_t element_message;\n    while (1) {\n        /* Waiting for touch element messages */\n        if (touch_element_message_receive(&element_message, portMAX_DELAY) == ESP_OK) {\n            if (element_message.element_type != TOUCH_ELEM_TYPE_SLIDER) {\n                continue;\n            }\n            /* Decode message */\n            const touch_slider_message_t *slider_message = touch_slider_get_message(&element_message);\n            if (slider_message->event == TOUCH_SLIDER_EVT_ON_PRESS) {\n                ESP_LOGI(TAG, \"Slider Press, position: %\"PRIu32, slider_message->position);\n            } else if (slider_message->event == TOUCH_SLIDER_EVT_ON_RELEASE) {\n                ESP_LOGI(TAG, \"Slider Release, position: %\"PRIu32, slider_message->position);\n            } else if (slider_message->event == TOUCH_SLIDER_EVT_ON_CALCULATION) {\n                ESP_LOGI(TAG, \"Slider Calculate, position: %\"PRIu32, slider_message->position);\n            }\n        }\n    }\n}\n#elif CONFIG_TOUCH_ELEM_CALLBACK\n/* Slider callback routine */\nvoid slider_handler(touch_slider_handle_t out_handle, touch_slider_message_t *out_message, void *arg)\n{\n    (void) arg; //Unused\n    if (out_handle != slider_handle) {\n        return;\n    }\n    if (out_message->event == TOUCH_SLIDER_EVT_ON_PRESS) {\n        ESP_LOGI(TAG, \"Slider Press, position: %\"PRIu32, out_message->position);\n    } else if (out_message->event == TOUCH_SLIDER_EVT_ON_RELEASE) {\n        ESP_LOGI(TAG, \"Slider Release, position: %\"PRIu32, out_message->position);\n    } else if (out_message->event == TOUCH_SLIDER_EVT_ON_CALCULATION) {\n        ESP_LOGI(TAG, \"Slider Calculate, position: %\"PRIu32, out_message->position);\n    }\n}\n#endif\n\nvoid app_main(void)\n{\n    /* Initialize Touch Element library */\n    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();\n    ESP_ERROR_CHECK(touch_element_install(&global_config));\n    ESP_LOGI(TAG, \"Touch element library installed\");\n\n    touch_slider_global_config_t slider_global_config = TOUCH_SLIDER_GLOBAL_DEFAULT_CONFIG();\n    ESP_ERROR_CHECK(touch_slider_install(&slider_global_config));\n    ESP_LOGI(TAG, \"Touch slider installed\");\n    /* Create Touch slider */\n    touch_slider_config_t slider_config = {\n        .channel_array = channel_array,\n        .sensitivity_array = channel_sens_array,\n        .channel_num = (sizeof(channel_array) / sizeof(channel_array[0])),\n        .position_range = 101\n    };\n    ESP_ERROR_CHECK(touch_slider_create(&slider_config, &slider_handle));\n    /* Subscribe touch slider events (On Press, On Release, On Calculation) */\n    ESP_ERROR_CHECK(touch_slider_subscribe_event(slider_handle,\n                    TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE | TOUCH_ELEM_EVENT_ON_CALCULATION, NULL));\n#ifdef CONFIG_TOUCH_ELEM_EVENT\n    /* Set EVENT as the dispatch method */\n    ESP_ERROR_CHECK(touch_slider_set_dispatch_method(slider_handle, TOUCH_ELEM_DISP_EVENT));\n    /* Create a handler task to handle event messages */\n    xTaskCreate(&slider_handler_task, \"slider_handler_task\", 4 * 1024, NULL, 5, NULL);\n#elif CONFIG_TOUCH_ELEM_CALLBACK\n    /* Set CALLBACK as the dispatch method */\n    ESP_ERROR_CHECK(touch_slider_set_dispatch_method(slider_handle, TOUCH_ELEM_DISP_CALLBACK));\n    /* Register a handler function to handle event messages */\n    ESP_ERROR_CHECK(touch_slider_set_callback(slider_handle, slider_handler));\n#endif\n    ESP_LOGI(TAG, \"Touch slider created\");\n    touch_element_start();\n    ESP_LOGI(TAG, \"Touch element library start\");\n}\n"
  },
  {
    "path": "touch_element/examples/touch_slider/pytest_touch_slider.py",
    "content": "# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nimport glob\nfrom pathlib import Path\n\n\n@pytest.mark.generic\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that not build\"\n)\ndef test_touch_slider(dut: Dut) -> None:\n    dut.expect_exact('Touch Slider Example: Touch element library installed')\n    dut.expect_exact('Touch Slider Example: Touch slider installed')\n    dut.expect_exact('Touch Slider Example: Touch slider created')\n    dut.expect_exact('Touch Slider Example: Touch element library start')\n"
  },
  {
    "path": "touch_element/idf_component.yml",
    "content": "version: \"1.1.2\"\ndescription: Touch Element Library\nurl: https://github.com/espressif/idf-extra-components/tree/master/touch_element\nrepository: https://github.com/espressif/idf-extra-components.git\ndocumentation: https://espressif.github.io/idf-extra-components/latest/touch_element/index.html\nissues: https://github.com/espressif/idf-extra-components/issues\ndependencies:\n  idf: \">=5.3\"\ntargets:\n- esp32s2\n- esp32s3\n"
  },
  {
    "path": "touch_element/include/esp_private/touch_element_private.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include \"touch_element/touch_element.h\"\n#include \"touch_element/touch_button.h\"\n#include \"touch_element/touch_slider.h\"\n#include \"touch_element/touch_matrix.h\"\n#include \"esp_pm.h\"\n#include \"sdkconfig.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define TE_TAG \"Touch Element\"\n#define TE_DEBUG_TAG \"Touch Element Debug\"\n#define TE_UNUSED(arg)            (void)arg\n\n#define TE_CHECK(cond, ret_val) ({                                            \\\n    if (!(cond)) {                                                            \\\n        ESP_LOGE(TE_TAG, \"%s(%d)\", __FUNCTION__, __LINE__);     \\\n        return (ret_val);                                                     \\\n    }                                                                         \\\n})\n\n#define TE_CHECK_GOTO(cond, label) ({                                         \\\n    if (!(cond)) {                                                            \\\n        goto label;                                                           \\\n    }                                                                         \\\n})\n\n#define TE_FREE_AND_NULL(ptr) ({                                              \\\n    free(ptr);                                                                \\\n    (ptr) = NULL;                                                             \\\n})\n\n#define TE_DEFAULT_THRESHOLD_DIVIDER(obj)       ((obj)->global_config->threshold_divider)\n#define TE_DEFAULT_LONGPRESS_TIME(obj)          ((obj)->global_config->default_lp_time)\n\ntypedef enum {\n    TE_STATE_IDLE = 0,\n    TE_STATE_PRESS,\n    TE_STATE_RELEASE,\n} te_state_t;\n\ntypedef te_state_t te_dev_state_t;\ntypedef touch_elem_type_t te_dev_type_t;\n\ntypedef struct {\n    float sens;                   //!< Touch channel sensitivity\n    touch_pad_t channel;          //!< Touch channel number(index)\n    te_dev_type_t type;           //!< Touch channel type  TODO: need to refactor as te_class_type_t\n    te_dev_state_t state;         //!< Touch channel current state\n    bool is_use_last_threshold;\n} te_dev_t;\n\ntypedef enum {\n    TE_CLS_TYPE_BUTTON = 0,\n    TE_CLS_TYPE_SLIDER,\n    TE_CLS_TYPE_MATRIX,\n    TE_CLS_TYPE_MAX  //TODO: add waterproof class\n} te_class_type_t;\n\ntypedef struct  {\n    touch_elem_handle_t handle;\n    bool (*check_channel) (touch_pad_t);\n    esp_err_t (*set_threshold) (void);\n    void (*process_state) (void);\n    void (*update_state) (touch_pad_t, te_state_t);\n} te_object_methods_t;\n\n/* -------------------------------------------- Waterproof basic type --------------------------------------------- */\nstruct te_waterproof_s {\n    te_dev_t *guard_device;                     //Waterproof guard channel device\n    touch_elem_handle_t *mask_handle;           //Waterproof masked handle array\n    touch_pad_t shield_channel;                 //Waterproof shield channel\n    bool is_shield_level_set;                   //Waterproof shield level setting bit\n};\ntypedef struct te_waterproof_s *te_waterproof_handle_t;\n/* -------------------------------------------- Sleep basic type --------------------------------------------- */\nstruct te_sleep_s {\n    touch_elem_handle_t wakeup_handle;\n#ifdef CONFIG_PM_ENABLE\n    esp_pm_lock_handle_t pm_lock;\n#endif\n    uint32_t *non_volatile_threshold;\n};\n\ntypedef struct te_sleep_s *te_sleep_handle_t;\n/* -------------------------------------------- Button basic type --------------------------------------------- */\ntypedef struct {\n    touch_elem_dispatch_t dispatch_method;      //Button dispatch method\n    touch_button_callback_t callback;           //Button callback routine\n    uint32_t event_mask;                        //Button subscribed event mask\n    void *arg;                                  //User input argument\n} te_button_handle_config_t;\n\ntypedef te_state_t te_button_state_t;           //TODO: add Long Press state\n\nstruct te_button_s {\n    te_button_handle_config_t *config;          //Button configuration\n    te_dev_t *device;                           //Base device information\n    te_button_state_t current_state;            //Button current state\n    te_button_state_t last_state;               //Button last state\n    touch_button_event_t event;                 //Button outside state(for application layer)\n    uint32_t trigger_cnt;                       //Button long time trigger counter\n    uint32_t trigger_thr;                       //Button long time trigger counter threshold\n};\n\ntypedef struct te_button_s *te_button_handle_t;\n/* -------------------------------------------- Slider basic type --------------------------------------------- */\ntypedef struct {\n    touch_elem_dispatch_t dispatch_method;      //Slider dispatch method\n    touch_slider_callback_t callback;           //Slider callback routine\n    uint32_t event_mask;                        //Slider subscribed event mask\n    void *arg;                                  //User input argument\n} te_slider_handle_config_t;\n\ntypedef te_state_t te_slider_state_t;\n\nstruct te_slider_s {\n    te_slider_handle_config_t *config;          //Slider configuration\n    te_dev_t **device;                          //Base device information set\n    te_slider_state_t current_state;            //Slider current state\n    te_slider_state_t last_state;               //Slider last state\n    touch_slider_event_t event;                 //Slider outside state(for application layer)\n    float position_scale;                       //Slider position scale(step size)\n    float *quantify_signal_array;               //Slider re-quantization array\n    uint32_t *channel_bcm;                      //Channel benchmark array\n    uint32_t channel_bcm_update_cnt;            //Channel benchmark update counter\n    uint32_t filter_reset_cnt;                  //Slider reset counter\n    uint32_t last_position;                     //Slider last position\n    touch_slider_position_t position;           //Slider position\n    uint8_t position_range;                     //Slider position range([0, position_range])\n    uint8_t channel_sum;                        //Slider channel sum\n    uint8_t *pos_filter_window;                 //Slider position moving average filter window\n    uint8_t pos_window_idx;                     //Slider position moving average filter window index\n    bool is_first_sample;                       //Slider first time sample record bit\n};\n\ntypedef struct te_slider_s *te_slider_handle_t;\n/* -------------------------------------------- Matrix basic type --------------------------------------------- */\ntypedef struct {\n    touch_elem_dispatch_t dispatch_method;      //Matrix button dispatch method\n    touch_matrix_callback_t callback;           //Matrix button callback routine\n    uint32_t event_mask;                        //Matrix button subscribed event mask\n    void *arg;                                  //User input argument\n} te_matrix_handle_config_t;\n\ntypedef te_state_t te_matrix_state_t;           //TODO: add Long Press state\n\nstruct te_matrix_s {\n    te_matrix_handle_config_t *config;          //Matrix button configuration\n    te_dev_t **device;                          //Base device information\n    te_matrix_state_t current_state;            //Matrix button current state\n    te_matrix_state_t last_state;               //Matrix button current state\n    touch_matrix_event_t event;                 //Matrix button outside state(for application layer)\n    uint32_t trigger_cnt;                       //Matrix button long time trigger counter\n    uint32_t trigger_thr;                       //Matrix button long time trigger counter threshold\n    touch_matrix_position_t position;           //Matrix button position\n    uint8_t x_channel_num;                      //The number of touch sensor channel in x axis\n    uint8_t y_channel_num;                      //The number of touch sensor channel in y axis\n};\n\ntypedef struct te_matrix_s *te_matrix_handle_t;\n/* ------------------------------------------------------------------------------------------------------------------ */\n\n/* --------------------------------------------- Global system methods ---------------------------------------------- */\nuint32_t te_read_smooth_signal(touch_pad_t channel_num);\nbool te_system_check_state(void);\n//TODO: Refactor this function with function overload\nesp_err_t te_dev_init(te_dev_t **device, uint8_t device_num, te_dev_type_t type, const touch_pad_t *channel, const float *sens, float divider);\nvoid te_dev_deinit(te_dev_t **device, uint8_t device_num);\nesp_err_t te_dev_set_threshold(te_dev_t *device);\nesp_err_t te_event_give(touch_elem_message_t te_message);\nuint8_t te_get_timer_period(void);\nvoid te_object_method_register(te_object_methods_t *object_methods, te_class_type_t object_type);\nvoid te_object_method_unregister(te_class_type_t object_type);\nbool te_object_check_channel(const touch_pad_t *channel_array, uint8_t channel_sum);\nbool waterproof_check_mask_handle(touch_elem_handle_t te_handle);\nbool te_is_touch_dsleep_wakeup(void);\ntouch_pad_t te_get_sleep_channel(void);\n\nbool is_button_object_handle(touch_elem_handle_t element_handle);\nbool is_slider_object_handle(touch_elem_handle_t element_handle);\nbool is_matrix_object_handle(touch_elem_handle_t element_handle);\n\nvoid button_enable_wakeup_calibration(te_button_handle_t button_handle, bool en);\nvoid slider_enable_wakeup_calibration(te_slider_handle_t slider_handle, bool en);\nvoid matrix_enable_wakeup_calibration(te_matrix_handle_t matrix_handle, bool en);\n/* ------------------------------------------------------------------------------------------------------------------ */\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "touch_element/include/esp_private/touch_sensor_legacy_hal.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include \"esp_private/touch_sensor_legacy_ll.h\"\n#include \"touch_element/touch_sensor_legacy_types.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct {\n    touch_high_volt_t refh;\n    touch_low_volt_t refl;\n    touch_volt_atten_t atten;\n} touch_hal_volt_t;\n\ntypedef struct {\n    touch_cnt_slope_t slope;    /*!<Set touch sensor charge/discharge speed(currents) for each pad.*/\n    touch_tie_opt_t tie_opt;    /*!<Set initial voltage state of touch channel for each measurement.*/\n} touch_hal_meas_mode_t;\n\n/**\n * Set touch sensor high / low voltage threshold of charge.\n * The touch sensor measures the channel capacitance value by charging and discharging the channel.\n * So charge threshold should be less than the supply voltage.\n * The actual charge threshold is high voltage threshold minus attenuation value.\n *\n * @param refh The high voltage threshold of charge.\n */\nvoid touch_hal_set_voltage(const touch_hal_volt_t *volt);\n\n/**\n * Get touch sensor high / low voltage threshold of charge.\n * The touch sensor measures the channel capacitance value by charging and discharging the channel.\n * So charge threshold should be less than the supply voltage.\n * The actual charge threshold is high voltage threshold minus attenuation value.\n *\n * @param refh The voltage threshold of charge / discharge.\n */\nvoid touch_hal_get_voltage(touch_hal_volt_t *volt);\n\n/**\n * Set touch sensor charge/discharge speed(currents) and initial voltage state for each pad measurement.\n *\n * @param touch_num Touch pad index.\n * @param meas Touch pad measurement config.\n */\nvoid touch_hal_set_meas_mode(touch_pad_t touch_num, const touch_hal_meas_mode_t *meas);\n\n/**\n * Get touch sensor charge/discharge speed(currents) and initial voltage state for each pad measurement.\n *\n * @param touch_num Touch pad index.\n * @param meas Touch pad measurement config.\n */\nvoid touch_hal_get_meas_mode(touch_pad_t touch_num, touch_hal_meas_mode_t *meas);\n\n/**\n * Initialize touch module.\n *\n * @note  If default parameter don't match the usage scenario, it can be changed after this function.\n */\nvoid touch_hal_init(void);\n\n/**\n * Un-install touch pad driver.\n *\n * @note  After this function is called, other touch functions are prohibited from being called.\n */\nvoid touch_hal_deinit(void);\n\n/**\n * Configure touch sensor for each channel.\n */\nvoid touch_hal_config(touch_pad_t touch_num);\n\n/************************ Filter register setting ************************/\n\n/**\n * Set parameter of touch sensor filter and detection algorithm.\n * For more details on the detection algorithm, please refer to the application documentation.\n *\n * @param filter_info select filter type and threshold of detection algorithm\n */\nvoid touch_hal_filter_set_config(const touch_filter_config_t *filter_info);\n\n/**\n * Get parameter of touch sensor filter and detection algorithm.\n * For more details on the detection algorithm, please refer to the application documentation.\n *\n * @param filter_info select filter type and threshold of detection algorithm\n */\nvoid touch_hal_filter_get_config(touch_filter_config_t *filter_info);\n\n\n/************************ Denoise register setting ************************/\n\n/**\n * set parameter of denoise pad (TOUCH_PAD_NUM0).\n *        T0 is an internal channel that does not have a corresponding external GPIO.\n *        T0 will work simultaneously with the measured channel Tn. Finally, the actual\n *        measured value of Tn is the value after subtracting lower bits of T0.\n *        This denoise function filters out interference introduced on all channels,\n *        such as noise introduced by the power supply and external EMI.\n *\n * @param denoise parameter of denoise\n */\nvoid touch_hal_denoise_set_config(const touch_pad_denoise_t *denoise);\n\n/**\n * @brief get parameter of denoise pad (TOUCH_PAD_NUM0).\n *\n * @param denoise Pointer to parameter of denoise\n */\nvoid touch_hal_denoise_get_config(touch_pad_denoise_t *denoise);\n\n/**\n * Enable denoise function.\n * T0 is an internal channel that does not have a corresponding external GPIO.\n * T0 will work simultaneously with the measured channel Tn. Finally, the actual\n * measured value of Tn is the value after subtracting lower bits of T0.\n * This denoise function filters out interference introduced on all channels,\n * such as noise introduced by the power supply and external EMI.\n */\nvoid touch_hal_denoise_enable(void);\n\n\n/************************ Waterproof register setting ************************/\n\n/**\n * Set parameter of waterproof function.\n *\n * The waterproof function includes a shielded channel (TOUCH_PAD_NUM14) and a guard channel.\n * Guard pad is used to detect the large area of water covering the touch panel.\n * Shield pad is used to shield the influence of water droplets covering the touch panel.\n * It is generally designed as a grid and is placed around the touch buttons.\n *\n * @param waterproof parameter of waterproof\n */\nvoid touch_hal_waterproof_set_config(const touch_pad_waterproof_t *waterproof);\n\n/**\n * Get parameter of waterproof function.\n *\n * @param waterproof parameter of waterproof.\n */\nvoid touch_hal_waterproof_get_config(touch_pad_waterproof_t *waterproof);\n\n/**\n * Enable parameter of waterproof function.\n * Should be called after function ``touch_hal_waterproof_set_config``.\n */\nvoid touch_hal_waterproof_enable(void);\n\n/************************ Proximity register setting ************************/\n\n/**\n * Enable/disable proximity function of touch channels.\n * The proximity sensor measurement is the accumulation of touch channel measurements.\n *\n * @note Supports up to three touch channels configured as proximity sensors.\n * @param touch_num touch pad index\n * @param enabled true: enable the proximity function; false:  disable the proximity function\n * @return\n *     - true: Configured correctly.\n *     - false: Configured error.\n */\nbool touch_hal_enable_proximity(touch_pad_t touch_num, bool enabled);\n\n\n/************** sleep pad setting ***********************/\n\n/**\n * Get parameter of touch sensor sleep channel.\n * The touch sensor can works in sleep mode to wake up sleep.\n * After the sleep channel is configured, users should query the channel reading using a specific function.\n *\n * @param slp_config Point to touch sleep pad config.\n */\nvoid touch_hal_sleep_channel_get_config(touch_pad_sleep_channel_t *slp_config);\n\n/**\n * Set parameter of touch sensor sleep channel.\n * The touch sensor can works in sleep mode to wake up sleep.\n * After the sleep channel is configured, users should query the channel reading using a specific function.\n *\n * @note ESP32S2 only support one channel to be set sleep channel.\n *\n * @param pad_num touch sleep pad number.\n * @param enable Enable/disable sleep pad function.\n */\nvoid touch_hal_sleep_channel_enable(touch_pad_t pad_num, bool enable);\n\n/**\n * Change the operating frequency of touch pad in deep sleep state. Reducing the operating frequency can effectively reduce power consumption.\n * If this function is not called, the working frequency of touch in the deep sleep state is the same as that in the wake-up state.\n *\n * @param sleep_cycle The touch sensor will sleep after each measurement.\n *                    sleep_cycle decide the interval between each measurement.\n *                    t_sleep = sleep_cycle / (RTC_SLOW_CLK frequency).\n *                    The approximate frequency value of RTC_SLOW_CLK can be obtained using rtc_clk_slow_freq_get_hz function.\n * @param meas_times The times of charge and discharge in each measure process of touch channels.\n *                  The timer frequency is 8Mhz. Range: 0 ~ 0xffff.\n *                  Recommended typical value: Modify this value to make the measurement time around 1ms.\n */\nvoid touch_hal_sleep_channel_set_work_time(uint16_t sleep_cycle, uint16_t meas_times);\n\n/**\n * Get the operating frequency of touch pad in deep sleep state. Reducing the operating frequency can effectively reduce power consumption.\n *\n * @param sleep_cycle The touch sensor will sleep after each measurement.\n *                    sleep_cycle decide the interval between each measurement.\n *                    t_sleep = sleep_cycle / (RTC_SLOW_CLK frequency).\n *                    The approximate frequency value of RTC_SLOW_CLK can be obtained using rtc_clk_slow_freq_get_hz function.\n * @param meas_times The times of charge and discharge in each measure process of touch channels.\n *                  The timer frequency is 8Mhz. Range: 0 ~ 0xffff.\n *                  Recommended typical value: Modify this value to make the measurement time around 1ms.\n */\nvoid touch_hal_sleep_channel_get_work_time(uint16_t *sleep_cycle, uint16_t *meas_times);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "touch_element/include/esp_private/touch_sensor_legacy_ll.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// The Lowlevel layer for Touch Sensor\n\n#pragma once\n\n#include <stdlib.h>\n#include <stdbool.h>\n#include \"esp_bit_defs.h\"\n#include \"hal/misc.h\"\n#include \"hal/assert.h\"\n#include \"soc/rtc_cntl_struct.h\"\n#include \"soc/rtc_cntl_reg.h\"\n#include \"soc/rtc_io_struct.h\"\n#include \"soc/sens_struct.h\"\n#include \"touch_element/touch_sensor_legacy_types.h\"\n#include \"esp_idf_version.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define TOUCH_LL_CHAN_NUM                    15\n#define TOUCH_LL_PROXIMITY_CHANNEL_NUM       3\n#define TOUCH_LL_SHIELD_CHANNEL              14\n#define TOUCH_LL_DENOISE_CHANNEL             0\n\n#define TOUCH_LL_INTR_MASK_DONE              0x01/*!<Measurement done for one of the enabled channels. */\n#define TOUCH_LL_INTR_MASK_ACTIVE            0x02 /*!<Active for one of the enabled channels. */\n#define TOUCH_LL_INTR_MASK_INACTIVE          0x04 /*!<Inactive for one of the enabled channels. */\n#define TOUCH_LL_INTR_MASK_SCAN_DONE         0x08 /*!<Measurement done for all the enabled channels. */\n#define TOUCH_LL_INTR_MASK_TIMEOUT           0x10 /*!<Timeout for one of the enabled channels. */\n#ifdef RTC_CNTL_INT_ENA_W1TS_REG\n#define TOUCH_LL_INTR_MASK_PROXI_MEAS_DONE   0x20 /*!<For proximity sensor, when the number of measurements reaches the set count of measurements, an interrupt will be generated. */\n#define TOUCH_LL_INTR_MASK_ALL               0x3F /*!<All touch interrupt type enable. */\n#else\n#define TOUCH_LL_INTR_MASK_ALL               0x1F /*!<All touch interrupt type enable. */\n#endif\n\n#define TOUCH_LL_READ_RAW           0x0\n#define TOUCH_LL_READ_BENCHMARK     0x2\n#define TOUCH_LL_READ_SMOOTH        0x3\n\n#define TOUCH_LL_TIMER_FORCE_DONE   0x3\n#define TOUCH_LL_TIMER_DONE         0x0\n\n#define TOUCH_LL_PAD_MEASURE_WAIT_MAX      (0xFF)      // The timer frequency is 8Mhz, the max value is 0xff\n#define TOUCH_LL_ACTIVE_THRESH_MAX         (0x3FFFFF)  // Max channel active threshold\n#define TOUCH_LL_TIMEOUT_MAX               (0x3FFFFF)  // Max timeout value\n\n/**\n * Get the current measure channel. Touch sensor measurement is cyclic scan mode.\n *\n * @return\n *      - touch channel number\n */\n__attribute__((always_inline))\nstatic inline uint32_t touch_ll_get_current_meas_channel(void)\n{\n    return SENS.sar_touch_status0.touch_scan_curr;\n}\n\n/**\n * Get touch sensor measure status. No block.\n *\n * @return\n *      - If touch sensors measure done.\n */\n__attribute__((always_inline))\nstatic inline bool touch_ll_is_measure_done(void)\n{\n    return (bool)SENS.sar_touch_chn_st.touch_meas_done;\n}\n\n/**\n * Enable or disable touch sensor filter and detection algorithm.\n * For more details on the detection algorithm, please refer to the application documentation.\n */\nstatic inline void touch_ll_filter_enable(bool enable)\n{\n    RTCCNTL.touch_filter_ctrl.touch_filter_en = enable;\n}\n\n/**\n * Enable denoise function.\n * T0 is an internal channel that does not have a corresponding external GPIO.\n * T0 will work simultaneously with the measured channel Tn. Finally, the actual\n * measured value of Tn is the value after subtracting lower bits of T0.\n * This denoise function filters out interference introduced on all channels,\n * such as noise introduced by the power supply and external EMI.\n * @param enable  enable the denoise channel\n */\nstatic inline void touch_ll_denoise_enable(bool enable)\n{\n    RTCCNTL.touch_scan_ctrl.touch_denoise_en = enable;\n}\n\n/**\n * Read denoise measure value (TOUCH_PAD_NUM0).\n *\n * @param denoise value of denoise.\n */\nstatic inline void touch_ll_denoise_read_data(uint32_t *data)\n{\n#ifdef SENS_SAR_TOUCH_DENOISE_REG\n    *data =  SENS.sar_touch_denoise.touch_denoise_data;\n#else\n    *data =  SENS.sar_touch_status0.touch_denoise_data;\n#endif\n}\n\n/**\n * Enable parameter of waterproof function.\n *\n * The waterproof function includes a shielded channel (TOUCH_PAD_NUM14) and a guard channel.\n * Guard pad is used to detect the large area of water covering the touch panel.\n * Shield pad is used to shield the influence of water droplets covering the touch panel.\n * It is generally designed as a grid and is placed around the touch buttons.\n * @param enable Enable or disable waterproof function.\n */\nstatic inline void touch_ll_waterproof_enable(bool enable)\n{\n    RTCCNTL.touch_scan_ctrl.touch_shield_pad_en = enable;\n}\n\n/**\n * Enable proximity sensing function for sleep channel.\n */\nstatic inline void touch_ll_sleep_enable_proximity_sensing(bool enable)\n{\n    RTCCNTL.touch_slp_thres.touch_slp_approach_en = enable;\n}\n\n/**\n * Get touch channel number for sleep pad.\n *\n * @note Only one touch sensor channel is supported in deep sleep mode.\n * @param touch_num Touch sensor channel number.\n */\nstatic inline void touch_ll_sleep_get_channel_num(uint32_t *touch_num)\n{\n    *touch_num = RTCCNTL.touch_slp_thres.touch_slp_pad;\n}\n\n/**\n * Set the trigger threshold of touch sensor in deep sleep.\n * The threshold determines the sensitivity of the touch sensor.\n * The threshold is the original value of the trigger state minus the benchmark value.\n *\n * @note In general, the touch threshold during sleep can use the threshold parameter parameters before sleep.\n */\nstatic inline void touch_ll_sleep_set_threshold(uint32_t touch_thres)\n{\n    RTCCNTL.touch_slp_thres.touch_slp_th = touch_thres;\n}\n\nstatic inline void touch_ll_sleep_reset_benchmark(void)\n{\n    RTCCNTL.touch_approach.touch_slp_channel_clr = 1;\n}\n\n/**\n * Set touch channel number for sleep channel.\n *\n * @note Only one touch sensor channel is supported in deep sleep mode.\n * @param touch_num Touch sensor channel number.\n */\nstatic inline void touch_ll_sleep_set_channel_num(uint32_t touch_num)\n{\n    RTCCNTL.touch_slp_thres.touch_slp_pad = touch_num;\n}\n\n/**\n * Set filter mode. The input of the filter is the raw value of touch reading,\n * and the output of the filter is involved in the judgment of the touch state.\n *\n * @param mode Filter mode type. Refer to ``touch_benchmark_filter_mode_t``.\n */\nstatic inline void touch_ll_filter_set_filter_mode(touch_benchmark_filter_mode_t mode)\n{\n    RTCCNTL.touch_filter_ctrl.touch_filter_mode = mode;\n}\n\n/**\n * Set debounce count, such as `n`. If the measured values continue to exceed\n * the threshold for `n+1` times, it is determined that the touch sensor state changes.\n *\n * @param dbc_cnt Debounce count value.\n */\nstatic inline void touch_ll_filter_set_debounce(uint32_t dbc_cnt)\n{\n    RTCCNTL.touch_filter_ctrl.touch_debounce = dbc_cnt;\n}\n\n/**\n * Set jitter filter step size.\n * If filter mode is jitter, should set filter step for jitter.\n * Range: 0 ~ 15\n *\n * @param step The step size of the data change.\n */\nstatic inline void touch_ll_filter_set_jitter_step(uint32_t step)\n{\n    RTCCNTL.touch_filter_ctrl.touch_jitter_step = step;\n}\n\n/**\n * Set filter mode. The input to the filter is raw data and the output is the smooth data.\n * The smooth data is used to determine the touch status.\n *\n * @param mode Filter mode type. Refer to ``touch_smooth_filter_mode_t``.\n */\nstatic inline void touch_ll_filter_set_smooth_mode(touch_smooth_filter_mode_t mode)\n{\n    RTCCNTL.touch_filter_ctrl.touch_smooth_lvl = mode;\n}\n\n/**\n * Set max equivalent capacitance for shield channel.\n * The equivalent capacitance of the shielded channel can be calculated\n * from the reading of denoise channel.\n *\n * @param pad_num Touch sensor channel number. Refer to ``touch_chan_shield_cap_t``\n */\nstatic inline void touch_ll_waterproof_set_shield_driver(touch_chan_shield_cap_t driver_level)\n{\n    RTCCNTL.touch_scan_ctrl.touch_bufdrv = driver_level;\n}\n\n/******************************************************************************/\n/*                                Legacy APIs                                 */\n/******************************************************************************/\n\n/**\n * Set touch sensor touch sensor times of charge and discharge.\n *\n * @param meas_timers The times of charge and discharge in each measure process of touch channels.\n *                     The timer frequency is 8Mhz. Range: 0 ~ 0xffff.\n */\nstatic inline void touch_ll_set_meas_times(uint16_t meas_time)\n{\n    //The times of charge and discharge in each measure process of touch channels.\n    HAL_FORCE_MODIFY_U32_REG_FIELD(RTCCNTL.touch_ctrl1, touch_meas_num, meas_time);\n    //the waiting cycles (in 8MHz) between TOUCH_START and TOUCH_XPD\n    HAL_FORCE_MODIFY_U32_REG_FIELD(RTCCNTL.touch_ctrl2, touch_xpd_wait, TOUCH_LL_PAD_MEASURE_WAIT_MAX); //wait volt stable\n}\n\n/**\n * Get touch sensor times of charge and discharge.\n *\n * @param meas_times Pointer to accept times count of charge and discharge.\n */\nstatic inline void touch_ll_get_measure_times(uint16_t *meas_time)\n{\n    *meas_time = HAL_FORCE_READ_U32_REG_FIELD(RTCCNTL.touch_ctrl1, touch_meas_num);\n}\n\n/**\n * Set touch sensor sleep time.\n *\n * @param sleep_cycle  The touch sensor will sleep after each measurement.\n *                     sleep_cycle decide the interval between each measurement.\n *                     t_sleep = sleep_cycle / (RTC_SLOW_CLK frequency).\n *                     The approximate frequency value of RTC_SLOW_CLK can be obtained using rtc_clk_slow_freq_get_hz function.\n */\nstatic inline void touch_ll_set_sleep_time(uint16_t sleep_time)\n{\n    // touch sensor sleep cycle Time = sleep_cycle / RTC_SLOW_CLK(150k)\n    HAL_FORCE_MODIFY_U32_REG_FIELD(RTCCNTL.touch_ctrl1, touch_sleep_cycles, sleep_time);\n}\n\n/**\n * Get touch sensor sleep time.\n *\n * @param sleep_cycle  Pointer to accept sleep cycle number.\n */\nstatic inline void touch_ll_get_sleep_time(uint16_t *sleep_time)\n{\n    *sleep_time = HAL_FORCE_READ_U32_REG_FIELD(RTCCNTL.touch_ctrl1, touch_sleep_cycles);\n}\n\n/**\n * Set touch sensor high voltage threshold of charge.\n * The touch sensor measures the channel capacitance value by charging and discharging the channel.\n * So the high threshold should be less than the supply voltage.\n *\n * @param refh The high voltage threshold of charge.\n */\nstatic inline void touch_ll_set_voltage_high(touch_high_volt_t refh)\n{\n    RTCCNTL.touch_ctrl2.touch_drefh = refh;\n}\n\n/**\n * Get touch sensor high voltage threshold of charge.\n * The touch sensor measures the channel capacitance value by charging and discharging the channel.\n * So the high threshold should be less than the supply voltage.\n *\n * @param refh The high voltage threshold of charge.\n */\nstatic inline void touch_ll_get_voltage_high(touch_high_volt_t *refh)\n{\n    *refh = (touch_high_volt_t)RTCCNTL.touch_ctrl2.touch_drefh;\n}\n\n/**\n * Set touch sensor low voltage threshold of discharge.\n * The touch sensor measures the channel capacitance value by charging and discharging the channel.\n *\n * @param refl The low voltage threshold of discharge.\n */\nstatic inline void touch_ll_set_voltage_low(touch_low_volt_t refl)\n{\n    RTCCNTL.touch_ctrl2.touch_drefl = refl;\n}\n\n/**\n * Get touch sensor low voltage threshold of discharge.\n * The touch sensor measures the channel capacitance value by charging and discharging the channel.\n *\n * @param refl The low voltage threshold of discharge.\n */\nstatic inline void touch_ll_get_voltage_low(touch_low_volt_t *refl)\n{\n    *refl = (touch_low_volt_t)RTCCNTL.touch_ctrl2.touch_drefl;\n}\n\n/**\n * Set touch sensor high voltage attenuation of charge. The actual charge threshold is high voltage threshold minus attenuation value.\n * The touch sensor measures the channel capacitance value by charging and discharging the channel.\n * So the high threshold should be less than the supply voltage.\n *\n * @param refh The high voltage threshold of charge.\n */\nstatic inline void touch_ll_set_voltage_attenuation(touch_volt_atten_t atten)\n{\n    RTCCNTL.touch_ctrl2.touch_drange = atten;\n}\n\n/**\n * Get touch sensor high voltage attenuation of charge. The actual charge threshold is high voltage threshold minus attenuation value.\n * The touch sensor measures the channel capacitance value by charging and discharging the channel.\n * So the high threshold should be less than the supply voltage.\n *\n * @param refh The high voltage threshold of charge.\n */\nstatic inline void touch_ll_get_voltage_attenuation(touch_volt_atten_t *atten)\n{\n    *atten = (touch_volt_atten_t)RTCCNTL.touch_ctrl2.touch_drange;\n}\n\n/**\n * Set touch sensor charge/discharge speed(currents) for each pad.\n *        If the slope is 0, the counter would always be zero.\n *        If the slope is 1, the charging and discharging would be slow. The measurement time becomes longer.\n *        If the slope is set 7, which is the maximum value, the charging and discharging would be fast.\n *        The measurement time becomes shorter.\n *\n * @note The higher the charge and discharge current, the greater the immunity of the touch channel,\n *       but it will increase the system power consumption.\n * @param touch_num Touch pad index.\n * @param slope touch pad charge/discharge speed(currents).\n */\nstatic inline void touch_ll_set_slope(touch_pad_t touch_num, touch_cnt_slope_t slope)\n{\n#ifdef RTC_CNTL_TOUCH_DAC_REG\n#define PAD_SLOP_MASK(val, num) ((val) << (29 - (num) * 3))\n    uint32_t curr_slop = 0;\n    if (touch_num < TOUCH_PAD_NUM10) {\n        curr_slop = RTCCNTL.touch_dac.val;\n        curr_slop &= ~PAD_SLOP_MASK(0x07, touch_num);  // clear the old value\n        RTCCNTL.touch_dac.val = curr_slop | PAD_SLOP_MASK(slope, touch_num);\n    } else {\n        curr_slop = RTCCNTL.touch_dac1.val;\n        curr_slop &= ~PAD_SLOP_MASK(0x07, touch_num - TOUCH_PAD_NUM10);  // clear the old value\n        RTCCNTL.touch_dac1.val = curr_slop | PAD_SLOP_MASK(slope, touch_num - TOUCH_PAD_NUM10);\n    }\n#undef PAD_SLOP_MASK\n#else\n#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0))\n    RTCIO.touch_pad[touch_num].slope = slope;\n#else\n    RTCIO.touch_pad[touch_num].dac = slope;\n#endif\n#endif\n}\n\n/**\n * Get touch sensor charge/discharge speed(currents) for each pad.\n *        If the slope is 0, the counter would always be zero.\n *        If the slope is 1, the charging and discharging would be slow. The measurement time becomes longer.\n *        If the slope is set 7, which is the maximum value, the charging and discharging would be fast.\n *        The measurement time becomes shorter.\n *\n * @param touch_num Touch pad index.\n * @param slope touch pad charge/discharge speed(currents).\n */\nstatic inline void touch_ll_get_slope(touch_pad_t touch_num, touch_cnt_slope_t *slope)\n{\n#ifdef RTC_CNTL_TOUCH_DAC_REG\n    if (touch_num < TOUCH_PAD_NUM10) {\n        *slope = (touch_cnt_slope_t)((RTCCNTL.touch_dac.val >> (29 - touch_num * 3)) & 0x07);\n    } else {\n        *slope = (touch_cnt_slope_t)((RTCCNTL.touch_dac1.val >> (29 - (touch_num - TOUCH_PAD_NUM10) * 3)) & 0x07);\n    }\n#else\n#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0))\n    *slope = (touch_cnt_slope_t)RTCIO.touch_pad[touch_num].slope;\n#else\n    *slope = (touch_cnt_slope_t)RTCIO.touch_pad[touch_num].dac;\n#endif\n#endif\n}\n\n/**\n * Set initial voltage state of touch channel for each measurement.\n *\n * @param touch_num Touch pad index.\n * @param opt Initial voltage state.\n */\nstatic inline void touch_ll_set_tie_option(touch_pad_t touch_num, touch_tie_opt_t opt)\n{\n    if (opt == TOUCH_PAD_TIE_OPT_FLOAT) {\n        RTCIO.touch_pad[touch_num].xpd = 0;\n    } else {\n        RTCIO.touch_pad[touch_num].xpd = 1;\n        RTCIO.touch_pad[touch_num].tie_opt = opt;\n    }\n}\n\n/**\n * Get initial voltage state of touch channel for each measurement.\n *\n * @param touch_num Touch pad index.\n * @param opt Initial voltage state.\n */\nstatic inline void touch_ll_get_tie_option(touch_pad_t touch_num, touch_tie_opt_t *opt)\n{\n    if (RTCIO.touch_pad[touch_num].xpd) {\n        *opt = (touch_tie_opt_t)RTCIO.touch_pad[touch_num].tie_opt;\n    } else {\n        *opt = TOUCH_PAD_TIE_OPT_FLOAT;\n    }\n}\n\n/**\n * Set touch sensor FSM mode.\n *        The measurement action can be triggered by the hardware timer, as well as by the software instruction.\n *\n * @param mode FSM mode.\n */\n__attribute__((always_inline))\nstatic inline void touch_ll_set_fsm_mode(touch_fsm_mode_t mode)\n{\n    RTCCNTL.touch_ctrl2.touch_start_force = mode;\n}\n\n/**\n * Get touch sensor FSM mode.\n *        The measurement action can be triggered by the hardware timer, as well as by the software instruction.\n *\n * @param mode FSM mode.\n */\nstatic inline void touch_ll_get_fsm_mode(touch_fsm_mode_t *mode)\n{\n    *mode = (touch_fsm_mode_t)RTCCNTL.touch_ctrl2.touch_start_force;\n}\n\n/**\n * Enable/disable clock gate of touch sensor.\n *\n * @param enable true/false.\n */\nstatic inline void touch_ll_clkgate(bool enable)\n{\n    RTCCNTL.touch_ctrl2.touch_clkgate_en = enable; //enable touch clock for FSM. or force enable.\n}\n\n/**\n * Get touch sensor FSM state.\n * @return\n *          - true: fsm state is open.\n *          - false: fsm state is close.\n */\nstatic inline bool touch_ll_clkgate_get_state(void)\n{\n    return RTCCNTL.touch_ctrl2.touch_clkgate_en;\n}\n\n/**\n * Touch timer trigger measurement and always wait measurement done.\n * Force done for touch timer ensures that the timer always can get the measurement done signal.\n */\nstatic inline void touch_ll_timer_force_done(void)\n{\n    RTCCNTL.touch_ctrl2.touch_timer_force_done = TOUCH_LL_TIMER_FORCE_DONE;\n    RTCCNTL.touch_ctrl2.touch_timer_force_done = TOUCH_LL_TIMER_DONE;\n}\n\n/**\n * Start touch sensor FSM timer.\n *        The measurement action can be triggered by the hardware timer, as well as by the software instruction.\n */\nstatic inline void touch_ll_start_fsm(void)\n{\n    /**\n     * Touch timer trigger measurement and always wait measurement done.\n     * Force done for touch timer ensures that the timer always can get the measurement done signal.\n     */\n    RTCCNTL.touch_ctrl2.touch_timer_force_done = TOUCH_LL_TIMER_FORCE_DONE;\n    RTCCNTL.touch_ctrl2.touch_timer_force_done = TOUCH_LL_TIMER_DONE;\n    RTCCNTL.touch_ctrl2.touch_slp_timer_en = (RTCCNTL.touch_ctrl2.touch_start_force == TOUCH_FSM_MODE_TIMER ? 1 : 0);\n}\n\n/**\n * Stop touch sensor FSM timer.\n *        The measurement action can be triggered by the hardware timer, as well as by the software instruction.\n */\n__attribute__((always_inline))\nstatic inline void touch_ll_stop_fsm(void)\n{\n    RTCCNTL.touch_ctrl2.touch_start_en = 0; //stop touch fsm\n    RTCCNTL.touch_ctrl2.touch_slp_timer_en = 0;\n    RTCCNTL.touch_ctrl2.touch_timer_force_done = TOUCH_LL_TIMER_FORCE_DONE;\n    RTCCNTL.touch_ctrl2.touch_timer_force_done = TOUCH_LL_TIMER_DONE;\n}\n\n/**\n * Get touch sensor FSM timer state.\n * @return\n *     - true: FSM enabled\n *     - false: FSM disabled\n */\nstatic inline bool touch_ll_get_fsm_state(void)\n{\n    return (bool)RTCCNTL.touch_ctrl2.touch_slp_timer_en;\n}\n\n/**\n * Trigger a touch sensor measurement, only support in SW mode of FSM.\n */\nstatic inline void touch_ll_start_sw_meas(void)\n{\n    RTCCNTL.touch_ctrl2.touch_start_en = 1;\n    RTCCNTL.touch_ctrl2.touch_start_en = 0;\n}\n\n/**\n * Set the trigger threshold of touch sensor.\n * The threshold determines the sensitivity of the touch sensor.\n * The threshold is the original value of the trigger state minus the benchmark value.\n *\n * @note  If set \"TOUCH_PAD_THRESHOLD_MAX\", the touch is never be triggered.\n * @param touch_num touch pad index\n * @param threshold threshold of touch sensor.\n */\nstatic inline void touch_ll_set_threshold(touch_pad_t touch_num, uint32_t threshold)\n{\n    HAL_ASSERT(touch_num > 0);\n    SENS.touch_thresh[touch_num - 1].thresh = threshold;\n}\n\n/**\n * Get the trigger threshold of touch sensor.\n * The threshold determines the sensitivity of the touch sensor.\n * The threshold is the original value of the trigger state minus the benchmark value.\n *\n * @param touch_num touch pad index.\n * @param threshold pointer to accept threshold.\n */\nstatic inline void touch_ll_get_threshold(touch_pad_t touch_num, uint32_t *threshold)\n{\n    HAL_ASSERT(touch_num > 0);\n    *threshold = SENS.touch_thresh[touch_num - 1].thresh;\n}\n\n/**\n * Enable touch sensor channel. Register touch channel into touch sensor measurement group.\n * The working mode of the touch sensor is simultaneous measurement.\n * This function will set the measure bits according to the given bitmask.\n *\n * @note  If set this mask, the FSM timer should be stop firsty.\n * @note  The touch sensor that in scan map, should be deinit GPIO function firstly.\n * @param enable_mask bitmask of touch sensor scan group.\n *        e.g. TOUCH_PAD_NUM1 -> BIT(1)\n * @return\n *      - ESP_OK on success\n */\nstatic inline void touch_ll_set_channel_mask(uint16_t enable_mask)\n{\n    RTCCNTL.touch_scan_ctrl.touch_scan_pad_map  |= (enable_mask & TOUCH_PAD_BIT_MASK_ALL);\n    SENS.sar_touch_conf.touch_outen |= (enable_mask & TOUCH_PAD_BIT_MASK_ALL);\n}\n\n/**\n * Get touch sensor channel mask.\n *\n * @param enable_mask bitmask of touch sensor scan group.\n *        e.g. TOUCH_PAD_NUM1 -> BIT(1)\n */\nstatic inline void touch_ll_get_channel_mask(uint16_t *enable_mask)\n{\n    *enable_mask = SENS.sar_touch_conf.touch_outen \\\n                   & RTCCNTL.touch_scan_ctrl.touch_scan_pad_map \\\n                   & TOUCH_PAD_BIT_MASK_ALL;\n}\n\n/**\n * Disable touch sensor channel by bitmask.\n *\n * @param enable_mask bitmask of touch sensor scan group.\n *        e.g. TOUCH_PAD_NUM1 -> BIT(1)\n */\nstatic inline void touch_ll_clear_channel_mask(uint16_t disable_mask)\n{\n    SENS.sar_touch_conf.touch_outen &= ~(disable_mask & TOUCH_PAD_BIT_MASK_ALL);\n    RTCCNTL.touch_scan_ctrl.touch_scan_pad_map  &= ~(disable_mask & TOUCH_PAD_BIT_MASK_ALL);\n}\n\n/**\n * Get the touch sensor trigger status, usually used in ISR to decide which pads are 'touched'.\n *\n * @param status_mask The touch sensor status. e.g. Touch1 trigger status is `status_mask & (BIT1)`.\n */\nstatic inline void touch_ll_read_trigger_status_mask(uint32_t *status_mask)\n{\n    *status_mask = SENS.sar_touch_chn_st.touch_pad_active;\n}\n\n/**\n * Clear all touch sensor status.\n *\n * @note Generally no manual removal is required.\n */\nstatic inline void touch_ll_clear_trigger_status_mask(void)\n{\n    SENS.sar_touch_conf.touch_status_clr = 1;\n}\n\n/**\n * Get touch sensor raw data (touch sensor counter value) from register. No block.\n *\n * @param touch_num touch pad index.\n * @return touch_value pointer to accept touch sensor value.\n */\nstatic inline uint32_t IRAM_ATTR touch_ll_read_raw_data(touch_pad_t touch_num)\n{\n    SENS.sar_touch_conf.touch_data_sel = TOUCH_LL_READ_RAW;\n    HAL_ASSERT(touch_num > 0);\n    return SENS.sar_touch_status[touch_num - 1].touch_pad_data;\n}\n\n/**\n * Reset the whole of touch module.\n *\n * @note Call this function after `touch_pad_fsm_stop`.\n */\nstatic inline void touch_ll_reset(void)\n{\n    RTCCNTL.touch_ctrl2.touch_reset = 0;\n    RTCCNTL.touch_ctrl2.touch_reset = 1;\n    RTCCNTL.touch_ctrl2.touch_reset = 0;    // Should be set 0.\n}\n\n/**\n * Set connection type of touch channel in idle status.\n *        When a channel is in measurement mode, other initialized channels are in idle mode.\n *        The touch channel is generally adjacent to the trace, so the connection state of the idle channel\n *        affects the stability and sensitivity of the test channel.\n *        The `CONN_HIGHZ`(high resistance) setting increases the sensitivity of touch channels.\n *        The `CONN_GND`(grounding) setting increases the stability of touch channels.\n *\n * @param type  Select idle channel connect to high resistance state or ground.\n */\nstatic inline void touch_ll_set_idle_channel_connect(touch_pad_conn_type_t type)\n{\n    RTCCNTL.touch_scan_ctrl.touch_inactive_connection = type;\n}\n\n/**\n * Set connection type of touch channel in idle status.\n *        When a channel is in measurement mode, other initialized channels are in idle mode.\n *        The touch channel is generally adjacent to the trace, so the connection state of the idle channel\n *        affects the stability and sensitivity of the test channel.\n *        The `CONN_HIGHZ`(high resistance) setting increases the sensitivity of touch channels.\n *        The `CONN_GND`(grounding) setting increases the stability of touch channels.\n *\n * @param type  Select idle channel connect to high resistance state or ground.\n */\nstatic inline void touch_ll_get_idle_channel_connect(touch_pad_conn_type_t *type)\n{\n    *type = (touch_pad_conn_type_t)(RTCCNTL.touch_scan_ctrl.touch_inactive_connection);\n}\n\n#ifdef RTC_CNTL_INT_ENA_W1TS_REG\n\n/**\n * Enable touch sensor interrupt by bitmask.\n *\n * @param type interrupt type\n */\nstatic inline void touch_ll_intr_enable(touch_pad_intr_mask_t int_mask)\n{\n    if (int_mask & TOUCH_LL_INTR_MASK_DONE) {\n        RTCCNTL.int_ena_w1ts.rtc_touch_done_w1ts = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_ACTIVE) {\n        RTCCNTL.int_ena_w1ts.rtc_touch_active_w1ts = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_INACTIVE) {\n        RTCCNTL.int_ena_w1ts.rtc_touch_inactive_w1ts = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_SCAN_DONE) {\n        RTCCNTL.int_ena_w1ts.rtc_touch_scan_done_w1ts = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_TIMEOUT) {\n        RTCCNTL.int_ena_w1ts.rtc_touch_timeout_w1ts = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_PROXI_MEAS_DONE) {\n        RTCCNTL.int_ena_w1ts.rtc_touch_approach_loop_done_w1ts = 1;\n    }\n}\n\n/**\n * Disable touch sensor interrupt by bitmask.\n *\n * @param type interrupt type\n */\nstatic inline void touch_ll_intr_disable(touch_pad_intr_mask_t int_mask)\n{\n    if (int_mask & TOUCH_LL_INTR_MASK_DONE) {\n        RTCCNTL.int_ena_w1tc.rtc_touch_done_w1tc = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_ACTIVE) {\n        RTCCNTL.int_ena_w1tc.rtc_touch_active_w1tc = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_INACTIVE) {\n        RTCCNTL.int_ena_w1tc.rtc_touch_inactive_w1tc = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_SCAN_DONE) {\n        RTCCNTL.int_ena_w1tc.rtc_touch_scan_done_w1tc = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_TIMEOUT) {\n        RTCCNTL.int_ena_w1tc.rtc_touch_timeout_w1tc = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_PROXI_MEAS_DONE) {\n        RTCCNTL.int_ena_w1tc.rtc_touch_approach_loop_done_w1tc = 1;\n    }\n}\n\n/**\n * Clear touch sensor interrupt by bitmask.\n *\n * @param int_mask Pad mask to clear interrupts\n */\nstatic inline void touch_ll_intr_clear(touch_pad_intr_mask_t int_mask)\n{\n    if (int_mask & TOUCH_LL_INTR_MASK_DONE) {\n        RTCCNTL.int_clr.rtc_touch_done = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_ACTIVE) {\n        RTCCNTL.int_clr.rtc_touch_active = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_INACTIVE) {\n        RTCCNTL.int_clr.rtc_touch_inactive = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_SCAN_DONE) {\n        RTCCNTL.int_clr.rtc_touch_scan_done = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_TIMEOUT) {\n        RTCCNTL.int_clr.rtc_touch_timeout = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_PROXI_MEAS_DONE) {\n        RTCCNTL.int_clr.rtc_touch_approach_loop_done = 1;\n    }\n}\n\n/**\n * Get the bitmask of touch sensor interrupt status.\n *\n * @return type interrupt type\n */\nstatic inline uint32_t touch_ll_read_intr_status_mask(void)\n{\n    typeof(RTCCNTL.int_st) intr_st;\n    intr_st.val = RTCCNTL.int_st.val;\n    uint32_t intr_msk = 0;\n\n    if (intr_st.rtc_touch_done) {\n        intr_msk |= TOUCH_LL_INTR_MASK_DONE;\n    }\n    if (intr_st.rtc_touch_active) {\n        intr_msk |= TOUCH_LL_INTR_MASK_ACTIVE;\n    }\n    if (intr_st.rtc_touch_inactive) {\n        intr_msk |= TOUCH_LL_INTR_MASK_INACTIVE;\n    }\n    if (intr_st.rtc_touch_scan_done) {\n        intr_msk |= TOUCH_LL_INTR_MASK_SCAN_DONE;\n    }\n    if (intr_st.rtc_touch_timeout) {\n        intr_msk |= TOUCH_LL_INTR_MASK_TIMEOUT;\n    }\n    if (intr_st.rtc_touch_approach_loop_done) {\n        intr_msk |= TOUCH_LL_INTR_MASK_PROXI_MEAS_DONE;\n    }\n    return (intr_msk & TOUCH_LL_INTR_MASK_ALL);\n}\n\n#else\n\n/**\n * Enable touch sensor interrupt by bitmask.\n *\n * @param type interrupt type\n */\nstatic inline void touch_ll_intr_enable(touch_pad_intr_mask_t int_mask)\n{\n    if (int_mask & TOUCH_LL_INTR_MASK_DONE) {\n        RTCCNTL.int_ena.rtc_touch_done = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_ACTIVE) {\n        RTCCNTL.int_ena.rtc_touch_active = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_INACTIVE) {\n        RTCCNTL.int_ena.rtc_touch_inactive = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_SCAN_DONE) {\n        RTCCNTL.int_ena.rtc_touch_scan_done = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_TIMEOUT) {\n        RTCCNTL.int_ena.rtc_touch_timeout = 1;\n    }\n}\n\n/**\n * Disable touch sensor interrupt by bitmask.\n *\n * @param type interrupt type\n */\nstatic inline void touch_ll_intr_disable(uint32_t int_mask)\n{\n    if (int_mask & TOUCH_LL_INTR_MASK_DONE) {\n        RTCCNTL.int_ena.rtc_touch_done = 0;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_ACTIVE) {\n        RTCCNTL.int_ena.rtc_touch_active = 0;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_INACTIVE) {\n        RTCCNTL.int_ena.rtc_touch_inactive = 0;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_SCAN_DONE) {\n        RTCCNTL.int_ena.rtc_touch_scan_done = 0;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_TIMEOUT) {\n        RTCCNTL.int_ena.rtc_touch_timeout = 0;\n    }\n}\n\n/**\n * Clear touch sensor interrupt by bitmask.\n *\n * @param int_mask Pad mask to clear interrupts\n */\nstatic inline void touch_ll_intr_clear(touch_pad_intr_mask_t int_mask)\n{\n    if (int_mask & TOUCH_LL_INTR_MASK_DONE) {\n        RTCCNTL.int_clr.rtc_touch_done = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_ACTIVE) {\n        RTCCNTL.int_clr.rtc_touch_active = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_INACTIVE) {\n        RTCCNTL.int_clr.rtc_touch_inactive = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_SCAN_DONE) {\n        RTCCNTL.int_clr.rtc_touch_scan_done = 1;\n    }\n    if (int_mask & TOUCH_LL_INTR_MASK_TIMEOUT) {\n        RTCCNTL.int_clr.rtc_touch_timeout = 1;\n    }\n}\n\n/**\n * Get the bitmask of touch sensor interrupt status.\n *\n * @return type interrupt type\n */\nstatic inline uint32_t touch_ll_read_intr_status_mask(void)\n{\n    typeof(RTCCNTL.int_st) intr_st;\n    intr_st.val = RTCCNTL.int_st.val;\n    uint32_t intr_msk = 0;\n\n    if (intr_st.rtc_touch_done) {\n        intr_msk |= TOUCH_LL_INTR_MASK_DONE;\n    }\n    if (intr_st.rtc_touch_active) {\n        intr_msk |= TOUCH_LL_INTR_MASK_ACTIVE;\n    }\n    if (intr_st.rtc_touch_inactive) {\n        intr_msk |= TOUCH_LL_INTR_MASK_INACTIVE;\n    }\n    if (intr_st.rtc_touch_scan_done) {\n        intr_msk |= TOUCH_LL_INTR_MASK_SCAN_DONE;\n    }\n    if (intr_st.rtc_touch_timeout) {\n        intr_msk |= TOUCH_LL_INTR_MASK_TIMEOUT;\n    }\n    return (intr_msk & TOUCH_LL_INTR_MASK_ALL);\n}\n\n#endif\n\n/**\n * Enable the timeout check for all touch sensor channels measurements.\n * When the touch reading of a touch channel exceeds the measurement threshold,\n * If enable: a timeout interrupt will be generated and it will go to the next channel measurement.\n * If disable: the FSM is always on the channel, until the measurement of this channel is over.\n *\n * @note Set the timeout threshold correctly before enabling it.\n */\nstatic inline void touch_ll_timeout_enable(void)\n{\n    RTCCNTL.touch_timeout_ctrl.touch_timeout_en = 1;\n}\n\n/**\n * Disable the timeout check for all touch sensor channels measurements.\n * When the touch reading of a touch channel exceeds the measurement threshold,\n * If enable: a timeout interrupt will be generated and it will go to the next channel measurement.\n * If disable: the FSM is always on the channel, until the measurement of this channel is over.\n *\n * @note Set the timeout threshold correctly before enabling it.\n */\nstatic inline void touch_ll_timeout_disable(void)\n{\n    RTCCNTL.touch_timeout_ctrl.touch_timeout_en = 0;\n}\n\n/**\n * Set timeout threshold for all touch sensor channels measurements.\n * Compared with touch readings.\n *\n * @param threshold Set to the maximum time measured on one channel.\n */\nstatic inline void touch_ll_timeout_set_threshold(uint32_t threshold)\n{\n    RTCCNTL.touch_timeout_ctrl.touch_timeout_num = threshold;\n}\n\n/**\n * Get timeout threshold for all touch sensor channels measurements.\n * Compared with touch readings.\n *\n * @param threshold Point to timeout threshold.\n */\nstatic inline void touch_ll_timeout_get_threshold(uint32_t *threshold)\n{\n    *threshold = RTCCNTL.touch_timeout_ctrl.touch_timeout_num;\n}\n\n/************************ Filter register setting ************************/\n\n/**\n * Get smoothed data that obtained by filtering the raw data.\n *\n * @param touch_num touch pad index\n * @param smooth_data pointer to smoothed data\n */\nstatic inline void IRAM_ATTR touch_ll_filter_read_smooth(touch_pad_t touch_num, uint32_t *smooth_data)\n{\n    SENS.sar_touch_conf.touch_data_sel = TOUCH_LL_READ_SMOOTH;\n    HAL_ASSERT(touch_num > 0);\n    *smooth_data = SENS.sar_touch_status[touch_num - 1].touch_pad_data;\n}\n\n/**\n * Get benchmark value of touch sensor.\n *\n * @note After initialization, the benchmark value is the maximum during the first measurement period.\n * @param touch_num touch pad index\n * @param touch_value pointer to accept touch sensor value\n */\nstatic inline void IRAM_ATTR touch_ll_read_benchmark(touch_pad_t touch_num, uint32_t *benchmark)\n{\n    SENS.sar_touch_conf.touch_data_sel = TOUCH_LL_READ_BENCHMARK;\n    HAL_ASSERT(touch_num > 0);\n    *benchmark = SENS.sar_touch_status[touch_num - 1].touch_pad_data;\n}\n\n/**\n * Force reset benchmark to raw data of touch sensor.\n *\n * @note If call this API, make sure enable clock gate(`touch_ll_clkgate`) first.\n * @param touch_num touch pad index\n *                  - TOUCH_PAD_MAX Reset baseline of all channels.\n */\nstatic inline void touch_ll_reset_benchmark(touch_pad_t touch_num)\n{\n    /* Clear touch channels to initialize the channel value (benchmark, raw_data).\n     */\n    if (touch_num == TOUCH_PAD_MAX) {\n        SENS.sar_touch_chn_st.touch_channel_clr = TOUCH_PAD_BIT_MASK_ALL;\n    } else {\n        SENS.sar_touch_chn_st.touch_channel_clr = (1U << touch_num);\n    }\n}\n\n/**\n * Get filter mode. The input of the filter is the raw value of touch reading,\n * and the output of the filter is involved in the judgment of the touch state.\n *\n * @param mode Filter mode type. Refer to ``touch_filter_mode_t``.\n */\nstatic inline void touch_ll_filter_get_filter_mode(touch_filter_mode_t *mode)\n{\n    *mode = (touch_filter_mode_t)RTCCNTL.touch_filter_ctrl.touch_filter_mode;\n}\n\n/**\n * Get filter mode. The smooth data is used to determine the touch status.\n *\n * @param mode Filter mode type. Refer to ``touch_smooth_mode_t``.\n */\nstatic inline void touch_ll_filter_get_smooth_mode(touch_smooth_mode_t *mode)\n{\n    *mode = (touch_smooth_mode_t)(RTCCNTL.touch_filter_ctrl.touch_smooth_lvl);\n}\n\n/**\n * Get debounce count.\n *\n * @param dbc_cnt Debounce count value.\n */\nstatic inline void touch_ll_filter_get_debounce(uint32_t *dbc_cnt)\n{\n    *dbc_cnt = RTCCNTL.touch_filter_ctrl.touch_debounce;\n}\n\n/**\n * Set noise threshold coefficient. Higher = More noise resistance.\n * The actual noise should be less than (noise coefficient * touch threshold).\n * Range: 0 ~ 3. The coefficient is 0: 4/8;  1: 3/8;   2: 2/8;   3: 1;\n *\n * @param hys_thr Noise threshold coefficient.\n */\nstatic inline void touch_ll_filter_set_noise_thres(uint32_t noise_thr)\n{\n    RTCCNTL.touch_filter_ctrl.touch_noise_thres = noise_thr;\n    RTCCNTL.touch_filter_ctrl.config2 = noise_thr;\n    RTCCNTL.touch_filter_ctrl.config1 = 0xF;\n    RTCCNTL.touch_filter_ctrl.config3 = 2;\n}\n\n/**\n * Get noise threshold coefficient. Higher = More noise resistance.\n * The actual noise should be less than (noise coefficient * touch threshold).\n * Range: 0 ~ 3. The coefficient is 0: 4/8;  1: 3/8;   2: 2/8;   3: 1;\n *\n * @param noise_thr Noise threshold coefficient.\n */\nstatic inline void touch_ll_filter_get_noise_thres(uint32_t *noise_thr)\n{\n    *noise_thr = RTCCNTL.touch_filter_ctrl.touch_noise_thres;\n}\n\n/**\n * Get jitter filter step size.\n * If filter mode is jitter, should set filter step for jitter.\n * Range: 0 ~ 15\n *\n * @param step The step size of the data change.\n */\nstatic inline void touch_ll_filter_get_jitter_step(uint32_t *step)\n{\n    *step = RTCCNTL.touch_filter_ctrl.touch_jitter_step;\n}\n\n/************************ Denoise register setting ************************/\n\n/**\n * Set internal reference capacitance of denoise channel.\n * Select the appropriate internal reference capacitance value so that\n * the reading of denoise channel is closest to the reading of the channel being measured.\n *\n * @param cap_level Capacitance level.\n */\nstatic inline void touch_ll_denoise_set_cap_level(touch_pad_denoise_cap_t cap_level)\n{\n    RTCCNTL.touch_ctrl2.touch_refc = cap_level;\n}\n\n/**\n * Get internal reference capacitance of denoise channel.\n * Select the appropriate internal reference capacitance value so that\n * the reading of denoise channel is closest to the reading of the channel being measured.\n *\n * @param cap_level Capacitance level.\n */\nstatic inline void touch_ll_denoise_get_cap_level(touch_pad_denoise_cap_t *cap_level)\n{\n    *cap_level = (touch_pad_denoise_cap_t)(RTCCNTL.touch_ctrl2.touch_refc);\n}\n\n/**\n * Set denoise range of denoise channel.\n * Determined by measuring the noise amplitude of the denoise channel.\n *\n * @param grade Denoise range of denoise channel.\n */\nstatic inline void touch_ll_denoise_set_grade(touch_pad_denoise_grade_t grade)\n{\n    RTCCNTL.touch_scan_ctrl.touch_denoise_res = grade;\n}\n\n/**\n * Set denoise range of denoise channel.\n * Determined by measuring the noise amplitude of the denoise channel.\n *\n * @param grade Denoise range of denoise channel.\n */\nstatic inline void touch_ll_denoise_get_grade(touch_pad_denoise_grade_t *grade)\n{\n    *grade = (touch_pad_denoise_grade_t)(RTCCNTL.touch_scan_ctrl.touch_denoise_res);\n}\n\n/************************ Waterproof register setting ************************/\n\n/**\n * Set touch channel use for guard pad.\n *\n * @param pad_num Touch sensor channel number.\n */\nstatic inline void touch_ll_waterproof_set_guard_pad(touch_pad_t pad_num)\n{\n    RTCCNTL.touch_scan_ctrl.touch_out_ring = pad_num;\n}\n\n/**\n * Get touch channel use for guard pad.\n *\n * @param pad_num Touch sensor channel number.\n */\nstatic inline void touch_ll_waterproof_get_guard_pad(touch_pad_t *pad_num)\n{\n    *pad_num = (touch_pad_t)(RTCCNTL.touch_scan_ctrl.touch_out_ring);\n}\n\n/**\n * Get max equivalent capacitance for shield channel.\n * The equivalent capacitance of the shielded channel can be calculated\n * from the reading of denoise channel.\n *\n * @param pad_num Touch sensor channel number.\n */\nstatic inline void touch_ll_waterproof_get_shield_driver(touch_pad_shield_driver_t *driver_level)\n{\n    *driver_level = (touch_pad_shield_driver_t)(RTCCNTL.touch_scan_ctrl.touch_bufdrv);\n}\n\n/************************ Proximity register setting ************************/\n\n/**\n * Set touch channel number for proximity pad.\n * If disable the proximity pad, point this pad to `TOUCH_PAD_NUM0`\n *\n * @param prox_pad The array of three proximity pads.\n */\nstatic inline void touch_ll_proximity_set_channel_num(const touch_pad_t prox_pad[])\n{\n    SENS.sar_touch_conf.touch_approach_pad0 = prox_pad[0];\n    SENS.sar_touch_conf.touch_approach_pad1 = prox_pad[1];\n    SENS.sar_touch_conf.touch_approach_pad2 = prox_pad[2];\n}\n\n/**\n * Get touch channel number for proximity pad.\n * If disable the proximity pad, point this pad to `TOUCH_PAD_NUM0`\n *\n * @param prox_pad The array of three proximity pads.\n */\nstatic inline void touch_ll_proximity_get_channel_num(touch_pad_t prox_pad[])\n{\n    prox_pad[0] = (touch_pad_t)(SENS.sar_touch_conf.touch_approach_pad0);\n    prox_pad[1] = (touch_pad_t)(SENS.sar_touch_conf.touch_approach_pad1);\n    prox_pad[2] = (touch_pad_t)(SENS.sar_touch_conf.touch_approach_pad2);\n}\n\n/**\n * Set cumulative measurement times for proximity pad.\n *\n * @param times The cumulative number of measurement cycles.\n */\nstatic inline void touch_ll_proximity_set_meas_times(uint32_t times)\n{\n    HAL_FORCE_MODIFY_U32_REG_FIELD(RTCCNTL.touch_approach, touch_approach_meas_time, times);\n}\n\n/**\n * Get cumulative measurement times for proximity pad.\n *\n * @param times The cumulative number of measurement cycles.\n */\nstatic inline void touch_ll_proximity_get_meas_times(uint32_t *times)\n{\n    *times = HAL_FORCE_READ_U32_REG_FIELD(RTCCNTL.touch_approach, touch_approach_meas_time);\n}\n\n/**\n * Read current cumulative measurement times for proximity pad.\n *\n * @param times The cumulative number of measurement cycles.\n */\nstatic inline void touch_ll_proximity_read_meas_cnt(touch_pad_t touch_num, uint32_t *cnt)\n{\n    if (SENS.sar_touch_conf.touch_approach_pad0 == touch_num) {\n        *cnt = HAL_FORCE_READ_U32_REG_FIELD(SENS.sar_touch_appr_status, touch_approach_pad0_cnt);\n    } else if (SENS.sar_touch_conf.touch_approach_pad1 == touch_num) {\n        *cnt = HAL_FORCE_READ_U32_REG_FIELD(SENS.sar_touch_appr_status, touch_approach_pad1_cnt);\n    } else if (SENS.sar_touch_conf.touch_approach_pad2 == touch_num) {\n        *cnt = HAL_FORCE_READ_U32_REG_FIELD(SENS.sar_touch_appr_status, touch_approach_pad2_cnt);\n    }\n}\n\n/**\n * Check if the touch sensor channel is the proximity pad.\n *\n * @param touch_num The touch sensor channel number.\n */\nstatic inline bool touch_ll_proximity_pad_check(touch_pad_t touch_num)\n{\n    if ((SENS.sar_touch_conf.touch_approach_pad0 != touch_num)\n            && (SENS.sar_touch_conf.touch_approach_pad1 != touch_num)\n            && (SENS.sar_touch_conf.touch_approach_pad2 != touch_num)) {\n        return false;\n    } else {\n        return true;\n    }\n}\n\n/************** sleep pad setting ***********************/\n/**\n * Get the trigger threshold of touch sensor in deep sleep.\n * The threshold determines the sensitivity of the touch sensor.\n * The threshold is the original value of the trigger state minus the benchmark value.\n *\n * @note In general, the touch threshold during sleep can use the threshold parameter parameters before sleep.\n */\nstatic inline void touch_ll_sleep_get_threshold(uint32_t *touch_thres)\n{\n    *touch_thres = RTCCNTL.touch_slp_thres.touch_slp_th;\n}\n\n/**\n * Get proximity function status for sleep pad.\n */\nstatic inline bool touch_ll_sleep_is_proximity_enabled(void)\n{\n    return (bool)RTCCNTL.touch_slp_thres.touch_slp_approach_en;\n}\n\n/**\n * Read benchmark of touch sensor for sleep pad.\n *\n * @param benchmark Pointer to accept touch sensor benchmark value.\n */\nstatic inline void touch_ll_sleep_read_benchmark(uint32_t *benchmark)\n{\n    SENS.sar_touch_conf.touch_data_sel = TOUCH_LL_READ_BENCHMARK;\n    *benchmark = SENS.sar_touch_slp_status.touch_slp_data;\n}\n\nstatic inline void touch_ll_sleep_read_smooth(uint32_t *smooth_data)\n{\n    SENS.sar_touch_conf.touch_data_sel = TOUCH_LL_READ_SMOOTH;\n    *smooth_data = SENS.sar_touch_slp_status.touch_slp_data;\n}\n\n/* Workaround: Note: sleep pad raw data is not in `sar_touch_slp_status` */\nstatic inline void touch_ll_sleep_read_data(uint32_t *raw_data)\n{\n    uint32_t touch_num = RTCCNTL.touch_slp_thres.touch_slp_pad;\n    SENS.sar_touch_conf.touch_data_sel = TOUCH_LL_READ_RAW;\n    HAL_ASSERT(touch_num > 0);\n    *raw_data = SENS.sar_touch_status[touch_num - 1].touch_pad_data;\n}\n\n/**\n * Get the data of the touch channel according to the types\n *\n * @param sample_cfg_id The sample configuration index\n * @param type  data type\n *              0/1: TOUCH_LL_READ_RAW, the raw data of the touch channel\n *              2:   TOUCH_LL_READ_BENCHMARK, benchmark value of touch channel,\n *                   the benchmark value is the maximum during the first measurement period\n *              3:   TOUCH_LL_READ_SMOOTH, the smoothed data that obtained by filtering the raw data.\n * @param smooth_data pointer to smoothed data\n */\n__attribute__((always_inline))\nstatic inline void touch_ll_sleep_read_chan_data(uint8_t type, uint32_t *data)\n{\n    SENS.sar_touch_conf.touch_data_sel = type;\n    if (type == TOUCH_LL_READ_RAW) {\n        uint32_t touch_num = RTCCNTL.touch_slp_thres.touch_slp_pad;\n        HAL_ASSERT(touch_num > 0);\n        *data = SENS.sar_touch_status[touch_num - 1].touch_pad_data;\n    } else {\n        *data = SENS.sar_touch_slp_status.touch_slp_data;\n    }\n}\n\n\n/**\n * Select touch sensor dbias to save power in sleep mode.\n *\n * @note If change the dbias, the reading of touch sensor will changed. Users should make sure the threshold.\n */\nstatic inline void touch_ll_sleep_low_power(bool is_low_power)\n{\n    RTCCNTL.touch_ctrl2.touch_dbias = is_low_power;\n}\n\n/**\n * Read debounce of touch sensor for sleep pad.\n *\n * @param debounce Pointer to accept touch sensor debounce value.\n */\nstatic inline void touch_ll_sleep_read_debounce(uint32_t *debounce)\n{\n    *debounce = SENS.sar_touch_slp_status.touch_slp_debounce;\n}\n\n/**\n * Read proximity count of touch sensor for sleep pad.\n * @param prox_cnt Pointer to accept touch sensor proximity count value.\n */\nstatic inline void touch_ll_sleep_read_proximity_cnt(uint32_t *prox_cnt)\n{\n    *prox_cnt = HAL_FORCE_READ_U32_REG_FIELD(SENS.sar_touch_appr_status, touch_slp_approach_cnt);\n}\n\n/**\n * Get the touch pad which caused wakeup from deep sleep.\n *\n * @param pad_num pointer to touch pad which caused wakeup.\n */\nstatic inline void touch_ll_get_wakeup_status(touch_pad_t *pad_num)\n{\n    *pad_num = (touch_pad_t)RTCCNTL.touch_slp_thres.touch_slp_pad;\n}\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "touch_element/include/touch_element/touch_button.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n#pragma once\n\n#include \"touch_element/touch_element.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n/* --------------------------------- General button instance default configuration  --------------------------------- */\n#define TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG()                                  \\\n{                                                                             \\\n    .threshold_divider = 0.8,                                                 \\\n    .default_lp_time = 1000                                                   \\\n}\n/* ------------------------------------------------------------------------------------------------------------------ */\n\n/**\n * @brief   Button initialization configuration passed to touch_button_install\n */\ntypedef struct {\n    float threshold_divider;        //!< Button channel threshold divider\n    uint32_t default_lp_time;       //!< Button default LongPress event time (ms)\n} touch_button_global_config_t;\n\n/**\n * @brief   Button configuration (for new instance) passed to touch_button_create()\n */\ntypedef struct {\n    touch_pad_t channel_num;     //!< Button channel number (index)\n    float channel_sens;          //!< Button channel sensitivity\n} touch_button_config_t;\n\n/**\n * @brief   Button event type\n */\ntypedef enum {\n    TOUCH_BUTTON_EVT_ON_PRESS,         //!< Button Press event\n    TOUCH_BUTTON_EVT_ON_RELEASE,       //!< Button Release event\n    TOUCH_BUTTON_EVT_ON_LONGPRESS,     //!< Button LongPress event\n    TOUCH_BUTTON_EVT_MAX\n} touch_button_event_t;\n\n/**\n * @brief   Button message type\n */\ntypedef struct {\n    touch_button_event_t event;        //!< Button event\n} touch_button_message_t;\n\ntypedef touch_elem_handle_t touch_button_handle_t;      //!< Button handle\ntypedef void(*touch_button_callback_t)(touch_button_handle_t, touch_button_message_t *, void *); //!< Button callback type\n\n/**\n * @brief   Touch Button initialize\n *\n * This function initializes touch button global and acts on all\n * touch button instances.\n *\n * @param[in] global_config   Button object initialization configuration\n *\n * @return\n *      - ESP_OK: Successfully initialized touch button\n *      - ESP_ERR_INVALID_STATE: Touch element library was not initialized\n *      - ESP_ERR_INVALID_ARG: button_init is NULL\n *      - ESP_ERR_NO_MEM: Insufficient memory\n */\nesp_err_t touch_button_install(const touch_button_global_config_t *global_config);\n\n/**\n * @brief   Release resources allocated using touch_button_install()\n */\nvoid touch_button_uninstall(void);\n\n/**\n * @brief   Create a new touch button instance\n *\n * @param[in]  button_config    Button configuration\n * @param[out] button_handle    Button handle\n *\n * @note    The sensitivity has to be explored in experiments,\n *          Sensitivity = (Raw(touch) - Raw(release)) / Raw(release) * 100%\n *\n * @return\n *      - ESP_OK: Successfully create touch button\n *      - ESP_ERR_INVALID_STATE: Touch button driver was not initialized\n *      - ESP_ERR_NO_MEM: Insufficient memory\n *      - ESP_ERR_INVALID_ARG: Invalid configuration struct or arguments is NULL\n */\nesp_err_t touch_button_create(const touch_button_config_t *button_config, touch_button_handle_t *button_handle);\n\n/**\n * @brief Release resources allocated using touch_button_create()\n *\n * @param[in] button_handle   Button handle\n * @return\n *      - ESP_OK: Successfully released resources\n *      - ESP_ERR_INVALID_STATE: Touch button driver was not initialized\n *      - ESP_ERR_INVALID_ARG: button_handle is null\n *      - ESP_ERR_NOT_FOUND: Input handle is not a button handle\n */\nesp_err_t touch_button_delete(touch_button_handle_t button_handle);\n\n/**\n * @brief   Touch button subscribes event\n *\n * This function uses event mask to subscribe to touch button events, once one of\n * the subscribed events occurs, the event message could be retrieved by calling\n * touch_element_message_receive() or input callback routine.\n *\n * @param[in] button_handle     Button handle\n * @param[in] event_mask        Button subscription event mask\n * @param[in] arg               User input argument\n *\n * @note    Touch button only support three kind of event masks, they are\n *          TOUCH_ELEM_EVENT_ON_PRESS, TOUCH_ELEM_EVENT_ON_RELEASE, TOUCH_ELEM_EVENT_ON_LONGPRESS.\n *          You can use those event masks in any combination to achieve the desired effect.\n *\n * @return\n *      - ESP_OK: Successfully subscribed touch button event\n *      - ESP_ERR_INVALID_STATE: Touch button driver was not initialized\n *      - ESP_ERR_INVALID_ARG: button_handle is null or event is not supported\n */\nesp_err_t touch_button_subscribe_event(touch_button_handle_t button_handle, uint32_t event_mask, void *arg);\n\n/**\n * @brief   Touch button set dispatch method\n *\n * This function sets a dispatch method that the driver core will use\n * this method as the event notification method.\n *\n * @param[in] button_handle     Button handle\n * @param[in] dispatch_method   Dispatch method (By callback/event)\n *\n * @return\n *      - ESP_OK: Successfully set dispatch method\n *      - ESP_ERR_INVALID_STATE: Touch button driver was not initialized\n *      - ESP_ERR_INVALID_ARG: button_handle is null or dispatch_method is invalid\n */\nesp_err_t touch_button_set_dispatch_method(touch_button_handle_t button_handle, touch_elem_dispatch_t dispatch_method);\n\n/**\n * @brief   Touch button set callback\n *\n * This function sets a callback routine into touch element driver core,\n * when the subscribed events occur, the callback routine will be called.\n *\n * @param[in] button_handle     Button handle\n * @param[in] button_callback   User input callback\n *\n * @note        Button message will be passed from the callback function and it will be destroyed when the callback function return.\n *\n * @warning     Since this input callback routine runs on driver core (esp-timer callback routine),\n *              it should not do something that attempts to Block, such as calling vTaskDelay().\n *\n * @return\n *      - ESP_OK: Successfully set callback\n *      - ESP_ERR_INVALID_STATE: Touch button driver was not initialized\n *      - ESP_ERR_INVALID_ARG: button_handle or button_callback is null\n */\nesp_err_t touch_button_set_callback(touch_button_handle_t button_handle, touch_button_callback_t button_callback);\n\n/**\n * @brief   Touch button set long press trigger time\n *\n * This function sets the threshold time (ms) for a long press event. If a button is pressed\n * and held for a period of time that exceeds the threshold time, a long press event is triggered.\n *\n * @param[in] button_handle     Button handle\n * @param[in] threshold_time    Threshold time (ms) of long press event occur\n *\n * @return\n *      - ESP_OK: Successfully set the threshold time of long press event\n *      - ESP_ERR_INVALID_STATE: Touch button driver was not initialized\n *      - ESP_ERR_INVALID_ARG: button_handle is null or time (ms) is not lager than 0\n */\nesp_err_t touch_button_set_longpress(touch_button_handle_t button_handle, uint32_t threshold_time);\n\n/**\n * @brief   Touch button get message\n *\n * This function decodes the element message from touch_element_message_receive() and return\n * a button message pointer.\n *\n * @param[in] element_message   element message\n *\n * @return  Touch button message pointer\n */\nconst touch_button_message_t *touch_button_get_message(const touch_elem_message_t *element_message);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "touch_element/include/touch_element/touch_element.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2016-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include \"touch_sensor_legacy_types.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* -------------------------------- General hardware & system default configuration  -------------------------------- */\n/* Since those are important hardware and algorithm parameters, user should not change them before knowing all details*/\n/* ------------------------------------------------------------------------------------------------------------------ */\n#define TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG()                                    \\\n{                                                                             \\\n    .hardware = {                                                             \\\n        .upper_voltage = TOUCH_HVOLT_2V7,                                     \\\n        .voltage_attenuation = TOUCH_HVOLT_ATTEN_0V5,                         \\\n        .lower_voltage = TOUCH_LVOLT_0V5,                                     \\\n        .suspend_channel_polarity = TOUCH_PAD_CONN_HIGHZ,                     \\\n        .denoise_level = TOUCH_PAD_DENOISE_BIT4,                              \\\n        .denoise_equivalent_cap = TOUCH_PAD_DENOISE_CAP_L0,                   \\\n        .smooth_filter_mode = TOUCH_PAD_SMOOTH_IIR_2,                         \\\n        .benchmark_filter_mode = TOUCH_PAD_FILTER_IIR_16,                     \\\n        .sample_count = 500,                                                  \\\n        .sleep_cycle = 0xf,                                                   \\\n        .benchmark_debounce_count = 2,                                        \\\n        .benchmark_calibration_threshold = 2,                                 \\\n        .benchmark_jitter_step = 5                                            \\\n    },                                                                        \\\n    .software = {                                                             \\\n        .waterproof_threshold_divider = 0.8,                                  \\\n        .processing_period = 10,                                              \\\n        .intr_message_size = 14,                                              \\\n        .event_message_size = 20                                              \\\n    }                                                                         \\\n}\n/* ------------------------------------------------------------------------------------------------------------------ */\n\n/* ---------------------------------------------- Event subscription  ----------------------------------------------- */\n#define TOUCH_ELEM_EVENT_NONE                       BIT(0)      //!< None event\n#define TOUCH_ELEM_EVENT_ON_PRESS                   BIT(1)      //!< On Press event\n#define TOUCH_ELEM_EVENT_ON_RELEASE                 BIT(2)      //!< On Release event\n#define TOUCH_ELEM_EVENT_ON_LONGPRESS               BIT(3)      //!< On LongPress event\n#define TOUCH_ELEM_EVENT_ON_CALCULATION             BIT(4)      //!< On Calculation event\n/* ------------------------------------------------------------------------------------------------------------------ */\n#define TOUCH_WATERPROOF_GUARD_NOUSE       (0)         //!< Waterproof no use guard sensor\n/* -------------------------------- Global hardware & software configuration struct --------------------------------- */\n/**\n * @brief   Touch element software configuration\n */\ntypedef struct {\n    float waterproof_threshold_divider;        //!< Waterproof guard channel threshold divider\n    uint8_t processing_period;                 //!< Processing period(ms)\n    uint8_t intr_message_size;                 //!< Interrupt message queue size\n    uint8_t event_message_size;                //!< Event message queue size\n} touch_elem_sw_config_t;\n\n/**\n * @brief   Touch element hardware configuration\n */\ntypedef struct {\n    touch_high_volt_t upper_voltage;                  //!< Touch sensor channel upper charge voltage\n    touch_volt_atten_t voltage_attenuation;           //!< Touch sensor channel upper charge voltage attenuation (Diff voltage is upper - attenuation - lower)\n    touch_low_volt_t lower_voltage;                   //!< Touch sensor channel lower charge voltage\n    touch_pad_conn_type_t suspend_channel_polarity;   //!< Suspend channel polarity (High Impedance State or GND)\n    touch_pad_denoise_grade_t denoise_level;          //!< Internal de-noise level\n    touch_pad_denoise_cap_t denoise_equivalent_cap;   //!< Internal de-noise channel (Touch channel 0) equivalent capacitance\n    touch_smooth_mode_t smooth_filter_mode;           //!< Smooth value filter mode (This only apply to touch_pad_filter_read_smooth())\n    touch_filter_mode_t benchmark_filter_mode;        //!< Benchmark filter mode\n    uint16_t sample_count;                            //!< The count of sample in each measurement of touch sensor\n    uint16_t sleep_cycle;                             //!< The cycle (RTC slow clock) of sleep\n    uint8_t benchmark_debounce_count;                 //!< Benchmark debounce count\n    uint8_t benchmark_calibration_threshold;          //!< Benchmark calibration threshold\n    uint8_t benchmark_jitter_step;                    //!< Benchmark jitter filter step (This only works at while benchmark filter mode is jitter filter)\n} touch_elem_hw_config_t;\n\n/**\n * @brief   Touch element global configuration passed to touch_element_install\n */\ntypedef struct {\n    touch_elem_hw_config_t hardware;         //!< Hardware configuration\n    touch_elem_sw_config_t software;         //!< Software configuration\n} touch_elem_global_config_t;\n\n/**\n * @brief   Touch element waterproof configuration passed to touch_element_waterproof_install\n */\ntypedef struct {\n    touch_pad_t guard_channel;     //!< Waterproof Guard-Sensor channel number (index)\n    float guard_sensitivity;       //!< Waterproof Guard-Sensor sensitivity\n} touch_elem_waterproof_config_t;\n\n/**\n * @brief   Touch element sleep configuration passed to touch_element_enable_light_sleep or touch_element_enable_deep_sleep\n*/\ntypedef struct {\n    uint16_t sample_count;                     //!< scan times in every measurement, normally equal to the 'sample_count' field in 'touch_elem_hw_config_t'.\n    uint16_t sleep_cycle;                    //!< sleep_cycle decide the interval between two measurements， t_sleep = sleep_cycle / (RTC_SLOW_CLK frequency), normally equal to the 'sleep_cycle' field in 'touch_elem_hw_config_t'.\n} touch_elem_sleep_config_t;\n/* ------------------------------------------------------------------------------------------------------------------ */\ntypedef void *touch_elem_handle_t;        //!< Touch element handle type\ntypedef uint32_t touch_elem_event_t;      //!< Touch element event type\n\n/**\n * @brief   Touch element handle type\n */\ntypedef enum {\n    TOUCH_ELEM_TYPE_BUTTON,         //!< Touch element button\n    TOUCH_ELEM_TYPE_SLIDER,         //!< Touch element slider\n    TOUCH_ELEM_TYPE_MATRIX,         //!< Touch element matrix button\n} touch_elem_type_t;\n\n/**\n * @brief   Touch element event dispatch methods (event queue/callback)\n */\ntypedef enum {\n    TOUCH_ELEM_DISP_EVENT,           //!< Event queue dispatch\n    TOUCH_ELEM_DISP_CALLBACK,        //!< Callback dispatch\n    TOUCH_ELEM_DISP_MAX\n} touch_elem_dispatch_t;\n\n/**\n * @brief   Touch element event message type from touch_element_message_receive()\n */\ntypedef struct {\n    touch_elem_handle_t handle;             //!< Touch element handle\n    touch_elem_type_t element_type;         //!< Touch element type\n    void *arg;                              //!< User input argument\n    uint8_t child_msg[8];                   //!< Encoded message\n} touch_elem_message_t;\n/* ------------------------------------------------------------------------------------------------------------------ */\n\n/**\n * @brief   Touch element processing initialization\n *\n * @param[in]   global_config   Global initialization configuration structure\n *\n * @note    To reinitialize the touch element object, call touch_element_uninstall() first\n *\n * @return\n *      - ESP_OK: Successfully initialized\n *      - ESP_ERR_INVALID_ARG: Invalid argument\n *      - ESP_ERR_NO_MEM: Insufficient memory\n *      - ESP_ERR_INVALID_STATE: Touch element is already initialized\n *      - Others: Unknown touch driver layer or lower layer error\n */\nesp_err_t touch_element_install(const touch_elem_global_config_t *global_config);\n\n/**\n * @brief   Touch element processing start\n *\n * This function starts the touch element processing system\n *\n * @note    This function must only be called after all the touch element instances finished creating\n *\n * @return\n *      - ESP_OK: Successfully started to process\n *      - Others: Unknown touch driver layer or lower layer error\n */\nesp_err_t touch_element_start(void);\n\n/**\n * @brief   Touch element processing stop\n *\n * This function stops the touch element processing system\n *\n * @note    This function must be called before changing the system (hardware, software) parameters\n *\n * @return\n *      - ESP_OK: Successfully stopped to process\n *      - Others: Unknown touch driver layer or lower layer error\n */\nesp_err_t touch_element_stop(void);\n\n/**\n * @brief   Release resources allocated using touch_element_install\n *\n */\nvoid touch_element_uninstall(void);\n\n/**\n * @brief   Get current event message of touch element instance\n *\n * This function will receive the touch element message (handle, event type, etc...)\n * from te_event_give(). It will block until a touch element event or a timeout occurs.\n *\n * @param[out]  element_message          Touch element event message structure\n * @param[in]   ticks_to_wait   Number of FreeRTOS ticks to block for waiting event\n * @return\n *      - ESP_OK: Successfully received touch element event\n *      - ESP_ERR_INVALID_STATE: Touch element library is not initialized\n *      - ESP_ERR_INVALID_ARG: element_message is null\n *      - ESP_ERR_TIMEOUT: Timed out waiting for event\n */\nesp_err_t touch_element_message_receive(touch_elem_message_t *element_message, uint32_t ticks_to_wait);\n\n/**\n * @brief   Touch element waterproof initialization\n *\n * This function enables the hardware waterproof, then touch element system uses Shield-Sensor\n * and Guard-Sensor to mitigate the influence of water-drop and water-stream.\n *\n * @param[in] waterproof_config     Waterproof configuration\n *\n * @note    If the waterproof function is used, Shield-Sensor can not be disabled and it will use channel 14 as\n *          it's internal channel. Hence, the user can not use channel 14 for another propose. And the Guard-Sensor\n *          is not necessary since it is optional.\n *\n * @note    Shield-Sensor: It always uses channel 14 as the shield channel, so user must connect\n *          the channel 14 and Shield-Layer in PCB since it will generate a synchronous signal automatically\n *\n * @note    Guard-Sensor: This function is optional. If used, the user must connect the guard channel and Guard-Ring\n *          in PCB. Any channels user wants to protect should be added into Guard-Ring in PCB.\n *\n * @return\n *      - ESP_OK: Successfully initialized\n *      - ESP_ERR_INVALID_STATE: Touch element library is not initialized\n *      - ESP_ERR_INVALID_ARG: waterproof_config is null or invalid Guard-Sensor channel\n *      - ESP_ERR_NO_MEM: Insufficient memory\n */\nesp_err_t touch_element_waterproof_install(const touch_elem_waterproof_config_t *waterproof_config);\n\n/**\n * @brief   Release resources allocated using touch_element_waterproof_install()\n */\nvoid touch_element_waterproof_uninstall(void);\n\n/**\n * @brief   Add a masked handle to protect while Guard-Sensor has been triggered\n *\n * This function will add an application handle (button, slider, etc...) as a masked handle. While Guard-Sensor\n * has been triggered, waterproof function will start working and lock the application internal state. While the\n * influence of water is reduced, the application will be unlock and reset into IDLE state.\n *\n * @param[in] element_handle     Touch element instance handle\n *\n * @note    The waterproof protection logic must follow the real circuit in PCB, it means that all of the channels\n *          inside the input handle must be inside the Guard-Ring in real circuit.\n *\n * @return\n *      - ESP_OK: Successfully added a masked handle\n *      - ESP_ERR_INVALID_STATE: Waterproof is not initialized\n *      - ESP_ERR_INVALID_ARG: element_handle is null\n */\nesp_err_t touch_element_waterproof_add(touch_elem_handle_t element_handle);\n\n/**\n * @brief   Remove a masked handle to protect\n *\n * This function will remove an application handle from masked handle table.\n *\n * @param[in] element_handle     Touch element instance handle\n *\n * @return\n *      - ESP_OK: Successfully removed a masked handle\n *      - ESP_ERR_INVALID_STATE: Waterproof is not initialized\n *      - ESP_ERR_INVALID_ARG: element_handle is null\n *      - ESP_ERR_NOT_FOUND: Failed to search element_handle from waterproof mask_handle list\n */\nesp_err_t touch_element_waterproof_remove(touch_elem_handle_t element_handle);\n\n/**\n * @brief   Touch element light sleep initialization\n *\n * @note    It should be called after touch button element installed.\n *          Any of installed touch element can wake up from the light sleep\n *\n * @param[in] sleep_config Sleep configurations, set NULL to use default config\n * @return\n *      - ESP_OK: Successfully initialized touch sleep\n *      - ESP_ERR_INVALID_STATE: Touch element is not installed or touch sleep has been installed\n *      - ESP_ERR_INVALID_ARG: inputted argument is NULL\n *      - ESP_ERR_NO_MEM: no memory for touch sleep struct\n *      - ESP_ERR_NOT_SUPPORTED: inputted wakeup_elem_handle is not touch_button_handle_t type, currently only touch_button_handle_t supported\n */\nesp_err_t touch_element_enable_light_sleep(const touch_elem_sleep_config_t *sleep_config);\n\n/**\n * @brief   Release the resources that allocated by touch_element_enable_deep_sleep()\n *\n * This function will also disable the touch sensor to wake up the device\n *\n * @return\n *      - ESP_OK: uninstall success\n *      - ESP_ERR_INVALID_STATE: touch sleep has not been installed\n */\nesp_err_t touch_element_disable_light_sleep(void);\n\n/**\n * @brief   Touch element deep sleep initialization\n *\n * This function will enable the device wake-up from deep sleep or light sleep by touch sensor\n *\n * @note    It should be called after touch button element installed.\n *          Only one touch button can be registered as the deep sleep wake-up button\n *\n * @param[in] wakeup_elem_handle    Touch element instance handle for waking up the device, only support button element\n * @param[in] sleep_config          Sleep configurations, set NULL to use default config\n *\n * @return\n *      - ESP_OK: Successfully initialized touch sleep\n *      - ESP_ERR_INVALID_STATE: Touch element is not installed or touch sleep has been installed\n *      - ESP_ERR_INVALID_ARG: inputted argument is NULL\n *      - ESP_ERR_NO_MEM: no memory for touch sleep struct\n *      - ESP_ERR_NOT_SUPPORTED: inputted wakeup_elem_handle is not touch_button_handle_t type, currently only touch_button_handle_t supported\n */\nesp_err_t touch_element_enable_deep_sleep(touch_elem_handle_t wakeup_elem_handle, const touch_elem_sleep_config_t *sleep_config);\n\n/**\n * @brief   Release the resources that allocated by touch_element_enable_deep_sleep()\n *\n * This function will also disable the touch sensor to wake up the device\n *\n * @return\n *      - ESP_OK: uninstall success\n *      - ESP_ERR_INVALID_STATE: touch sleep has not been installed\n */\nesp_err_t touch_element_disable_deep_sleep(void);\n\n/**\n * @brief   Touch element wake up calibrations\n *\n * This function will also disable the touch sensor to wake up the device\n *\n * @return\n *      - ESP_OK: uninstall success\n *      - ESP_ERR_INVALID_STATE: touch sleep has not been installed\n */\nesp_err_t touch_element_sleep_enable_wakeup_calibration(touch_elem_handle_t element_handle, bool en);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "touch_element/include/touch_element/touch_matrix.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include \"touch_element/touch_element.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* ----------------------------- General matrix button instance default configuration  ------------------------------ */\n#define TOUCH_MATRIX_GLOBAL_DEFAULT_CONFIG()                                  \\\n{                                                                             \\\n    .threshold_divider = 0.8,                                                 \\\n    .default_lp_time = 1000                                                   \\\n}\n/* ------------------------------------------------------------------------------------------------------------------ */\n/**\n * @brief   Matrix button initialization configuration passed to touch_matrix_install\n */\ntypedef struct {\n    float threshold_divider;        //!< Matrix button channel threshold divider\n    uint32_t default_lp_time;       //!< Matrix button default LongPress event time (ms)\n} touch_matrix_global_config_t;\n\n/**\n * @brief   Matrix button configuration (for new instance) passed to touch_matrix_create()\n */\ntypedef struct {\n    const touch_pad_t *x_channel_array;      //!< Matrix button x-axis channels array\n    const touch_pad_t *y_channel_array;      //!< Matrix button y-axis channels array\n    const float *x_sensitivity_array;        //!< Matrix button x-axis channels sensitivity array\n    const float *y_sensitivity_array;        //!< Matrix button y-axis channels sensitivity array\n    uint8_t x_channel_num;                   //!< The number of channels in x-axis\n    uint8_t y_channel_num;                   //!< The number of channels in y-axis\n} touch_matrix_config_t;\n\n/**\n * @brief   Matrix button event type\n */\ntypedef enum {\n    TOUCH_MATRIX_EVT_ON_PRESS,            //!< Matrix button Press event\n    TOUCH_MATRIX_EVT_ON_RELEASE,          //!< Matrix button Press event\n    TOUCH_MATRIX_EVT_ON_LONGPRESS,        //!< Matrix button LongPress event\n    TOUCH_MATRIX_EVT_MAX\n} touch_matrix_event_t;\n\n/**\n * @brief   Matrix button position data type\n */\ntypedef struct {\n    uint8_t x_axis;     //!< Matrix button x axis position\n    uint8_t y_axis;     //!< Matrix button y axis position\n    uint8_t index;      //!< Matrix button position index\n} touch_matrix_position_t;\n\n/**\n * @brief   Matrix message type\n */\ntypedef struct {\n    touch_matrix_event_t event;             //!< Matrix event\n    touch_matrix_position_t position;       //!< Matrix position\n} touch_matrix_message_t;\n\ntypedef touch_elem_handle_t touch_matrix_handle_t;  //!< Matrix button instance handle\ntypedef void(*touch_matrix_callback_t)(touch_matrix_handle_t, touch_matrix_message_t *, void *); //!< Matrix button callback type\n\n/**\n * @brief   Touch matrix button initialize\n *\n * This function initializes touch matrix button object and acts on all\n * touch matrix button instances.\n *\n * @param[in] global_config   Touch matrix global initialization configuration\n *\n * @return\n *      - ESP_OK: Successfully initialized touch matrix button\n *      - ESP_ERR_INVALID_STATE: Touch element library was not initialized\n *      - ESP_ERR_INVALID_ARG: matrix_init is NULL\n *      - ESP_ERR_NO_MEM: Insufficient memory\n */\nesp_err_t touch_matrix_install(const touch_matrix_global_config_t *global_config);\n\n/**\n * @brief   Release resources allocated using touch_matrix_install()\n *\n */\nvoid touch_matrix_uninstall(void);\n\n/**\n * @brief   Create a new touch matrix button instance\n *\n * @param[in]  matrix_config    Matrix button configuration\n * @param[out] matrix_handle    Matrix button handle\n *\n * @note    Channel array and sensitivity array must be one-one correspondence in those array\n *\n * @note    Touch matrix button does not support Multi-Touch now\n *\n * @return\n *      - ESP_OK: Successfully create touch matrix button\n *      - ESP_ERR_INVALID_STATE: Touch matrix driver was not initialized\n *      - ESP_ERR_INVALID_ARG: Invalid configuration struct or arguments is NULL\n *      - ESP_ERR_NO_MEM: Insufficient memory\n */\nesp_err_t touch_matrix_create(const touch_matrix_config_t *matrix_config, touch_matrix_handle_t *matrix_handle);\n\n/**\n * @brief   Release resources allocated using touch_matrix_create()\n *\n * @param[in] matrix_handle    Matrix handle\n * @return\n *      - ESP_OK: Successfully released resources\n *      - ESP_ERR_INVALID_STATE: Touch matrix driver was not initialized\n *      - ESP_ERR_INVALID_ARG: matrix_handle is null\n *      - ESP_ERR_NOT_FOUND: Input handle is not a matrix handle\n */\nesp_err_t touch_matrix_delete(touch_matrix_handle_t matrix_handle);\n\n/**\n * @brief   Touch matrix button subscribes event\n *\n * This function uses event mask to subscribe to touch matrix events, once one of\n * the subscribed events occurs, the event message could be retrieved by calling\n * touch_element_message_receive() or input callback routine.\n *\n * @param[in] matrix_handle     Matrix handle\n * @param[in] event_mask        Matrix subscription event mask\n * @param[in] arg               User input argument\n *\n * @note    Touch matrix button only support three kind of event masks, they are\n *          TOUCH_ELEM_EVENT_ON_PRESS, TOUCH_ELEM_EVENT_ON_RELEASE, TOUCH_ELEM_EVENT_ON_LONGPRESS. You can use those event\n *          masks in any combination to achieve the desired effect.\n *\n * @return\n *      - ESP_OK: Successfully subscribed touch matrix event\n *      - ESP_ERR_INVALID_STATE: Touch matrix driver was not initialized\n *      - ESP_ERR_INVALID_ARG: matrix_handle is null or event is not supported\n */\nesp_err_t touch_matrix_subscribe_event(touch_matrix_handle_t matrix_handle, uint32_t event_mask, void *arg);\n\n/**\n * @brief   Touch matrix button set dispatch method\n *\n * This function sets a dispatch method that the driver core will use\n * this method as the event notification method.\n *\n * @param[in] matrix_handle     Matrix button handle\n * @param[in] dispatch_method   Dispatch method (By callback/event)\n *\n * @return\n *      - ESP_OK: Successfully set dispatch method\n *      - ESP_ERR_INVALID_STATE: Touch matrix driver was not initialized\n *      - ESP_ERR_INVALID_ARG: matrix_handle is null or dispatch_method is invalid\n */\nesp_err_t touch_matrix_set_dispatch_method(touch_matrix_handle_t matrix_handle, touch_elem_dispatch_t dispatch_method);\n\n/**\n * @brief   Touch matrix button set callback\n *\n * This function sets a callback routine into touch element driver core,\n * when the subscribed events occur, the callback routine will be called.\n *\n * @param[in] matrix_handle     Matrix button handle\n * @param[in] matrix_callback   User input callback\n *\n * @note        Matrix message will be passed from the callback function and it will be destroyed when the callback function return.\n *\n * @warning     Since this input callback routine runs on driver core (esp-timer callback routine),\n *              it should not do something that attempts to Block, such as calling vTaskDelay().\n *\n * @return\n *      - ESP_OK: Successfully set callback\n *      - ESP_ERR_INVALID_STATE: Touch matrix driver was not initialized\n *      - ESP_ERR_INVALID_ARG: matrix_handle or matrix_callback is null\n */\nesp_err_t touch_matrix_set_callback(touch_matrix_handle_t matrix_handle, touch_matrix_callback_t matrix_callback);\n\n/**\n * @brief   Touch matrix button set long press trigger time\n *\n * This function sets the threshold time (ms) for a long press event. If a matrix button is pressed\n * and held for a period of time that exceeds the threshold time, a long press event is triggered.\n *\n * @param[in] matrix_handle     Matrix button handle\n * @param[in] threshold_time    Threshold time (ms) of long press event occur\n *\n * @return\n *      - ESP_OK: Successfully set the time of long press event\n *      - ESP_ERR_INVALID_STATE: Touch matrix driver was not initialized\n *      - ESP_ERR_INVALID_ARG: matrix_handle is null or time (ms) is 0\n */\nesp_err_t touch_matrix_set_longpress(touch_matrix_handle_t matrix_handle, uint32_t threshold_time);\n\n/**\n * @brief   Touch matrix get message\n *\n * This function decodes the element message from touch_element_message_receive() and return\n * a matrix message pointer.\n *\n * @param[in] element_message   element message\n *\n * @return  Touch matrix message pointer\n */\nconst touch_matrix_message_t *touch_matrix_get_message(const touch_elem_message_t *element_message);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "touch_element/include/touch_element/touch_sensor_legacy_types.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include <stdbool.h>\n#include <stdint.h>\n#include \"esp_attr.h\"\n#include \"esp_bit_defs.h\"\n\n#if __has_include(\"hal/touch_sensor_legacy_types.h\")\n#include \"hal/touch_sensor_legacy_types.h\"\n#include \"esp_idf_version.h\"\n#if IDF_VERSION_MAJOR < 6\ntypedef touch_filter_mode_t touch_benchmark_filter_mode_t;\ntypedef touch_smooth_mode_t touch_smooth_filter_mode_t;\ntypedef touch_pad_shield_driver_t touch_chan_shield_cap_t;\n#endif\n#elif __has_include(\"hal/touch_sensor_types.h\")\n#include \"hal/touch_sensor_types.h\"\ntypedef touch_filter_mode_t touch_benchmark_filter_mode_t;\ntypedef touch_smooth_mode_t touch_smooth_filter_mode_t;\ntypedef touch_pad_shield_driver_t touch_chan_shield_cap_t;\n#else\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** Touch pad channel */\ntypedef enum {\n    TOUCH_PAD_NUM0 = 0, /*!< Internal touch channel */\n    TOUCH_PAD_NUM1,     /*!< Touch channel 1 is GPIO1 */\n    TOUCH_PAD_NUM2,     /*!< Touch channel 2 is GPIO2 */\n    TOUCH_PAD_NUM3,     /*!< Touch channel 3 is GPIO3 */\n    TOUCH_PAD_NUM4,     /*!< Touch channel 4 is GPIO4 */\n    TOUCH_PAD_NUM5,     /*!< Touch channel 5 is GPIO5 */\n    TOUCH_PAD_NUM6,     /*!< Touch channel 6 is GPIO6 */\n    TOUCH_PAD_NUM7,     /*!< Touch channel 7 is GPIO7 */\n    TOUCH_PAD_NUM8,     /*!< Touch channel 8 is GPIO8 */\n    TOUCH_PAD_NUM9,     /*!< Touch channel 9 is GPIO9 */\n    TOUCH_PAD_NUM10,    /*!< Touch channel 10 is GPIO10 */\n    TOUCH_PAD_NUM11,    /*!< Touch channel 11 is GPIO11 */\n    TOUCH_PAD_NUM12,    /*!< Touch channel 12 is GPIO12 */\n    TOUCH_PAD_NUM13,    /*!< Touch channel 13 is GPIO13 */\n    TOUCH_PAD_NUM14,    /*!< Touch channel 14 is GPIO14 */\n    TOUCH_PAD_MAX,\n} touch_pad_t;\n\n/** Touch sensor high reference voltage */\ntypedef enum {\n    TOUCH_HVOLT_KEEP = -1, /*!<Touch sensor high reference voltage, no change  */\n    TOUCH_HVOLT_2V4 = 0,   /*!<Touch sensor high reference voltage, 2.4V  */\n    TOUCH_HVOLT_2V5,       /*!<Touch sensor high reference voltage, 2.5V  */\n    TOUCH_HVOLT_2V6,       /*!<Touch sensor high reference voltage, 2.6V  */\n    TOUCH_HVOLT_2V7,       /*!<Touch sensor high reference voltage, 2.7V  */\n    TOUCH_HVOLT_MAX,\n} touch_high_volt_t;\n\n/** Touch sensor low reference voltage */\ntypedef enum {\n    TOUCH_LVOLT_KEEP = -1, /*!<Touch sensor low reference voltage, no change  */\n    TOUCH_LVOLT_0V5 = 0,   /*!<Touch sensor low reference voltage, 0.5V  */\n    TOUCH_LVOLT_0V6,       /*!<Touch sensor low reference voltage, 0.6V  */\n    TOUCH_LVOLT_0V7,       /*!<Touch sensor low reference voltage, 0.7V  */\n    TOUCH_LVOLT_0V8,       /*!<Touch sensor low reference voltage, 0.8V  */\n    TOUCH_LVOLT_MAX,\n} touch_low_volt_t;\n\n/** Touch sensor high reference voltage attenuation */\ntypedef enum {\n    TOUCH_HVOLT_ATTEN_KEEP = -1,  /*!<Touch sensor high reference voltage attenuation, no change  */\n    TOUCH_HVOLT_ATTEN_1V5 = 0,    /*!<Touch sensor high reference voltage attenuation, 1.5V attenuation  */\n    TOUCH_HVOLT_ATTEN_1V,         /*!<Touch sensor high reference voltage attenuation, 1.0V attenuation  */\n    TOUCH_HVOLT_ATTEN_0V5,        /*!<Touch sensor high reference voltage attenuation, 0.5V attenuation  */\n    TOUCH_HVOLT_ATTEN_0V,         /*!<Touch sensor high reference voltage attenuation,   0V attenuation  */\n    TOUCH_HVOLT_ATTEN_MAX,\n} touch_volt_atten_t;\n\n/** Touch sensor charge/discharge speed */\ntypedef enum {\n    TOUCH_PAD_SLOPE_0 = 0,       /*!<Touch sensor charge / discharge speed, always zero  */\n    TOUCH_PAD_SLOPE_1 = 1,       /*!<Touch sensor charge / discharge speed, slowest  */\n    TOUCH_PAD_SLOPE_2 = 2,       /*!<Touch sensor charge / discharge speed */\n    TOUCH_PAD_SLOPE_3 = 3,       /*!<Touch sensor charge / discharge speed  */\n    TOUCH_PAD_SLOPE_4 = 4,       /*!<Touch sensor charge / discharge speed  */\n    TOUCH_PAD_SLOPE_5 = 5,       /*!<Touch sensor charge / discharge speed  */\n    TOUCH_PAD_SLOPE_6 = 6,       /*!<Touch sensor charge / discharge speed  */\n    TOUCH_PAD_SLOPE_7 = 7,       /*!<Touch sensor charge / discharge speed, fast  */\n    TOUCH_PAD_SLOPE_MAX,\n} touch_cnt_slope_t;\n\n/** Touch sensor initial charge level */\ntypedef enum {\n    TOUCH_PAD_TIE_OPT_LOW = 0,    /*!<Initial level of charging voltage, low level */\n    TOUCH_PAD_TIE_OPT_HIGH = 1,   /*!<Initial level of charging voltage, high level */\n    TOUCH_PAD_TIE_OPT_FLOAT = 2,  /*!<Initial level of charging voltage, float */\n    TOUCH_PAD_TIE_OPT_MAX,        /*!<The max tie options */\n} touch_tie_opt_t;\n\n/** Touch sensor FSM mode */\ntypedef enum {\n    TOUCH_FSM_MODE_TIMER = 0,   /*!<To start touch FSM by timer */\n    TOUCH_FSM_MODE_SW,          /*!<To start touch FSM by software trigger */\n    TOUCH_FSM_MODE_MAX,\n} touch_fsm_mode_t;\n\n/**** ESP32 Only *****/\n\ntypedef enum {\n    TOUCH_TRIGGER_BELOW = 0,   /*!<Touch interrupt will happen if counter value is less than threshold.*/\n    TOUCH_TRIGGER_ABOVE = 1,   /*!<Touch interrupt will happen if counter value is larger than threshold.*/\n    TOUCH_TRIGGER_MAX,\n} touch_trigger_mode_t;\n\ntypedef enum {\n    TOUCH_TRIGGER_SOURCE_BOTH = 0,  /*!< wakeup interrupt is generated if both SET1 and SET2 are \"touched\"*/\n    TOUCH_TRIGGER_SOURCE_SET1 = 1,  /*!< wakeup interrupt is generated if SET1 is \"touched\"*/\n    TOUCH_TRIGGER_SOURCE_MAX,\n} touch_trigger_src_t;\n\n/**\n * @brief Touch sensor shield channel drive capability level\n *\n */\ntypedef enum {\n    TOUCH_SHIELD_CAP_40PF,                  /*!< The max equivalent capacitance in shield channel is 40pf */\n    TOUCH_SHIELD_CAP_80PF,                  /*!< The max equivalent capacitance in shield channel is 80pf */\n    TOUCH_SHIELD_CAP_120PF,                 /*!< The max equivalent capacitance in shield channel is 120pf */\n    TOUCH_SHIELD_CAP_160PF,                 /*!< The max equivalent capacitance in shield channel is 160pf */\n    TOUCH_SHIELD_CAP_200PF,                 /*!< The max equivalent capacitance in shield channel is 200pf */\n    TOUCH_SHIELD_CAP_240PF,                 /*!< The max equivalent capacitance in shield channel is 240pf */\n    TOUCH_SHIELD_CAP_280PF,                 /*!< The max equivalent capacitance in shield channel is 280pf */\n    TOUCH_SHIELD_CAP_320PF,                 /*!< The max equivalent capacitance in shield channel is 320pf */\n} touch_chan_shield_cap_t;\n\n/**\n * @brief Touch channel Infinite Impulse Response (IIR) filter or Jitter filter for benchmark\n * @note Recommended filter coefficient selection is `IIR_16`.\n */\ntypedef enum {\n    TOUCH_BM_IIR_FILTER_4,                  /*!< IIR Filter for benchmark, 1/4 raw_value + 3/4 benchmark */\n    TOUCH_BM_IIR_FILTER_8,                  /*!< IIR Filter for benchmark, 1/8 raw_value + 7/8 benchmark */\n    TOUCH_BM_IIR_FILTER_16,                 /*!< IIR Filter for benchmark, 1/16 raw_value + 15/16 benchmark (typical) */\n    TOUCH_BM_IIR_FILTER_32,                 /*!< IIR Filter for benchmark, 1/32 raw_value + 31/32 benchmark */\n    TOUCH_BM_IIR_FILTER_64,                 /*!< IIR Filter for benchmark, 1/64 raw_value + 63/64 benchmark */\n    TOUCH_BM_IIR_FILTER_128,                /*!< IIR Filter for benchmark, 1/128 raw_value + 127/128 benchmark */\n    TOUCH_BM_IIR_FILTER_256,                /*!< IIR Filter for benchmark, 1/256 raw_value + 255/256 benchmark */\n    TOUCH_BM_JITTER_FILTER,                 /*!< Jitter Filter for benchmark, raw value +/- jitter_step */\n} touch_benchmark_filter_mode_t;\n\n/**\n * @brief Touch channel Infinite Impulse Response (IIR) filter for smooth data\n *\n */\ntypedef enum {\n    TOUCH_SMOOTH_NO_FILTER,                 /*!< No filter adopted for smooth data, smooth data equals raw data */\n    TOUCH_SMOOTH_IIR_FILTER_2,              /*!< IIR filter adopted for smooth data, smooth data equals 1/2 raw data + 1/2 last smooth data (typical) */\n    TOUCH_SMOOTH_IIR_FILTER_4,              /*!< IIR filter adopted for smooth data, smooth data equals 1/4 raw data + 3/4 last smooth data */\n    TOUCH_SMOOTH_IIR_FILTER_8,              /*!< IIR filter adopted for smooth data, smooth data equals 1/8 raw data + 7/8 last smooth data */\n} touch_smooth_filter_mode_t;\n\n\n/********************************/\n#define TOUCH_PAD_BIT_MASK_ALL              (0x7FFF)\n#define TOUCH_PAD_SLOPE_DEFAULT             (TOUCH_PAD_SLOPE_7)\n#define TOUCH_PAD_TIE_OPT_DEFAULT           (TOUCH_PAD_TIE_OPT_FLOAT)\n#define TOUCH_PAD_BIT_MASK_MAX              (TOUCH_PAD_BIT_MASK_ALL)\n#define TOUCH_PAD_HIGH_VOLTAGE_THRESHOLD    (TOUCH_HVOLT_2V7)\n#define TOUCH_PAD_LOW_VOLTAGE_THRESHOLD     (TOUCH_LVOLT_0V5)\n#define TOUCH_PAD_ATTEN_VOLTAGE_THRESHOLD   (TOUCH_HVOLT_ATTEN_0V5)\n#define TOUCH_PAD_IDLE_CH_CONNECT_DEFAULT   (TOUCH_PAD_CONN_GND)\n#define TOUCH_PAD_THRESHOLD_MAX             (0x1FFFFF)  /*!< If set touch threshold max value, The touch sensor can't be in touched status */\n\n/**\n * Excessive total time will slow down the touch response.\n * Too small measurement time will not be sampled enough, resulting in inaccurate measurements.\n *\n * @note The greater the duty cycle of the measurement time, the more system power is consumed.\n */\n#define TOUCH_PAD_SLEEP_CYCLE_DEFAULT   (0xf)   /*!<The number of sleep cycle in each measure process of touch channels.\n                                                    The timer frequency is RTC_SLOW_CLK (can be 150k or 32k depending on the options).\n                                                    Range: 0 ~ 0xffff */\n#define TOUCH_PAD_MEASURE_CYCLE_DEFAULT (500)   /*!<The times of charge and discharge in each measure process of touch channels.\n                                                    The timer frequency is 8Mhz.\n                                                    Recommended typical value: Modify this value to make the measurement time around 1ms.\n                                                    Range: 0 ~ 0xffff */\n\ntypedef uint32_t touch_pad_intr_mask_t;\n\ntypedef enum {\n    TOUCH_PAD_DENOISE_BIT12 = 0,    /*!<Denoise range is 12bit */\n    TOUCH_PAD_DENOISE_BIT10 = 1,    /*!<Denoise range is 10bit */\n    TOUCH_PAD_DENOISE_BIT8 = 2,     /*!<Denoise range is 8bit */\n    TOUCH_PAD_DENOISE_BIT4 = 3,     /*!<Denoise range is 4bit */\n    TOUCH_PAD_DENOISE_MAX\n} touch_pad_denoise_grade_t;\n\ntypedef enum {\n    TOUCH_PAD_DENOISE_CAP_L0 = 0,   /*!<Denoise channel internal reference capacitance is 5pf */\n    TOUCH_PAD_DENOISE_CAP_L1 = 1,   /*!<Denoise channel internal reference capacitance is 6.4pf */\n    TOUCH_PAD_DENOISE_CAP_L2 = 2,   /*!<Denoise channel internal reference capacitance is 7.8pf */\n    TOUCH_PAD_DENOISE_CAP_L3 = 3,   /*!<Denoise channel internal reference capacitance is 9.2pf */\n    TOUCH_PAD_DENOISE_CAP_L4 = 4,   /*!<Denoise channel internal reference capacitance is 10.6pf */\n    TOUCH_PAD_DENOISE_CAP_L5 = 5,   /*!<Denoise channel internal reference capacitance is 12.0pf */\n    TOUCH_PAD_DENOISE_CAP_L6 = 6,   /*!<Denoise channel internal reference capacitance is 13.4pf */\n    TOUCH_PAD_DENOISE_CAP_L7 = 7,   /*!<Denoise channel internal reference capacitance is 14.8pf */\n    TOUCH_PAD_DENOISE_CAP_MAX = 8\n} touch_pad_denoise_cap_t;\n\n/** Touch sensor denoise configuration */\ntypedef struct touch_pad_denoise {\n    touch_pad_denoise_grade_t grade;    /*!<Select denoise range of denoise channel.\n                                            Determined by measuring the noise amplitude of the denoise channel. */\n    touch_pad_denoise_cap_t cap_level;  /*!<Select internal reference capacitance of denoise channel.\n                                            Ensure that the denoise readings are closest to the readings of the channel being measured.\n                                            Use `touch_pad_denoise_read_data` to get the reading of denoise channel.\n                                            The equivalent capacitance of the shielded channel can be calculated\n                                            from the reading of denoise channel. */\n} touch_pad_denoise_t;\n\n/** Touch sensor shield channel drive capability level */\ntypedef enum {\n    TOUCH_PAD_SHIELD_DRV_L0 = 0,/*!<The max equivalent capacitance in shield channel is 40pf */\n    TOUCH_PAD_SHIELD_DRV_L1,    /*!<The max equivalent capacitance in shield channel is 80pf */\n    TOUCH_PAD_SHIELD_DRV_L2,    /*!<The max equivalent capacitance in shield channel is 120pf */\n    TOUCH_PAD_SHIELD_DRV_L3,    /*!<The max equivalent capacitance in shield channel is 160pf */\n    TOUCH_PAD_SHIELD_DRV_L4,    /*!<The max equivalent capacitance in shield channel is 200pf */\n    TOUCH_PAD_SHIELD_DRV_L5,    /*!<The max equivalent capacitance in shield channel is 240pf */\n    TOUCH_PAD_SHIELD_DRV_L6,    /*!<The max equivalent capacitance in shield channel is 280pf */\n    TOUCH_PAD_SHIELD_DRV_L7,    /*!<The max equivalent capacitance in shield channel is 320pf */\n    TOUCH_PAD_SHIELD_DRV_MAX\n} touch_pad_shield_driver_t;\n\n/** Touch sensor waterproof configuration */\ntypedef struct touch_pad_waterproof {\n    touch_pad_t guard_ring_pad;             /*!<Waterproof. Select touch channel use for guard pad.\n                                                Guard pad is used to detect the large area of water covering the touch panel. */\n    touch_pad_shield_driver_t shield_driver;/*!<Waterproof. Shield channel drive capability configuration.\n                                                Shield pad is used to shield the influence of water droplets covering the touch panel.\n                                                When the waterproof function is enabled, Touch14 is set as shield channel by default.\n                                                The larger the parasitic capacitance on the shielding channel, the higher the drive capability needs to be set.\n                                                The equivalent capacitance of the shield channel can be estimated through the reading value of the denoise channel(Touch0).*/\n} touch_pad_waterproof_t;\n\n/** Touch sensor proximity detection configuration */\n#define TOUCH_PROXIMITY_MEAS_NUM_MAX (0xFF)\n\n/** Touch channel idle state configuration */\ntypedef enum {\n    TOUCH_PAD_CONN_HIGHZ = 0,   /*!<Idle status of touch channel is high resistance state */\n    TOUCH_PAD_CONN_GND = 1,     /*!<Idle status of touch channel is ground connection */\n    TOUCH_PAD_CONN_MAX\n} touch_pad_conn_type_t;\n\n/**\n * @brief Touch channel IIR filter coefficient configuration.\n * @note On ESP32S2. There is an error in the IIR calculation. The magnitude of the error is twice the filter coefficient.\n *       So please select a smaller filter coefficient on the basis of meeting the filtering requirements.\n *       Recommended filter coefficient selection `IIR_16`.\n */\ntypedef enum {\n    TOUCH_PAD_FILTER_IIR_4 = 0, /*!<The filter mode is first-order IIR filter. The coefficient is 4. */\n    TOUCH_PAD_FILTER_IIR_8,     /*!<The filter mode is first-order IIR filter. The coefficient is 8. */\n    TOUCH_PAD_FILTER_IIR_16,    /*!<The filter mode is first-order IIR filter. The coefficient is 16 (Typical value). */\n    TOUCH_PAD_FILTER_IIR_32,    /*!<The filter mode is first-order IIR filter. The coefficient is 32. */\n    TOUCH_PAD_FILTER_IIR_64,    /*!<The filter mode is first-order IIR filter. The coefficient is 64. */\n    TOUCH_PAD_FILTER_IIR_128,   /*!<The filter mode is first-order IIR filter. The coefficient is 128. */\n    TOUCH_PAD_FILTER_IIR_256,   /*!<The filter mode is first-order IIR filter. The coefficient is 256. */\n    TOUCH_PAD_FILTER_JITTER,    /*!<The filter mode is jitter filter */\n    TOUCH_PAD_FILTER_MAX\n} touch_filter_mode_t;\n\n/**\n * @brief Level of filter applied on the original data against large noise interference.\n * @note On ESP32S2. There is an error in the IIR calculation. The magnitude of the error is twice the filter coefficient.\n *       So please select a smaller filter coefficient on the basis of meeting the filtering requirements.\n *       Recommended filter coefficient selection `IIR_2`.\n */\ntypedef enum {\n    TOUCH_PAD_SMOOTH_OFF   = 0, /*!<No filtering of raw data. */\n    TOUCH_PAD_SMOOTH_IIR_2 = 1, /*!<Filter the raw data. The coefficient is 2 (Typical value). */\n    TOUCH_PAD_SMOOTH_IIR_4 = 2, /*!<Filter the raw data. The coefficient is 4. */\n    TOUCH_PAD_SMOOTH_IIR_8 = 3, /*!<Filter the raw data. The coefficient is 8. */\n    TOUCH_PAD_SMOOTH_MAX,\n} touch_smooth_mode_t;\n\n/** Touch sensor filter configuration */\ntypedef struct touch_filter_config {\n    touch_filter_mode_t mode;   /*!<Set filter mode. The input of the filter is the raw value of touch reading,\n                                    and the output of the filter is involved in the judgment of the touch state. */\n    uint32_t debounce_cnt;      /*!<Set debounce count, such as `n`. If the measured values continue to exceed\n                                    the threshold for `n+1` times, the touch sensor state changes.\n                                    Range: 0 ~ 7 */\n    uint32_t noise_thr;         /*!<Noise threshold coefficient. Higher = More noise resistance.\n                                    The actual noise should be less than (noise coefficient * touch threshold).\n                                    Range: 0 ~ 3. The coefficient is 0: 4/8;  1: 3/8;   2: 2/8;   3: 1; */\n    uint32_t jitter_step;       /*!<Set jitter filter step size. Range: 0 ~ 15 */\n    touch_smooth_mode_t smh_lvl;/*!<Level of filter applied on the original data against large noise interference. */\n#define TOUCH_DEBOUNCE_CNT_MAX      (7)\n#define TOUCH_NOISE_THR_MAX         (3)\n#define TOUCH_JITTER_STEP_MAX       (15)\n} touch_filter_config_t;\n\n/** Touch sensor channel sleep configuration */\ntypedef struct {\n    touch_pad_t touch_num;          /*!<Set touch channel number for sleep pad.\n                                        Only one touch sensor channel is supported in deep sleep mode.\n                                        If clear the sleep channel, point this pad to `TOUCH_PAD_NUM0`  */\n    bool en_proximity;              /*!<enable proximity function for sleep pad */\n} touch_pad_sleep_channel_t;\n\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "touch_element/include/touch_element/touch_slider.h",
    "content": "/*\n * SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#pragma once\n\n#include \"touch_element/touch_element.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* --------------------------------- General slider instance default configuration  --------------------------------- */\n#define TOUCH_SLIDER_GLOBAL_DEFAULT_CONFIG()                                  \\\n{                                                                             \\\n    .quantify_lower_threshold = 0.3,                                          \\\n    .threshold_divider = 0.8,                                                 \\\n    .filter_reset_time = 50,                                                  \\\n    .benchmark_update_time = 500,                                             \\\n    .position_filter_size = 10,                                               \\\n    .position_filter_factor = 2,                                              \\\n    .calculate_channel_count = 3                                              \\\n}\n/* ------------------------------------------------------------------------------------------------------------------ */\n\n/**\n * @brief   Slider initialization configuration passed to touch_slider_install\n */\ntypedef struct {\n    float quantify_lower_threshold;            //!< Slider signal quantification threshold\n    float threshold_divider;                   //!< Slider channel threshold divider\n    uint16_t filter_reset_time;                //!< Slider position filter reset time (Unit is esp_timer callback tick)\n    uint16_t benchmark_update_time;            //!< Slider benchmark update time (Unit is esp_timer callback tick)\n    uint8_t position_filter_size;              //!< Moving window filter buffer size\n    uint8_t position_filter_factor;            //!< One-order IIR filter factor\n    uint8_t calculate_channel_count;           //!< The number of channels which will take part in calculation\n} touch_slider_global_config_t;\n\n/**\n * @brief   Slider configuration (for new instance) passed to touch_slider_create()\n */\ntypedef struct {\n    const touch_pad_t *channel_array;    //!< Slider channel array\n    const float *sensitivity_array;      //!< Slider channel sensitivity array\n    uint8_t channel_num;                 //!< The number of slider channels\n    uint8_t position_range;              //!< The right region of touch slider position range, [0, position_range (less than or equal to 255)]\n} touch_slider_config_t;\n\n/**\n * @brief   Slider event type\n */\ntypedef enum {\n    TOUCH_SLIDER_EVT_ON_PRESS,                  //!< Slider on Press event\n    TOUCH_SLIDER_EVT_ON_RELEASE,                //!< Slider on Release event\n    TOUCH_SLIDER_EVT_ON_CALCULATION,            //!< Slider on Calculation event\n    TOUCH_SLIDER_EVT_MAX\n} touch_slider_event_t;\n\ntypedef uint32_t touch_slider_position_t;       //!< Slider position data type\n\n/**\n * @brief   Slider message type\n */\ntypedef struct {\n    touch_slider_event_t event;                 //!< Slider event\n    touch_slider_position_t position;           //!< Slider position\n} touch_slider_message_t;\n\ntypedef touch_elem_handle_t touch_slider_handle_t;   //!< Slider instance handle\ntypedef void(*touch_slider_callback_t)(touch_slider_handle_t, touch_slider_message_t *, void *); //!< Slider callback type\n\n/**\n * @brief   Touch slider initialize\n *\n * This function initializes touch slider object and acts on all\n * touch slider instances.\n *\n * @param[in] global_config   Touch slider global initialization configuration\n *\n * @return\n *      - ESP_OK: Successfully initialized touch slider\n *      - ESP_ERR_INVALID_STATE: Touch element library was not initialized\n *      - ESP_ERR_INVALID_ARG: slider_init is NULL\n *      - ESP_ERR_NO_MEM: Insufficient memory\n */\nesp_err_t touch_slider_install(const touch_slider_global_config_t *global_config);\n\n/**\n * @brief   Release resources allocated using touch_slider_install()\n *\n */\nvoid touch_slider_uninstall(void);\n\n/**\n* @brief   Create a new touch slider instance\n*\n* @param[in]  slider_config     Slider configuration\n* @param[out] slider_handle     Slider handle\n*\n* @note    The index of Channel array and sensitivity array must be one-one correspondence\n*\n* @return\n*      - ESP_OK: Successfully create touch slider\n*      - ESP_ERR_INVALID_STATE: Touch slider driver was not initialized\n*      - ESP_ERR_INVALID_ARG: Invalid configuration struct or arguments is NULL\n*      - ESP_ERR_NO_MEM: Insufficient memory\n*/\nesp_err_t touch_slider_create(const touch_slider_config_t *slider_config, touch_slider_handle_t *slider_handle);\n\n/**\n * @brief   Release resources allocated using touch_slider_create\n *\n * @param[in] slider_handle   Slider handle\n * @return\n *      - ESP_OK: Successfully released resources\n *      - ESP_ERR_INVALID_STATE: Touch slider driver was not initialized\n *      - ESP_ERR_INVALID_ARG: slider_handle is null\n *      - ESP_ERR_NOT_FOUND: Input handle is not a slider handle\n */\nesp_err_t touch_slider_delete(touch_slider_handle_t slider_handle);\n\n/**\n * @brief   Touch slider subscribes event\n *\n * This function uses event mask to subscribe to touch slider events, once one of\n * the subscribed events occurs, the event message could be retrieved by calling\n * touch_element_message_receive() or input callback routine.\n *\n * @param[in] slider_handle     Slider handle\n * @param[in] event_mask        Slider subscription event mask\n * @param[in] arg               User input argument\n *\n * @note    Touch slider only support three kind of event masks, they are\n *          TOUCH_ELEM_EVENT_ON_PRESS, TOUCH_ELEM_EVENT_ON_RELEASE. You can use those event masks in any\n *          combination to achieve the desired effect.\n *\n * @return\n *      - ESP_OK: Successfully subscribed touch slider event\n *      - ESP_ERR_INVALID_STATE: Touch slider driver was not initialized\n *      - ESP_ERR_INVALID_ARG: slider_handle is null or event is not supported\n */\nesp_err_t touch_slider_subscribe_event(touch_slider_handle_t slider_handle, uint32_t event_mask, void *arg);\n\n/**\n * @brief   Touch slider set dispatch method\n *\n * This function sets a dispatch method that the driver core will use\n * this method as the event notification method.\n *\n * @param[in] slider_handle     Slider handle\n * @param[in] dispatch_method   Dispatch method (By callback/event)\n *\n * @return\n *      - ESP_OK: Successfully set dispatch method\n *      - ESP_ERR_INVALID_STATE: Touch slider driver was not initialized\n *      - ESP_ERR_INVALID_ARG: slider_handle is null or dispatch_method is invalid\n */\nesp_err_t touch_slider_set_dispatch_method(touch_slider_handle_t slider_handle, touch_elem_dispatch_t dispatch_method);\n\n/**\n * @brief   Touch slider set callback\n *\n * This function sets a callback routine into touch element driver core,\n * when the subscribed events occur, the callback routine will be called.\n *\n * @param[in] slider_handle     Slider handle\n * @param[in] slider_callback   User input callback\n *\n * @note        Slider message will be passed from the callback function and it will be destroyed when the callback function return.\n *\n * @warning     Since this input callback routine runs on driver core (esp-timer callback routine),\n *              it should not do something that attempts to Block, such as calling vTaskDelay().\n *\n * @return\n *      - ESP_OK: Successfully set callback\n *      - ESP_ERR_INVALID_STATE: Touch slider driver was not initialized\n *      - ESP_ERR_INVALID_ARG: slider_handle or slider_callback is null\n */\nesp_err_t touch_slider_set_callback(touch_slider_handle_t slider_handle, touch_slider_callback_t slider_callback);\n\n/**\n * @brief   Touch slider get message\n *\n * This function decodes the element message from touch_element_message_receive() and return\n * a slider message pointer.\n *\n * @param[in] element_message   element message\n *\n * @return  Touch slider message pointer\n */\nconst touch_slider_message_t *touch_slider_get_message(const touch_elem_message_t *element_message);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "touch_element/test_apps/CMakeLists.txt",
    "content": "# This is the project CMakeLists.txt file for the test subproject\ncmake_minimum_required(VERSION 3.16)\n\nset(COMPONENTS main)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nproject(touch_element_test)\n"
  },
  {
    "path": "touch_element/test_apps/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"test_app_main.c\" \"test_touch_element.c\" \"test_touch_button.c\"\n                            \"test_touch_slider.c\" \"test_touch_matrix.c\"\n                       PRIV_REQUIRES unity touch_element esp_pm\n                       WHOLE_ARCHIVE\n)\n"
  },
  {
    "path": "touch_element/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/touch_element:\n    version: '*'\n    override_path: '../../'\n"
  },
  {
    "path": "touch_element/test_apps/main/test_app_main.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"unity.h\"\n#include \"unity_test_runner.h\"\n#include \"esp_heap_caps.h\"\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n\n#define TEST_MEMORY_LEAK_THRESHOLD (-400)\n\nstatic size_t before_free_8bit;\nstatic size_t before_free_32bit;\n\nstatic void check_leak(size_t before_free, size_t after_free, const char *type)\n{\n    ssize_t delta = after_free - before_free;\n    printf(\"MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\\n\", type, before_free, after_free, delta);\n    TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, \"memory leak\");\n}\n\nvoid setUp(void)\n{\n    before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);\n    before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);\n}\n\nvoid tearDown(void)\n{\n    size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);\n    size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);\n    check_leak(before_free_8bit, after_free_8bit, \"8BIT\");\n    check_leak(before_free_32bit, after_free_32bit, \"32BIT\");\n}\n\nvoid app_main(void)\n{\n    unity_run_menu();\n}\n"
  },
  {
    "path": "touch_element/test_apps/main/test_touch_button.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <time.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"freertos/queue.h\"\n#include \"freertos/semphr.h\"\n#include \"unity.h\"\n#include \"esp_random.h\"\n\n#include \"esp_private/touch_element_private.h\"\n#include \"esp_private/touch_sensor_legacy_ll.h\"\n#include \"touch_element/touch_button.h\"\n\nstatic portMUX_TYPE test_button_spinlock = portMUX_INITIALIZER_UNLOCKED;\n#define TEST_BUTTON_ENTER_CRITICAL()       portENTER_CRITICAL(&test_button_spinlock)\n#define TEST_BUTTON_EXIT_CRITICAL()        portEXIT_CRITICAL(&test_button_spinlock)\n\nstatic const touch_pad_t button_channel_array[14] = {\n    TOUCH_PAD_NUM1,\n    TOUCH_PAD_NUM2,\n    TOUCH_PAD_NUM3,\n    TOUCH_PAD_NUM4,\n    TOUCH_PAD_NUM5,\n    TOUCH_PAD_NUM6,\n    TOUCH_PAD_NUM7,\n    TOUCH_PAD_NUM8,\n    TOUCH_PAD_NUM9,\n    TOUCH_PAD_NUM10,\n    TOUCH_PAD_NUM11,\n    TOUCH_PAD_NUM12,\n    TOUCH_PAD_NUM13,\n    TOUCH_PAD_NUM14,\n};\nconst uint8_t BUTTON_CHANNEL_NUM = sizeof(button_channel_array) / sizeof(touch_pad_t);\n\ntypedef struct {\n    QueueHandle_t valid_msg_handle;\n    SemaphoreHandle_t response_sig_handle;\n} test_monitor_t;\n\ntypedef struct {\n    QueueHandle_t valid_msg_handle;\n    SemaphoreHandle_t response_sig_handle;\n    touch_button_handle_t button_handle;\n} test_concurrent_monitor_t;\n\n/* ------------------------------------------------------------------------------------------------------------------ */\nvoid test_button_event_simulator(touch_button_handle_t button_handle, touch_button_event_t button_event);\nvoid test_button_event_check(touch_elem_message_t *valid_message, touch_elem_message_t *current_message);\nstatic void test_button_callback_check(touch_button_handle_t current_handle, touch_button_message_t *current_message, touch_elem_message_t *valid_message);\nvoid test_button_event_trigger_and_check(touch_button_handle_t handle, touch_button_event_t button_event);\nvoid test_button_callback_trigger_and_check(touch_button_handle_t handle, touch_button_event_t button_event, bool should_trigger, test_monitor_t *monitor);\n/* ------------------------------------------------ Dispatch method test -------------------------------------------- */\nstatic void test_button_disp_event(void);\nstatic void test_button_disp_callback(void);\nvoid test_button_handler(touch_button_handle_t handle, touch_button_message_t *message, void *arg);\n/* ------------------------------------------------ Run-time test --------------------------------------------------- */\nstatic void test_button_event_change_lp(void);\nstatic void test_button_callback_change_lp(void);\nstatic void test_button_change_lp_handler(touch_button_handle_t handle, touch_button_message_t *message, void *arg);\n/* ------------------------------------------------ Concurrent test ------------------------------------------------- */\nstatic void test_button_event_concurrent(void);\nstatic void test_button_random_trigger_concurrent(void);\nvoid test_random_trigger_concurrent_task(void *arg);\nstatic void random_trigger_concurrent_handler(touch_button_handle_t handle, touch_button_message_t *message, void *arg);\n/* ------------------------------------------------------------------------------------------------------------------ */\n\nTEST_CASE(\"Touch button dispatch methods test\", \"[button][touch_element]\")\n{\n    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_element_install(&global_config));\n    test_button_disp_event();\n    test_button_disp_callback();\n    touch_element_uninstall();\n}\n\nTEST_CASE(\"Touch button run-time test\", \"[button][touch_element]\")\n{\n    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_element_install(&global_config));\n    test_button_event_change_lp();\n    test_button_callback_change_lp();\n    touch_element_uninstall();\n}\n\nTEST_CASE(\"Touch button concurrent test\", \"[button][touch_element]\")\n{\n    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_element_install(&global_config));\n    test_button_event_concurrent();\n    test_button_random_trigger_concurrent();\n    touch_element_uninstall();\n}\n\nvoid test_button_event_simulator(touch_button_handle_t button_handle, touch_button_event_t button_event)\n{\n    te_button_handle_t te_button = (te_button_handle_t) button_handle;\n    touch_pad_t channel = te_button->device->channel;\n    if (button_event == TOUCH_BUTTON_EVT_ON_PRESS) {\n        touch_ll_set_slope(channel, TOUCH_PAD_SLOPE_3);\n        touch_ll_set_tie_option(channel, TOUCH_PAD_TIE_OPT_DEFAULT);\n    } else if (button_event == TOUCH_BUTTON_EVT_ON_RELEASE) {\n        touch_ll_set_slope(channel, TOUCH_PAD_SLOPE_7);\n        touch_ll_set_tie_option(channel, TOUCH_PAD_TIE_OPT_DEFAULT);\n    } else {\n        touch_ll_set_slope(channel, TOUCH_PAD_SLOPE_3);\n        touch_ll_set_tie_option(channel, TOUCH_PAD_TIE_OPT_DEFAULT);\n    }\n}\n\nvoid test_button_event_check(touch_elem_message_t *valid_message, touch_elem_message_t *current_message)\n{\n    TEST_ASSERT_MESSAGE(current_message->handle == valid_message->handle, \"check handle failed\");\n    TEST_ASSERT_MESSAGE(current_message->element_type == valid_message->element_type, \"check element type failed\");\n    const touch_button_message_t *valid_button_message = touch_button_get_message(valid_message);\n    const touch_button_message_t *current_button_message = touch_button_get_message(current_message);\n    TEST_ASSERT_MESSAGE(current_button_message->event == valid_button_message->event, \"check event failed\");\n}\n\nstatic void test_button_callback_check(touch_button_handle_t current_handle, touch_button_message_t *current_message, touch_elem_message_t *valid_message)\n{\n    const touch_button_message_t *valid_button_message = touch_button_get_message(valid_message);\n    TEST_ASSERT_MESSAGE(valid_message->handle == current_handle, \"check handle failed\");\n    TEST_ASSERT_MESSAGE(valid_message->element_type == TOUCH_ELEM_TYPE_BUTTON, \"check element type failed\");\n    TEST_ASSERT_MESSAGE(valid_button_message->event == current_message->event, \"check event failed\");\n}\n\nvoid test_button_event_trigger_and_check(touch_button_handle_t handle, touch_button_event_t button_event)\n{\n    //TODO: refactor this with a constructor\n    touch_elem_message_t valid_message = {\n        .handle = handle,\n        .element_type = TOUCH_ELEM_TYPE_BUTTON,\n        .arg = NULL,\n    };\n    touch_button_message_t button_message = {\n        .event = button_event\n    };\n    memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t));  //Construct valid_message\n\n    test_button_event_simulator(handle, button_event);  //Trigger signal\n\n    touch_elem_message_t current_message;\n    te_button_handle_t te_button = handle;\n    esp_err_t ret = touch_element_message_receive(&current_message, pdMS_TO_TICKS(2 * te_button->trigger_thr * 10));\n    TEST_ASSERT_MESSAGE(ret == ESP_OK, \"button event receive timeout\");\n\n    test_button_event_check(&valid_message, &current_message);  //Verification\n}\n\nvoid test_button_callback_trigger_and_check(touch_button_handle_t handle, touch_button_event_t button_event, bool should_trigger, test_monitor_t *monitor)\n{\n    if (should_trigger) {\n        touch_elem_message_t valid_message = {\n            .handle = handle,\n            .element_type = TOUCH_ELEM_TYPE_BUTTON,\n            .arg = NULL\n        };\n        touch_button_message_t button_message = {\n            .event = button_event\n        };\n        memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t));  //Construct valid_message\n        xQueueSend(monitor->valid_msg_handle, &valid_message, portMAX_DELAY);\n    }\n\n    test_button_event_simulator(handle, button_event);  //Trigger signal\n\n    te_button_handle_t te_button = handle;\n    if (should_trigger) { //Verification\n        BaseType_t os_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(2 * te_button->trigger_thr * 10));\n        TEST_ASSERT_MESSAGE(os_ret == pdPASS, \"Button queue timeout\");\n    } else {\n        BaseType_t os_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(500));\n        TEST_ASSERT_MESSAGE(os_ret == pdFALSE, \"Button invalid trigger\");\n    }\n}\n\nstatic void test_button_disp_event(void)\n{\n    touch_button_handle_t button_handle[BUTTON_CHANNEL_NUM];\n    touch_button_global_config_t global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_button_install(&global_config));\n    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {\n        touch_button_config_t button_config = {\n            .channel_num = button_channel_array[i],\n            .channel_sens = 0.1F\n        };\n        TEST_ESP_OK(touch_button_create(&button_config, &button_handle[i]));\n        TEST_ESP_OK(touch_button_subscribe_event(button_handle[i],\n                    TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE | TOUCH_ELEM_EVENT_ON_LONGPRESS,\n                    (void *) button_channel_array[i]));\n        TEST_ESP_OK(touch_button_set_longpress(button_handle[i], 300));\n        TEST_ESP_OK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_EVENT));\n    }\n    TEST_ESP_OK(touch_element_start());\n\n    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1\n\n    srandom((unsigned int)time(NULL));\n    //10 times random press/longpress/release test\n    printf(\"Touch button event test start\\n\");\n    for (int i = 0; i < 10; i++) {\n        printf(\"Touch button event test... (%d/10)\\n\", i + 1);\n        touch_button_handle_t current_handle = button_handle[random() % 14];\n        test_button_event_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_PRESS);\n        test_button_event_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_LONGPRESS);\n        test_button_event_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_RELEASE);\n    }\n    printf(\"Touch button event test finish\\n\");\n    TEST_ESP_OK(touch_element_stop());\n    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {\n        TEST_ESP_OK(touch_button_delete(button_handle[i]));\n    }\n    touch_button_uninstall();\n}\n\nstatic void test_button_disp_callback(void)\n{\n    test_monitor_t monitor;\n    touch_button_handle_t button_handle[BUTTON_CHANNEL_NUM];\n    monitor.valid_msg_handle = xQueueCreate(10, sizeof(touch_elem_message_t));\n    monitor.response_sig_handle = xSemaphoreCreateBinary();\n    TEST_ASSERT(monitor.valid_msg_handle != NULL || monitor.response_sig_handle != NULL);\n\n    touch_button_global_config_t button_init = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_button_install(&button_init));\n    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {\n        touch_button_config_t button_config = {\n            .channel_num = button_channel_array[i],\n            .channel_sens = 0.1F\n        };\n        TEST_ESP_OK(touch_button_create(&button_config, &button_handle[i]));\n        TEST_ESP_OK(touch_button_subscribe_event(button_handle[i],\n                    TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE | TOUCH_ELEM_EVENT_ON_LONGPRESS,\n                    (void *) &monitor));\n        TEST_ESP_OK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_CALLBACK));\n        TEST_ESP_OK(touch_button_set_callback(button_handle[i], &test_button_handler));\n        TEST_ESP_OK(touch_button_set_longpress(button_handle[i], 300));\n    }\n    TEST_ESP_OK(touch_element_start());\n\n    srandom((unsigned int)time(NULL));\n    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1\n    //10 times random press/longpress/release test\n    printf(\"Touch button callback test start\\n\");\n    for (int i = 0; i < 10; i++) {\n        printf(\"Touch button callback test... (%d/10)\\n\", i + 1);\n        touch_button_handle_t current_handle = button_handle[random() % 14];\n        test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_PRESS, true, &monitor);\n        test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_LONGPRESS, true, &monitor);\n        test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_RELEASE, true, &monitor);\n    }\n    printf(\"Touch button callback test finish\\n\");\n    TEST_ESP_OK(touch_element_stop());\n    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {\n        TEST_ESP_OK(touch_button_delete(button_handle[i]));\n    }\n    touch_button_uninstall();\n    vQueueDelete(monitor.valid_msg_handle);\n    vSemaphoreDelete(monitor.response_sig_handle);\n}\n\nvoid test_button_handler(touch_button_handle_t handle, touch_button_message_t *message, void *arg)\n{\n    test_monitor_t *monitor = (test_monitor_t *)arg;\n    touch_elem_message_t valid_message;\n    BaseType_t os_ret = xQueueReceive(monitor->valid_msg_handle, &valid_message, pdMS_TO_TICKS(200));  //Get the valid message for the verification, 500ms timeout\n    TEST_ASSERT_MESSAGE(os_ret == pdPASS, \"test_button_handler: queue timeout\");\n    test_button_callback_check(handle, message, &valid_message);\n    xSemaphoreGive(monitor->response_sig_handle);\n}\n\nstatic void test_button_event_change_lp(void)\n{\n    touch_button_handle_t button_handle[BUTTON_CHANNEL_NUM];\n    touch_button_global_config_t global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_button_install(&global_config));\n    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {\n        touch_button_config_t button_config = {\n            .channel_num = button_channel_array[i],\n            .channel_sens = 0.1F\n        };\n        TEST_ESP_OK(touch_button_create(&button_config, &button_handle[i]));\n        TEST_ESP_OK(touch_button_subscribe_event(button_handle[i], TOUCH_ELEM_EVENT_ON_LONGPRESS, NULL));\n        TEST_ESP_OK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_EVENT));\n    }\n    TEST_ESP_OK(touch_element_start());\n\n    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1\n\n    srandom((unsigned int)time(NULL));\n    //10 times random press/longpress/release test\n    printf(\"Touch button event change longtime test start\\n\");\n    for (int i = 0; i < 10; i++) {\n        printf(\"Touch button event change longtime test... (%d/10)\\n\", i + 1);\n        esp_err_t ret = ESP_OK;\n        uint8_t channel_index = random() % BUTTON_CHANNEL_NUM;\n        touch_elem_message_t valid_message = {\n            .handle = button_handle[channel_index],\n            .element_type = TOUCH_ELEM_TYPE_BUTTON,\n            .arg = NULL\n        };\n        touch_button_message_t button_message = {\n            .event = TOUCH_BUTTON_EVT_ON_LONGPRESS\n        };\n        memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t));  //Construct valid_message\n\n        TEST_ESP_OK(touch_button_set_longpress(valid_message.handle, 200 + (i + 1) * 50));\n        test_button_event_simulator(valid_message.handle, button_message.event);  //Trigger signal\n\n        touch_elem_message_t current_message;\n        ret = touch_element_message_receive(&current_message, pdMS_TO_TICKS(10 * 1000));\n        TEST_ASSERT_MESSAGE(ret == ESP_OK, \"button event LongPress timeout\");\n        test_button_event_check(&valid_message, &current_message);  //Verification\n\n        test_button_event_simulator(valid_message.handle, TOUCH_BUTTON_EVT_ON_RELEASE); //Release the button.\n    }\n    printf(\"Touch button event change longtime test finish\\n\");\n    TEST_ESP_OK(touch_element_stop());\n    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {\n        TEST_ESP_OK(touch_button_delete(button_handle[i]));\n    }\n    touch_button_uninstall();\n}\n\nstatic void test_button_callback_change_lp(void)\n{\n    test_monitor_t monitor;\n    touch_button_handle_t button_handle[BUTTON_CHANNEL_NUM];\n    monitor.valid_msg_handle = xQueueCreate(10, sizeof(touch_elem_message_t));\n    monitor.response_sig_handle = xSemaphoreCreateBinary();\n    TEST_ASSERT(monitor.valid_msg_handle != NULL || monitor.response_sig_handle != NULL);\n\n    touch_button_global_config_t global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_button_install(&global_config));\n    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {\n        touch_button_config_t button_config = {\n            .channel_num = button_channel_array[i],\n            .channel_sens = 0.1F\n        };\n        TEST_ESP_OK(touch_button_create(&button_config, &button_handle[i]));\n        TEST_ESP_OK(touch_button_subscribe_event(button_handle[i], TOUCH_ELEM_EVENT_ON_LONGPRESS, (void *)&monitor));\n        TEST_ESP_OK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_CALLBACK));\n        TEST_ESP_OK(touch_button_set_callback(button_handle[i], &test_button_change_lp_handler));\n    }\n    TEST_ESP_OK(touch_element_start());\n\n    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1\n\n    //10 times random press/longpress/release test\n    printf(\"Touch button event change longtime test start\\n\");\n    for (int i = 0; i < 10; i++) {\n        printf(\"Touch button event change longtime test... (%d/10)\\n\", i + 1);\n        uint8_t channel_index = 5;  //Always this channel\n        touch_elem_message_t valid_message = {\n            .handle = button_handle[channel_index],\n            .element_type = TOUCH_ELEM_TYPE_BUTTON,\n            .arg = NULL,\n        };\n        touch_button_message_t button_message = {\n            .event = TOUCH_BUTTON_EVT_ON_LONGPRESS\n        };\n        memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t));  //Construct valid_message\n\n        xQueueSend(monitor.valid_msg_handle, &valid_message, portMAX_DELAY);\n        test_button_event_simulator(button_handle[channel_index], button_message.event);\n\n        BaseType_t os_ret = xSemaphoreTake(monitor.response_sig_handle, pdMS_TO_TICKS(10 * 1000)); //100ms timeout\n        TEST_ASSERT_MESSAGE(os_ret == pdPASS, \"Button LongPress queue timeout\");\n        test_button_event_simulator(valid_message.handle, TOUCH_BUTTON_EVT_ON_RELEASE); //Reset hardware\n    }\n    printf(\"Touch button event change longtime test finish\\n\");\n    TEST_ESP_OK(touch_element_stop());\n    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {\n        TEST_ESP_OK(touch_button_delete(button_handle[i]));\n    }\n    touch_button_uninstall();\n}\n\nstatic void test_button_change_lp_handler(touch_button_handle_t handle, touch_button_message_t *message, void *arg)\n{\n    test_monitor_t *monitor = (test_monitor_t *)arg;\n    touch_elem_message_t valid_message;\n    BaseType_t os_ret = xQueueReceive(monitor->valid_msg_handle, &valid_message, pdMS_TO_TICKS(200));  //Get the valid message for the verification, 500ms timeout\n    TEST_ASSERT_MESSAGE(os_ret == pdPASS, \"test_button_handler: queue timeout\");\n    test_button_callback_check(handle, message, &valid_message);\n    xSemaphoreGive(monitor->response_sig_handle);\n    TEST_ESP_OK(touch_button_set_longpress(valid_message.handle, 300)); // Always 300ms\n}\n\nstatic void test_button_event_concurrent(void)\n{\n    touch_button_handle_t button_handle[BUTTON_CHANNEL_NUM];\n    touch_button_global_config_t global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_button_install(&global_config));\n    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {\n        touch_button_config_t button_config = {\n            .channel_num = button_channel_array[i],\n            .channel_sens = 0.1F\n        };\n        TEST_ESP_OK(touch_button_create(&button_config, &button_handle[i]));\n        TEST_ESP_OK(touch_button_subscribe_event(button_handle[i], TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE, NULL));\n        TEST_ESP_OK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_EVENT));\n    }\n    TEST_ESP_OK(touch_element_start());\n\n    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1\n\n    //10 times random press/longpress/release test\n    printf(\"Touch button event concurrent test start\\n\");\n    for (int i = 0; i < 10; i++) {\n        printf(\"Touch button event concurrent test... (%d/10)\\n\", i + 1);\n        esp_err_t ret = ESP_OK;\n        uint32_t message_count = 0;\n        touch_elem_message_t current_message;\n\n        TEST_BUTTON_ENTER_CRITICAL();\n        for (int idx = 0; idx < BUTTON_CHANNEL_NUM; idx++) {\n            test_button_event_simulator(button_handle[idx], TOUCH_BUTTON_EVT_ON_PRESS);  //All channels trigger\n        }\n        TEST_BUTTON_EXIT_CRITICAL();\n        message_count = 0;\n        do {\n            ret = touch_element_message_receive(&current_message, pdMS_TO_TICKS(500));\n            if (ret == ESP_OK) {\n                message_count++;\n            }\n        } while (ret == ESP_OK);\n        TEST_ASSERT_MESSAGE(message_count == BUTTON_CHANNEL_NUM, \"button concurrent Press failed\");\n\n        TEST_BUTTON_ENTER_CRITICAL();\n        for (int idx = 0; idx < BUTTON_CHANNEL_NUM; idx++) {\n            test_button_event_simulator(button_handle[idx], TOUCH_BUTTON_EVT_ON_RELEASE);  //All channels trigger\n        }\n        TEST_BUTTON_EXIT_CRITICAL();\n        message_count = 0;\n        do {\n            ret = touch_element_message_receive(&current_message, pdMS_TO_TICKS(500));\n            if (ret == ESP_OK) {\n                message_count++;\n            }\n        } while (ret == ESP_OK);\n        TEST_ASSERT_MESSAGE(message_count == BUTTON_CHANNEL_NUM, \"button concurrent Release failed\");\n    }\n    printf(\"Touch button event concurrent test finish\\n\");\n    TEST_ESP_OK(touch_element_stop());\n    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {\n        TEST_ESP_OK(touch_button_delete(button_handle[i]));\n    }\n    touch_button_uninstall();\n}\n\nstatic void test_button_random_trigger_concurrent(void)\n{\n    uint64_t sem_and_monitor[BUTTON_CHANNEL_NUM];\n    printf(\"Touch button random trigger concurrent test start\\n\");\n    test_concurrent_monitor_t monitor[BUTTON_CHANNEL_NUM];\n\n    SemaphoreHandle_t count_sem = xSemaphoreCreateCounting(BUTTON_CHANNEL_NUM, 0);\n\n    touch_button_global_config_t global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_button_install(&global_config));\n    for (uint32_t i = 0; i < BUTTON_CHANNEL_NUM; i++) {\n        touch_button_config_t button_config = {\n            .channel_num = button_channel_array[i],\n            .channel_sens = 0.1F\n        };\n        monitor[i].response_sig_handle = xSemaphoreCreateBinary();\n        monitor[i].valid_msg_handle = xQueueCreate(BUTTON_CHANNEL_NUM, sizeof(touch_elem_message_t));\n        TEST_ASSERT(monitor[i].valid_msg_handle != NULL && monitor[i].response_sig_handle != NULL);\n        uintptr_t temp_count_sem = (uint32_t)count_sem;\n        uintptr_t temp_monitor = (uint32_t)&monitor[i];  //Prevent compiler warning\n        sem_and_monitor[i] = (uint64_t)(((uint64_t)temp_count_sem << 32) | (uint64_t) temp_monitor);\n        TEST_ESP_OK(touch_button_create(&button_config, &monitor[i].button_handle));\n        TEST_ESP_OK(touch_button_subscribe_event(monitor[i].button_handle, TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_LONGPRESS | TOUCH_ELEM_EVENT_ON_RELEASE, (void *)&sem_and_monitor[i]));\n        TEST_ESP_OK(touch_button_set_longpress(monitor[i].button_handle, 500));\n        TEST_ESP_OK(touch_button_set_dispatch_method(monitor[i].button_handle, TOUCH_ELEM_DISP_CALLBACK));\n        TEST_ESP_OK(touch_button_set_callback(monitor[i].button_handle, &random_trigger_concurrent_handler));\n    }\n    TEST_ESP_OK(touch_element_start());\n\n    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1\n\n    for (uint32_t i = 0; i < BUTTON_CHANNEL_NUM; i++) {\n        BaseType_t os_ret = xTaskCreate(test_random_trigger_concurrent_task, \"test_random_trigger_concurrent_task\", 1024 * 4, (void *)&sem_and_monitor[i], 10, NULL);\n        TEST_ASSERT(os_ret == pdPASS);\n    }\n\n\n    uint32_t run_count = 0;\n    while (1) {\n        if (run_count++ % 1000 == 0) {\n            printf(\"Touch button random trigger concurrent test running... (1/1)\\n\");\n        }\n        uint8_t count = uxSemaphoreGetCount(count_sem);\n        if (count == BUTTON_CHANNEL_NUM) {\n            vTaskDelay(1); //Let IDLE task running and get tasks cleanup\n            break;\n        }\n        vTaskDelay(1);\n    }\n\n    TEST_ESP_OK(touch_element_stop());\n    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {\n        vQueueDelete(monitor[i].valid_msg_handle);\n        vSemaphoreDelete(monitor[i].response_sig_handle);\n        TEST_ESP_OK(touch_button_delete(monitor[i].button_handle));\n    }\n    touch_button_uninstall();\n    printf(\"Touch button random trigger concurrent test stop\\n\");\n}\n\nvoid test_random_trigger_concurrent_task(void *arg)\n{\n    uintptr_t temp_monitor = *((uint32_t *) arg);\n    uintptr_t temp_count_sem = (*((uint64_t *) arg) >> 32);  //Prevent compiler warning\n    test_concurrent_monitor_t *monitor = (test_concurrent_monitor_t *)temp_monitor;\n    SemaphoreHandle_t count_sem = (SemaphoreHandle_t) temp_count_sem;\n    uint32_t start_delay_time = (esp_random() % 100) * 10;\n    vTaskDelay(pdMS_TO_TICKS(start_delay_time));\n\n    touch_elem_message_t valid_message = {\n        .handle = monitor->button_handle,\n        .element_type = TOUCH_ELEM_TYPE_BUTTON,\n        .arg = NULL,\n    };\n    touch_button_message_t button_message;\n    button_message.event = TOUCH_BUTTON_EVT_ON_PRESS;\n    memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t));  //Construct valid_message\n    xQueueSend(monitor->valid_msg_handle, &valid_message, portMAX_DELAY);\n    test_button_event_simulator(valid_message.handle, button_message.event);  //Trigger signal\n    BaseType_t res_sem_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(1000));\n    TEST_ASSERT_MESSAGE(res_sem_ret == pdPASS, \"Response timeout\");\n\n    uint32_t hold_state_time_ms = (esp_random() % 100) * 10 + 100;\n    te_button_handle_t te_button = (te_button_handle_t) valid_message.handle;\n    if ((int)(hold_state_time_ms - te_button->trigger_thr * 10) > 50) {  //should raise longpress event\n        button_message.event = TOUCH_BUTTON_EVT_ON_LONGPRESS;\n        memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t));  //Construct valid_message\n        xQueueSend(monitor->valid_msg_handle, &valid_message, portMAX_DELAY);\n        test_button_event_simulator(valid_message.handle, button_message.event);  //Trigger signal\n        res_sem_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(1000)); //+100 make sure it will really raise longpress event\n        TEST_ASSERT_MESSAGE(res_sem_ret == pdPASS, \"Response timeout\");\n    } else { //should not raise longpress event\n        //Do nothing\n    }\n\n    button_message.event = TOUCH_BUTTON_EVT_ON_RELEASE;\n    memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t));  //Construct valid_message\n    xQueueSend(monitor->valid_msg_handle, &valid_message, portMAX_DELAY);\n    test_button_event_simulator(valid_message.handle, button_message.event);  //Trigger signal\n    res_sem_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(1000));\n    TEST_ASSERT_MESSAGE(res_sem_ret == pdPASS, \"Response timeout\");\n\n    xSemaphoreGive(count_sem);\n    vTaskDelete(NULL);\n}\n\nstatic void random_trigger_concurrent_handler(touch_button_handle_t handle, touch_button_message_t *message, void *arg)\n{\n    uintptr_t temp_monitor = *((uint32_t *) arg);  //Prevent compiler warning\n    test_concurrent_monitor_t *monitor = (test_concurrent_monitor_t *) temp_monitor;\n    touch_elem_message_t valid_message;\n    BaseType_t os_ret = xQueueReceive(monitor->valid_msg_handle, &valid_message, pdMS_TO_TICKS(1000));\n    TEST_ASSERT_MESSAGE(os_ret == pdPASS, \"valid message timeout\");\n    const touch_button_message_t *button_message =  touch_button_get_message(&valid_message);\n    if (button_message->event == TOUCH_BUTTON_EVT_ON_LONGPRESS) {\n        touch_button_set_longpress(handle, portMAX_DELAY);  //Prevent button triggers LongPress event again\n    }\n    TEST_ASSERT_MESSAGE(handle == valid_message.handle, \"check handle failed\");\n    TEST_ASSERT_MESSAGE(valid_message.element_type == TOUCH_ELEM_TYPE_BUTTON, \"check element type failed\");\n    TEST_ASSERT_MESSAGE(message->event == button_message->event, \"check event failed\");\n    xSemaphoreGive(monitor->response_sig_handle);\n}\n"
  },
  {
    "path": "touch_element/test_apps/main/test_touch_element.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n/* ---------------------------------------------------------- README ------------------------------------------------\n *  This doc is aimed at explain some important code block and do some records for the test result, if developer or\n *  test-owner has some question in reading this code implementation, please read it first.\n *\n *  CODE Block:\n *  `code-block-1`: Touch Element lib need some time to finish the initialization so as to configure the right threshold.\n *                  Since some hardware issue(Must to pass 2 times \"meas_done\" interrupt), Touch Element lib will spend\n *                  some time(Maybe <30ms) to finish the initialization, every operations (interrupts) happen to touch\n *                  sensor will be ignored before initialization. That's why \"vTaskDelay()\" could be saw in after call\n *                  \"touch_element_start()\". However, this just for the unit test, in the real application, users don't\n *                  need to delay something.\n *\n *  NOTES:\n *  `Simulator`: Currently the event simulator depend on the touch sensor driver and play some \"hack\" in some register so\n *               as to raise a FAKE interrupt. It means that Touch Element lib test case must be burned on dev-kit and keep\n *               the touch channel as clean as possible, ESP32-S2-Saola is good test board.  //TODO: Remove the dependent of touch sensor driver.\n ------------------------------------------------------------------------------------------------------------------ */\n\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <time.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"freertos/queue.h\"\n#include \"freertos/semphr.h\"\n#include \"unity.h\"\n\n#include \"touch_element/touch_button.h\"\n#include \"touch_element/touch_slider.h\"\n#include \"touch_element/touch_matrix.h\"\n#include \"esp_private/touch_sensor_legacy_ll.h\"\n\ntypedef struct {\n    QueueHandle_t valid_msg_handle;\n    SemaphoreHandle_t response_sig_handle;\n} test_monitor_t;\n\n/* ------------------------------------------------------------------------------------------------------------------ */\nextern void test_button_event_simulator(touch_button_handle_t button_handle, touch_button_event_t button_event);\nextern void test_button_handler(touch_button_handle_t handle, touch_button_message_t *message, void *arg);\nextern void test_button_event_check(touch_elem_message_t *valid_message, touch_elem_message_t *current_message);\nextern void test_button_event_trigger_and_check(touch_button_handle_t handle, touch_button_event_t button_event);\nextern void test_button_callback_trigger_and_check(touch_button_handle_t handle, touch_button_event_t button_event, bool should_trigger, test_monitor_t *monitor);\nextern void test_slider_event_simulator(touch_slider_handle_t slider_handle, touch_slider_event_t slider_event, uint32_t random);\nextern void test_slider_event_check(touch_elem_message_t *valid_message, touch_elem_message_t *current_message);\nextern void test_matrix_event_simulator(touch_matrix_handle_t matrix_handle, touch_matrix_event_t matrix_event, uint32_t pos_index);\nextern void test_matrix_event_check(touch_elem_message_t *valid_message, touch_elem_message_t *current_message);\n/* ------------------------------------------------------------------------------------------------------------------ */\nstatic void test_waterproof_event_simulator(touch_pad_t guard_channel, touch_button_event_t guard_state);\nstatic void test_system_waterproof_guard(void);\nstatic void test_integrat_btn_sld_mat(void);\nstatic void test_integration_monitor_task(void *arg);\n/* ------------------------------------------------------------------------------------------------------------------ */\nTEST_CASE(\"Touch element integration test\", \"[touch_element]\")\n{\n    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_element_install(&global_config));\n    test_integrat_btn_sld_mat();\n    touch_element_uninstall();\n}\n\nTEST_CASE(\"Touch element waterproof test\", \"[touch_element]\")\n{\n    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_element_install(&global_config));\n    test_system_waterproof_guard(); //TODO: add waterproof work with slider and matrix\n    touch_element_uninstall();\n}\n\nstatic void test_system_waterproof_guard(void)\n{\n    static const touch_pad_t button_channel_array[12] = {\n        TOUCH_PAD_NUM1,\n        TOUCH_PAD_NUM2,\n        TOUCH_PAD_NUM3,\n        TOUCH_PAD_NUM4,\n        TOUCH_PAD_NUM5,\n        TOUCH_PAD_NUM6,\n        TOUCH_PAD_NUM7,\n        TOUCH_PAD_NUM8,\n        TOUCH_PAD_NUM9,\n        TOUCH_PAD_NUM10,\n        TOUCH_PAD_NUM11,\n        TOUCH_PAD_NUM12\n    };\n    const uint8_t BUTTON_CHANNEL_NUM = sizeof(button_channel_array) / sizeof(touch_pad_t);\n\n    test_monitor_t monitor;\n    touch_button_handle_t button_handle[BUTTON_CHANNEL_NUM];\n    monitor.valid_msg_handle = xQueueCreate(10, sizeof(touch_elem_message_t));\n    monitor.response_sig_handle = xSemaphoreCreateBinary();\n    TEST_ASSERT(monitor.valid_msg_handle != NULL || monitor.response_sig_handle != NULL);\n    touch_button_global_config_t global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_button_install(&global_config));\n    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {\n        touch_button_config_t button_config = {\n            .channel_num = button_channel_array[i],\n            .channel_sens = 0.1F\n        };\n        TEST_ESP_OK(touch_button_create(&button_config, &button_handle[i]));\n        TEST_ESP_OK(touch_button_subscribe_event(button_handle[i], TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE, (void *)&monitor));\n        TEST_ESP_OK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_CALLBACK));\n        TEST_ESP_OK(touch_button_set_callback(button_handle[i], test_button_handler));\n    }\n    printf(\"Touch Element waterproof guard sensor test start\\n\");\n\n    srandom((unsigned int)time(NULL));\n    {\n        //No use waterproof guard sensor\n        touch_elem_waterproof_config_t waterproof_config = {\n            .guard_channel = TOUCH_WATERPROOF_GUARD_NOUSE,\n            .guard_sensitivity = 0.0F\n        };\n        TEST_ESP_OK(touch_element_waterproof_install(&waterproof_config));\n        TEST_ESP_OK(touch_element_start());\n        vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1\n        for (int i = 0; i < 10; i++) { //Start state test\n            printf(\"Touch Element waterproof no-use guard sensor test... (%d/10)\\n\", i + 1);\n            touch_button_handle_t current_handle = button_handle[random() % 12];\n            test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_PRESS, true, &monitor);\n            test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_RELEASE, true, &monitor);\n        }\n        TEST_ESP_OK(touch_element_stop());\n        touch_element_waterproof_uninstall();\n    }\n\n    {\n        //Use waterproof guard sensor(Add all handles)\n        touch_elem_waterproof_config_t waterproof_config = {\n            .guard_channel = TOUCH_PAD_NUM13,\n            .guard_sensitivity = 0.1F\n        };\n        TEST_ESP_OK(touch_element_waterproof_install(&waterproof_config));\n        for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {\n            TEST_ESP_OK(touch_element_waterproof_add(button_handle[i]));\n        }\n        TEST_ESP_OK(touch_element_start());\n        vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1\n        for (int i = 0; i < 10; i++) {\n            printf(\"Touch Element waterproof use guard sensor random trigger test... (%d/10)\\n\", i + 1);\n            bool should_trigger = random() % 2;\n            if (should_trigger) {\n                touch_button_handle_t current_handle = button_handle[random() % 12];\n                test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_PRESS, should_trigger, &monitor);\n                test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_RELEASE, should_trigger, &monitor);\n            } else {\n                test_waterproof_event_simulator(waterproof_config.guard_channel, TOUCH_BUTTON_EVT_ON_PRESS);  //Waterproof guard sensor trigger\n                touch_button_handle_t current_handle = button_handle[random() % 12];\n                test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_PRESS, should_trigger, &monitor);\n                test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_RELEASE, should_trigger, &monitor);\n                test_waterproof_event_simulator(waterproof_config.guard_channel, TOUCH_BUTTON_EVT_ON_RELEASE);  //Waterproof guard sensor release\n            }\n        }\n        TEST_ESP_OK(touch_element_stop());\n        touch_element_waterproof_uninstall();\n    }\n\n    {\n        //Put half button handles into guard ring\n        const uint8_t protect_handle_threshold = BUTTON_CHANNEL_NUM / 2;\n        touch_elem_waterproof_config_t waterproof_config = {\n            .guard_channel = TOUCH_PAD_NUM13,\n            .guard_sensitivity = 0.1F\n        };\n        TEST_ESP_OK(touch_element_waterproof_install(&waterproof_config));\n        for (int i = 0; i < protect_handle_threshold; i++) {\n            TEST_ESP_OK(touch_element_waterproof_add(button_handle[i]));\n        }\n        TEST_ESP_OK(touch_element_start());\n        vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1\n        for (int i = 0; i < 10; i++) {\n            printf(\"Touch Element waterproof use guard sensor test(guard sensor is triggered will half button handles)... (%d/10)\\n\", i + 1);\n            test_waterproof_event_simulator(waterproof_config.guard_channel, TOUCH_BUTTON_EVT_ON_PRESS);  //Waterproof guard sensor trigger\n            uint32_t handle_index = random() % 12;\n            touch_button_handle_t current_handle = button_handle[handle_index];\n            bool should_trigger = (handle_index < protect_handle_threshold) ? false : true;\n            test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_PRESS, should_trigger, &monitor);\n            test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_RELEASE, should_trigger, &monitor);\n            test_waterproof_event_simulator(waterproof_config.guard_channel, TOUCH_BUTTON_EVT_ON_RELEASE);  //Waterproof guard sensor release\n        }\n        TEST_ESP_OK(touch_element_stop());\n        touch_element_waterproof_uninstall();\n    }\n\n    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {\n        TEST_ESP_OK(touch_button_delete(button_handle[i]));\n    }\n    touch_button_uninstall();\n    vQueueDelete(monitor.valid_msg_handle);\n    vSemaphoreDelete(monitor.response_sig_handle);\n    printf(\"Touch Element waterproof guard sensor test finish\\n\");\n}\n\nstatic void test_waterproof_event_simulator(touch_pad_t guard_channel, touch_button_event_t guard_state)\n{\n    if (guard_state == TOUCH_BUTTON_EVT_ON_PRESS) {\n        touch_ll_set_slope(guard_channel, TOUCH_PAD_SLOPE_3);\n        touch_ll_set_tie_option(guard_channel, TOUCH_PAD_TIE_OPT_DEFAULT);\n    } else if (guard_state == TOUCH_BUTTON_EVT_ON_RELEASE) {\n        touch_ll_set_slope(guard_channel, TOUCH_PAD_SLOPE_7);\n        touch_ll_set_tie_option(guard_channel, TOUCH_PAD_TIE_OPT_DEFAULT);\n    } else {\n        printf(\"guard sensor simulator doesn't support this operation\\n\");\n    }\n    /* Fixme: If the normal instance and guard sensor trigger at the same time, guard sensor will lock the state failed */\n    vTaskDelay(pdMS_TO_TICKS(100));\n}\n\nstatic void test_integrat_btn_sld_mat(void)\n{\n    static const touch_pad_t button_channel_array[3] = {\n        TOUCH_PAD_NUM1,\n        TOUCH_PAD_NUM2,\n        TOUCH_PAD_NUM3\n    };\n    static const float button_sens_array[3] = {\n        0.1F,\n        0.1F,\n        0.1F\n    };\n    static const touch_pad_t slider_channel_array[5] = {\n        TOUCH_PAD_NUM4,\n        TOUCH_PAD_NUM5,\n        TOUCH_PAD_NUM6,\n        TOUCH_PAD_NUM7,\n        TOUCH_PAD_NUM8\n    };\n    static const float slider_sens_array[5] = {\n        0.1F,\n        0.1F,\n        0.1F,\n        0.1F,\n        0.1F\n    };\n    static const touch_pad_t x_axis_channel[3] = {\n        TOUCH_PAD_NUM9,\n        TOUCH_PAD_NUM10,\n        TOUCH_PAD_NUM11,\n    };\n    static const touch_pad_t y_axis_channel[3] = {\n        TOUCH_PAD_NUM12,\n        TOUCH_PAD_NUM13,\n        TOUCH_PAD_NUM14,\n    };\n    static const float x_axis_channel_sens[3] = {\n        0.1F,\n        0.1F,\n        0.1F,\n    };\n    static const float y_axis_channel_sens[3] = {\n        0.1F,\n        0.1F,\n        0.1F,\n    };\n    const uint8_t BUTTON_CHANNEL_NUM = sizeof(button_channel_array) / sizeof(touch_pad_t);\n    const uint8_t SLIDER_CHANNEL_NUM = sizeof(slider_channel_array) / sizeof(touch_pad_t);\n    const uint8_t MATRIX_CHANNEL_NUM_X = sizeof(x_axis_channel) / sizeof(touch_pad_t);\n    const uint8_t MATRIX_CHANNEL_NUM_Y = sizeof(y_axis_channel) / sizeof(touch_pad_t);\n\n    printf(\"Integration test(button + slider + matrix) start\\n\");\n\n    BaseType_t os_ret;\n    touch_button_handle_t button_handle[BUTTON_CHANNEL_NUM];\n    touch_slider_handle_t slider_handle;\n    touch_matrix_handle_t matrix_handle;\n    test_monitor_t monitor;\n    TaskHandle_t task_handle = NULL;\n\n    monitor.valid_msg_handle = xQueueCreate(10, sizeof(touch_elem_message_t));\n    monitor.response_sig_handle = xSemaphoreCreateBinary();\n    os_ret = xTaskCreate(&test_integration_monitor_task, \"test_integration_monitor_task\", 4096, (void *)&monitor, 5, &task_handle);\n    TEST_ASSERT(monitor.valid_msg_handle != NULL && monitor.response_sig_handle != NULL && os_ret == pdPASS);\n\n    touch_button_global_config_t button_global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();\n    touch_slider_global_config_t slider_global_config = TOUCH_SLIDER_GLOBAL_DEFAULT_CONFIG();\n    touch_matrix_global_config_t matrix_global_config = TOUCH_MATRIX_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_button_install(&button_global_config));\n    TEST_ESP_OK(touch_slider_install(&slider_global_config));\n    TEST_ESP_OK(touch_matrix_install(&matrix_global_config));\n\n    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {\n        touch_button_config_t button_config = {\n            .channel_num = button_channel_array[i],\n            .channel_sens = button_sens_array[i]\n        };\n        TEST_ESP_OK(touch_button_create(&button_config, &button_handle[i]));\n        TEST_ESP_OK(touch_button_subscribe_event(button_handle[i], TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE, NULL));\n        TEST_ESP_OK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_EVENT));\n    }\n\n    touch_slider_config_t slider_config = {\n        .channel_array = slider_channel_array,\n        .sensitivity_array = slider_sens_array,\n        .channel_num = SLIDER_CHANNEL_NUM,\n        .position_range = 101\n    };\n    TEST_ESP_OK(touch_slider_create(&slider_config, &slider_handle));\n    TEST_ESP_OK(touch_slider_subscribe_event(slider_handle, TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE, NULL));\n    TEST_ESP_OK(touch_slider_set_dispatch_method(slider_handle, TOUCH_ELEM_DISP_EVENT));\n\n    touch_matrix_config_t matrix_config = {\n        .x_channel_array = x_axis_channel,\n        .y_channel_array = y_axis_channel,\n        .x_sensitivity_array = x_axis_channel_sens,\n        .y_sensitivity_array = y_axis_channel_sens,\n        .x_channel_num = MATRIX_CHANNEL_NUM_X,\n        .y_channel_num = MATRIX_CHANNEL_NUM_Y\n    };\n    TEST_ESP_OK(touch_matrix_create(&matrix_config, &matrix_handle));\n    TEST_ESP_OK(touch_matrix_subscribe_event(matrix_handle, TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE, NULL));\n    TEST_ESP_OK(touch_matrix_set_dispatch_method(matrix_handle, TOUCH_ELEM_DISP_EVENT));\n    TEST_ESP_OK(touch_element_start());\n\n    vTaskDelay(pdMS_TO_TICKS(500)); //Mention in README, code-block-1\n\n    srandom((unsigned int)time(NULL));\n    for (int i = 0; i < 30; i++) {\n        printf(\"Integration test... (%d/30)\\n\", i + 1);\n        touch_elem_message_t valid_message;\n        touch_button_message_t button_message;\n        touch_slider_message_t slider_message;\n        touch_matrix_message_t matrix_message;\n\n        valid_message.element_type = (random() % (TOUCH_ELEM_TYPE_MATRIX + 1));\n        if (valid_message.element_type == TOUCH_ELEM_TYPE_BUTTON) {\n            uint32_t button_index = random() % BUTTON_CHANNEL_NUM;\n            valid_message.handle = button_handle[button_index];\n            button_message.event = TOUCH_BUTTON_EVT_ON_PRESS;\n            memcpy(valid_message.child_msg, &button_message, sizeof(button_message));  //Construct child message\n            xQueueSend(monitor.valid_msg_handle, &valid_message, portMAX_DELAY);\n            test_button_event_simulator(valid_message.handle, button_message.event);\n        } else if (valid_message.element_type == TOUCH_ELEM_TYPE_SLIDER) {\n            valid_message.handle = slider_handle;\n            slider_message.event = TOUCH_SLIDER_EVT_ON_PRESS;\n            slider_message.position = 0; //No check\n            memcpy(valid_message.child_msg, &slider_message, sizeof(slider_message));  //Construct child message\n            xQueueSend(monitor.valid_msg_handle, &valid_message, portMAX_DELAY);\n            test_slider_event_simulator(valid_message.handle, slider_message.event, 1);\n        } else if (valid_message.element_type == TOUCH_ELEM_TYPE_MATRIX) {\n            uint32_t matrix_x_axis_index = random() % MATRIX_CHANNEL_NUM_X;\n            uint32_t matrix_y_axis_index = random() % MATRIX_CHANNEL_NUM_Y;\n            valid_message.handle = matrix_handle;\n            matrix_message.event = TOUCH_MATRIX_EVT_ON_PRESS;\n            matrix_message.position.x_axis = matrix_x_axis_index;\n            matrix_message.position.y_axis = matrix_y_axis_index;\n            matrix_message.position.index = matrix_x_axis_index * MATRIX_CHANNEL_NUM_Y + matrix_y_axis_index;\n            memcpy(valid_message.child_msg, &matrix_message, sizeof(matrix_message));  //Construct child message\n            xQueueSend(monitor.valid_msg_handle, &valid_message, portMAX_DELAY);\n            test_matrix_event_simulator(valid_message.handle, matrix_message.event, matrix_message.position.index);\n        } else {\n            TEST_ABORT();\n        }\n        os_ret = xSemaphoreTake(monitor.response_sig_handle, pdMS_TO_TICKS(500));\n        TEST_ASSERT_MESSAGE(os_ret == pdPASS, \"response queue timeout (500ms)\");\n\n        if (valid_message.element_type == TOUCH_ELEM_TYPE_BUTTON) {\n            button_message.event = TOUCH_BUTTON_EVT_ON_RELEASE;\n            memcpy(valid_message.child_msg, &button_message, sizeof(button_message));\n            xQueueSend(monitor.valid_msg_handle, &valid_message, portMAX_DELAY);\n            test_button_event_simulator(valid_message.handle, button_message.event);\n        } else if (valid_message.element_type == TOUCH_ELEM_TYPE_SLIDER) {\n            slider_message.event = TOUCH_SLIDER_EVT_ON_RELEASE;\n            memcpy(valid_message.child_msg, &slider_message, sizeof(slider_message));\n            xQueueSend(monitor.valid_msg_handle, &valid_message, portMAX_DELAY);\n            test_slider_event_simulator(valid_message.handle, slider_message.event, 1);\n        } else if (valid_message.element_type == TOUCH_ELEM_TYPE_MATRIX) {\n            matrix_message.event = TOUCH_MATRIX_EVT_ON_RELEASE;\n            memcpy(valid_message.child_msg, &matrix_message, sizeof(matrix_message));\n            xQueueSend(monitor.valid_msg_handle, &valid_message, portMAX_DELAY);\n            const touch_matrix_message_t *matrix_message_ptr = touch_matrix_get_message(&valid_message);\n            test_matrix_event_simulator(valid_message.handle, matrix_message.event, matrix_message_ptr->position.index);\n        }\n        os_ret = xSemaphoreTake(monitor.response_sig_handle, pdMS_TO_TICKS(500));\n        TEST_ASSERT_MESSAGE(os_ret == pdPASS, \"response queue timeout (500ms)\");\n    }\n\n    TEST_ESP_OK(touch_element_stop());\n    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {\n        TEST_ESP_OK(touch_button_delete(button_handle[i]));\n    }\n    TEST_ESP_OK(touch_slider_delete(slider_handle));\n    TEST_ESP_OK(touch_matrix_delete(matrix_handle));\n    touch_button_uninstall();\n    touch_slider_uninstall();\n    touch_matrix_uninstall();\n\n    while (eTaskGetState(task_handle) == eRunning) {\n        vTaskDelay(pdTICKS_TO_MS(1));\n    }\n    vTaskDelete(task_handle);\n    vQueueDelete(monitor.valid_msg_handle);\n    vSemaphoreDelete(monitor.response_sig_handle);\n    printf(\"Integration test(button + slider + matrix) finish\\n\");\n}\n\nstatic void test_integration_monitor_task(void *arg)\n{\n    test_monitor_t *monitor = (test_monitor_t *)arg;\n    BaseType_t os_ret;\n    touch_elem_message_t current_message, valid_message;\n    while (1) {\n        touch_element_message_receive(&current_message, portMAX_DELAY);\n        os_ret = xQueueReceive(monitor->valid_msg_handle, &valid_message, pdMS_TO_TICKS(500)); //Get the valid message for the verification, 500ms timeout\n        TEST_ASSERT_MESSAGE(os_ret == pdPASS, \"trigger queue timeout (500ms)\");\n        if (current_message.element_type == TOUCH_ELEM_TYPE_BUTTON) {\n            test_button_event_check(&valid_message, &current_message);\n        } else if (current_message.element_type == TOUCH_ELEM_TYPE_SLIDER) {\n            test_slider_event_check(&valid_message, &current_message);\n        } else if (current_message.element_type == TOUCH_ELEM_TYPE_MATRIX) {\n            test_matrix_event_check(&valid_message, &current_message);\n        }\n        xSemaphoreGive(monitor->response_sig_handle);\n    }\n}\n"
  },
  {
    "path": "touch_element/test_apps/main/test_touch_matrix.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <time.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"freertos/queue.h\"\n#include \"freertos/semphr.h\"\n#include \"unity.h\"\n\n#include \"esp_private/touch_element_private.h\"\n#include \"esp_private/touch_sensor_legacy_ll.h\"\n#include \"touch_element/touch_matrix.h\"\n\nstatic const touch_pad_t x_axis_channel[3] = {\n    TOUCH_PAD_NUM5,\n    TOUCH_PAD_NUM7,\n    TOUCH_PAD_NUM9,\n};\nstatic const touch_pad_t y_axis_channel[3] = {\n    TOUCH_PAD_NUM11,\n    TOUCH_PAD_NUM12,\n    TOUCH_PAD_NUM14,\n};\nstatic const float x_axis_channel_sens[3] = {\n    0.1F,\n    0.1F,\n    0.1F,\n};\nstatic const float y_axis_channel_sens[3] = {\n    0.1F,\n    0.1F,\n    0.1F,\n};\nconst uint8_t MATRIX_CHANNEL_NUM_X = sizeof(x_axis_channel) / sizeof(touch_pad_t);\nconst uint8_t MATRIX_CHANNEL_NUM_Y = sizeof(y_axis_channel) / sizeof(touch_pad_t);\n\ntypedef struct {\n    QueueHandle_t valid_msg_handle;\n    SemaphoreHandle_t response_sig_handle;\n} test_monitor_t;\n\n/* ------------------------------------------------------------------------------------------------------------------ */\nvoid test_matrix_event_simulator(touch_matrix_handle_t matrix_handle, touch_matrix_event_t matrix_event, uint32_t pos_index);\nstatic void test_matrix_channel_simulator(touch_pad_t channel, touch_matrix_event_t matrix_event);\nvoid test_matrix_event_check(touch_elem_message_t *valid_message, touch_elem_message_t *current_message);\nstatic void test_matrix_callback_check(touch_matrix_handle_t current_handle, touch_matrix_message_t *current_message, touch_elem_message_t *valid_message);\nvoid test_matrix_event_trigger_and_check(touch_matrix_handle_t handle, touch_matrix_event_t matrix_event, uint32_t pos_index);\nvoid test_matrix_callback_trigger_and_check(touch_matrix_handle_t handle, touch_matrix_event_t matrix_event, uint32_t pos_index, bool should_trigger, test_monitor_t *monitor);\n/* ------------------------------------------------ Dispatch method test -------------------------------------------- */\nstatic void test_matrix_disp_event(void);\nstatic void test_matrix_disp_callback(void);\nstatic void test_matrix_handler(touch_matrix_handle_t handle, touch_matrix_message_t *message, void *arg);\n/* ------------------------------------------------ Run-time test --------------------------------------------------- */\nstatic void test_matrix_event_change_lp(void);\nstatic void test_matrix_callback_change_lp(void);\nstatic void test_matrix_change_lp_handler(touch_matrix_handle_t out_handle, touch_matrix_message_t *out_message, void *arg);\n/* ----------------------------------------------- Random channel trigger test -------------------------------------- */\nstatic void test_matrix_random_channel_trigger(void);\n/* ------------------------------------------------------------------------------------------------------------------ */\n\nTEST_CASE(\"Touch matrix dispatch methods test\", \"[matrix][touch_element]\")\n{\n    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_element_install(&global_config));\n    test_matrix_disp_event();\n    test_matrix_disp_callback();\n    touch_element_uninstall();\n}\n\nTEST_CASE(\"Touch matrix run-time test\", \"[matrix][touch_element]\")\n{\n    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_element_install(&global_config));\n    test_matrix_event_change_lp();\n    test_matrix_callback_change_lp();\n    touch_element_uninstall();\n}\n\nTEST_CASE(\"Touch matrix random channel trigger test\", \"[matrix][touch_element]\")\n{\n    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_element_install(&global_config));\n    test_matrix_random_channel_trigger();\n    touch_element_uninstall();\n}\n\nvoid test_matrix_event_simulator(touch_matrix_handle_t matrix_handle, touch_matrix_event_t matrix_event, uint32_t pos_index)\n{\n    te_matrix_handle_t te_matrix = (te_matrix_handle_t) matrix_handle;\n    touch_pad_t x_channel = te_matrix->device[pos_index / te_matrix->y_channel_num]->channel;\n    touch_pad_t y_channel = te_matrix->device[te_matrix->x_channel_num + (pos_index % te_matrix->y_channel_num)]->channel;\n    if (matrix_event == TOUCH_MATRIX_EVT_ON_PRESS) {\n        touch_ll_set_slope(x_channel, TOUCH_PAD_SLOPE_3);\n        touch_ll_set_tie_option(x_channel, TOUCH_PAD_TIE_OPT_DEFAULT);\n        touch_ll_set_slope(y_channel, TOUCH_PAD_SLOPE_3);\n        touch_ll_set_tie_option(y_channel, TOUCH_PAD_TIE_OPT_DEFAULT);\n    } else if (matrix_event == TOUCH_MATRIX_EVT_ON_RELEASE) {\n        touch_ll_set_slope(x_channel, TOUCH_PAD_SLOPE_7);\n        touch_ll_set_tie_option(x_channel, TOUCH_PAD_TIE_OPT_DEFAULT);\n        touch_ll_set_slope(y_channel, TOUCH_PAD_SLOPE_7);\n        touch_ll_set_tie_option(y_channel, TOUCH_PAD_TIE_OPT_DEFAULT);\n    } else {\n        touch_ll_set_slope(x_channel, TOUCH_PAD_SLOPE_3);\n        touch_ll_set_tie_option(x_channel, TOUCH_PAD_TIE_OPT_DEFAULT);\n        touch_ll_set_slope(y_channel, TOUCH_PAD_SLOPE_3);\n        touch_ll_set_tie_option(y_channel, TOUCH_PAD_TIE_OPT_DEFAULT);\n    }\n}\n\nstatic void test_matrix_channel_simulator(touch_pad_t channel, touch_matrix_event_t matrix_event)\n{\n    if (matrix_event == TOUCH_MATRIX_EVT_ON_PRESS) {\n        touch_ll_set_slope(channel, TOUCH_PAD_SLOPE_3);\n        touch_ll_set_tie_option(channel, TOUCH_PAD_TIE_OPT_DEFAULT);\n    } else if (matrix_event == TOUCH_MATRIX_EVT_ON_RELEASE) {\n        touch_ll_set_slope(channel, TOUCH_PAD_SLOPE_7);\n        touch_ll_set_tie_option(channel, TOUCH_PAD_TIE_OPT_DEFAULT);\n    }\n}\n\nvoid test_matrix_event_check(touch_elem_message_t *valid_message, touch_elem_message_t *current_message)\n{\n    TEST_ASSERT_MESSAGE(current_message->handle == valid_message->handle, \"check handle failed\");\n    TEST_ASSERT_MESSAGE(current_message->element_type == valid_message->element_type, \"check element type failed\");\n    const touch_matrix_message_t *valid_matrix_message = touch_matrix_get_message(valid_message);\n    const touch_matrix_message_t *current_matrix_message = touch_matrix_get_message(current_message);\n    TEST_ASSERT_MESSAGE(current_matrix_message->event == valid_matrix_message->event, \"check event failed\");\n    TEST_ASSERT_MESSAGE(current_matrix_message->position.index == valid_matrix_message->position.index, \"check index failed\");\n    TEST_ASSERT_MESSAGE(current_matrix_message->position.x_axis == valid_matrix_message->position.x_axis, \"check x_axis failed\");\n    TEST_ASSERT_MESSAGE(current_matrix_message->position.y_axis == valid_matrix_message->position.y_axis, \"check y_axis failed\");\n}\n\nstatic inline void test_matrix_callback_check(touch_matrix_handle_t current_handle, touch_matrix_message_t *current_message, touch_elem_message_t *valid_message)\n{\n    const touch_matrix_message_t *valid_matrix_message = touch_matrix_get_message(valid_message);\n    TEST_ASSERT_MESSAGE(valid_message->handle == current_handle, \"check handle failed\");\n    TEST_ASSERT_MESSAGE(valid_message->element_type == TOUCH_ELEM_TYPE_MATRIX, \"check element type failed\");\n    TEST_ASSERT_MESSAGE(valid_matrix_message->event == current_message->event, \"check event failed\");\n    TEST_ASSERT_MESSAGE(valid_matrix_message->position.index == current_message->position.index, \"check index failed\");\n    TEST_ASSERT_MESSAGE(valid_matrix_message->position.x_axis == current_message->position.x_axis, \"check x_axis failed\");\n    TEST_ASSERT_MESSAGE(valid_matrix_message->position.y_axis == current_message->position.y_axis, \"check y_axis failed\");\n}\n\nvoid test_matrix_event_trigger_and_check(touch_matrix_handle_t handle, touch_matrix_event_t matrix_event, uint32_t pos_index)\n{\n    touch_elem_message_t valid_message = {\n        .handle = handle,\n        .element_type = TOUCH_ELEM_TYPE_MATRIX,\n        .arg = NULL\n    };\n    touch_matrix_message_t matrix_message = {\n        .event = matrix_event,\n        .position.index = pos_index,\n        .position.x_axis = pos_index / MATRIX_CHANNEL_NUM_Y,\n        .position.y_axis = pos_index % MATRIX_CHANNEL_NUM_Y\n    };\n    memcpy(valid_message.child_msg, &matrix_message, sizeof(touch_matrix_message_t));  //Construct valid_message\n\n    test_matrix_event_simulator(handle, matrix_event, pos_index);  //Trigger signal\n\n    touch_elem_message_t current_message;\n    te_matrix_handle_t te_matrix = handle;\n    esp_err_t ret = touch_element_message_receive(&current_message, pdMS_TO_TICKS(2 * te_matrix->trigger_thr * 10));  //Get current message for verification\n    TEST_ASSERT_MESSAGE(ret == ESP_OK, \"matrix event receive timeout\");\n\n    test_matrix_event_check(&valid_message, &current_message);  //Verification\n}\n\nvoid test_matrix_callback_trigger_and_check(touch_matrix_handle_t handle, touch_matrix_event_t matrix_event, uint32_t pos_index, bool should_trigger, test_monitor_t *monitor)\n{\n    if (should_trigger) {\n        touch_elem_message_t valid_message = {\n            .handle = handle,\n            .element_type = TOUCH_ELEM_TYPE_MATRIX,\n            .arg = NULL\n        };\n        touch_matrix_message_t matrix_message = {\n            .event = matrix_event,\n            .position.index = pos_index,\n            .position.x_axis = pos_index / MATRIX_CHANNEL_NUM_Y,\n            .position.y_axis = pos_index % MATRIX_CHANNEL_NUM_Y\n        };\n        memcpy(valid_message.child_msg, &matrix_message, sizeof(touch_matrix_message_t));  //Construct valid_message\n        xQueueSend(monitor->valid_msg_handle, &valid_message, portMAX_DELAY);\n    }\n\n    test_matrix_event_simulator(handle, matrix_event, pos_index);  //Trigger signal\n\n    te_matrix_handle_t te_matrix = handle;\n    if (should_trigger) {\n        BaseType_t os_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(2 * te_matrix->trigger_thr * 10));\n        TEST_ASSERT_MESSAGE(os_ret == pdPASS, \"Matrix queue timeout\");\n    } else {\n        BaseType_t os_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(500));\n        TEST_ASSERT_MESSAGE(os_ret == pdFALSE, \"Matrix invalid trigger\");\n    }\n}\n\nstatic void test_matrix_disp_event(void)\n{\n    touch_matrix_handle_t matrix_handle = NULL;\n    touch_matrix_global_config_t global_config = TOUCH_MATRIX_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_matrix_install(&global_config));\n    touch_matrix_config_t matrix_config = {\n        .x_channel_array = x_axis_channel,\n        .y_channel_array = y_axis_channel,\n        .x_sensitivity_array = x_axis_channel_sens,\n        .y_sensitivity_array = y_axis_channel_sens,\n        .x_channel_num = MATRIX_CHANNEL_NUM_X,\n        .y_channel_num = MATRIX_CHANNEL_NUM_Y\n    };\n    TEST_ESP_OK(touch_matrix_create(&matrix_config, &matrix_handle));\n    TEST_ESP_OK(touch_matrix_subscribe_event(matrix_handle, TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_LONGPRESS | TOUCH_ELEM_EVENT_ON_RELEASE, NULL));\n    TEST_ESP_OK(touch_matrix_set_longpress(matrix_handle, 300));\n    TEST_ESP_OK(touch_matrix_set_dispatch_method(matrix_handle, TOUCH_ELEM_DISP_EVENT));\n    TEST_ESP_OK(touch_element_start());\n\n    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1\n\n    srandom((unsigned int)time(NULL));\n    printf(\"Touch matrix event test start\\n\");\n    for (int i = 0; i < 10; i++) {\n        printf(\"Touch matrix event test... (%d/10)\\n\", i + 1);\n        uint32_t button_num = random() % ( MATRIX_CHANNEL_NUM_X * MATRIX_CHANNEL_NUM_Y );\n        test_matrix_event_trigger_and_check(matrix_handle, TOUCH_MATRIX_EVT_ON_PRESS, button_num);\n        test_matrix_event_trigger_and_check(matrix_handle, TOUCH_MATRIX_EVT_ON_LONGPRESS, button_num);\n        test_matrix_event_trigger_and_check(matrix_handle, TOUCH_MATRIX_EVT_ON_RELEASE, button_num);\n    }\n    printf(\"Touch matrix event test finish\\n\");\n\n    TEST_ESP_OK(touch_element_stop());\n    TEST_ESP_OK(touch_matrix_delete(matrix_handle));\n    touch_matrix_uninstall();\n}\n\nstatic void test_matrix_disp_callback(void)\n{\n    test_monitor_t monitor;\n    touch_matrix_handle_t matrix_handle = NULL;\n    monitor.valid_msg_handle = xQueueCreate(10, sizeof(touch_elem_message_t));\n    monitor.response_sig_handle = xSemaphoreCreateBinary();\n    TEST_ASSERT(monitor.valid_msg_handle != NULL || monitor.response_sig_handle != NULL);\n\n    touch_matrix_global_config_t global_config = TOUCH_MATRIX_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_matrix_install(&global_config));\n    touch_matrix_config_t matrix_config = {\n        .x_channel_array = x_axis_channel,\n        .y_channel_array = y_axis_channel,\n        .x_sensitivity_array = x_axis_channel_sens,\n        .y_sensitivity_array = y_axis_channel_sens,\n        .x_channel_num = MATRIX_CHANNEL_NUM_X,\n        .y_channel_num = MATRIX_CHANNEL_NUM_Y\n    };\n    TEST_ESP_OK(touch_matrix_create(&matrix_config, &matrix_handle));\n    TEST_ESP_OK(touch_matrix_subscribe_event(matrix_handle, TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_LONGPRESS | TOUCH_ELEM_EVENT_ON_RELEASE, (void *)&monitor));\n    TEST_ESP_OK(touch_matrix_set_longpress(matrix_handle, 300));\n    TEST_ESP_OK(touch_matrix_set_dispatch_method(matrix_handle, TOUCH_ELEM_DISP_CALLBACK));\n    TEST_ESP_OK(touch_matrix_set_callback(matrix_handle, test_matrix_handler));\n    TEST_ESP_OK(touch_element_start());\n\n    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1\n\n    srandom((unsigned int)time(NULL));\n    printf(\"Touch matrix callback test start\\n\");\n    for (int i = 0; i < 10; i++) {\n        printf(\"Touch matrix callback test... (%d/10)\\n\", i + 1);\n        uint32_t button_num = random() % (MATRIX_CHANNEL_NUM_X * MATRIX_CHANNEL_NUM_Y);\n        test_matrix_callback_trigger_and_check(matrix_handle, TOUCH_MATRIX_EVT_ON_PRESS, button_num, true, &monitor);\n        test_matrix_callback_trigger_and_check(matrix_handle, TOUCH_MATRIX_EVT_ON_LONGPRESS, button_num, true, &monitor);\n        test_matrix_callback_trigger_and_check(matrix_handle, TOUCH_MATRIX_EVT_ON_RELEASE, button_num, true, &monitor);\n    }\n    printf(\"Touch matrix callback test finish\\n\");\n\n    TEST_ESP_OK(touch_element_stop());\n    TEST_ESP_OK(touch_matrix_delete(matrix_handle));\n    touch_matrix_uninstall();\n    vQueueDelete(monitor.valid_msg_handle);\n    vSemaphoreDelete(monitor.response_sig_handle);\n}\n\nstatic void test_matrix_handler(touch_matrix_handle_t handle, touch_matrix_message_t *message, void *arg)\n{\n    test_monitor_t *monitor = (test_monitor_t *)arg;\n    touch_elem_message_t valid_message;\n    BaseType_t os_ret = xQueueReceive(monitor->valid_msg_handle, &valid_message, pdMS_TO_TICKS(200));\n    TEST_ASSERT_MESSAGE(os_ret == pdPASS, \"test_matrix_handler: queue timeout\");\n    test_matrix_callback_check(handle, message, &valid_message);\n    xSemaphoreGive(monitor->response_sig_handle);\n}\n\nstatic void test_matrix_random_channel_trigger(void)\n{\n    test_monitor_t monitor;\n    touch_matrix_handle_t matrix_handle = NULL;\n    monitor.valid_msg_handle = xQueueCreate(10, sizeof(touch_elem_message_t));\n    monitor.response_sig_handle = xSemaphoreCreateBinary();\n    TEST_ASSERT(monitor.valid_msg_handle != NULL || monitor.response_sig_handle != NULL);\n\n    touch_matrix_global_config_t global_config = TOUCH_MATRIX_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_matrix_install(&global_config));\n    touch_matrix_config_t matrix_config = {\n        .x_channel_array = x_axis_channel,\n        .y_channel_array = y_axis_channel,\n        .x_sensitivity_array = x_axis_channel_sens,\n        .y_sensitivity_array = y_axis_channel_sens,\n        .x_channel_num = MATRIX_CHANNEL_NUM_X,\n        .y_channel_num = MATRIX_CHANNEL_NUM_Y\n    };\n    TEST_ESP_OK(touch_matrix_create(&matrix_config, &matrix_handle));\n    TEST_ESP_OK(touch_matrix_subscribe_event(matrix_handle, TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE, (void *) &monitor));\n    TEST_ESP_OK(touch_matrix_set_dispatch_method(matrix_handle, TOUCH_ELEM_DISP_CALLBACK));\n    TEST_ESP_OK(touch_matrix_set_callback(matrix_handle, test_matrix_handler));\n    TEST_ESP_OK(touch_element_start());\n\n    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1\n\n    srandom((unsigned int)time(NULL));\n    printf(\"Touch matrix random channel trigger test start\\n\");\n    for (int i = 0; i < 10; i++) {\n        printf(\"Touch matrix random channel trigger test... (%d/10)\\n\", i + 1);\n        uint32_t channel_index_1 = random() % (MATRIX_CHANNEL_NUM_X + MATRIX_CHANNEL_NUM_Y);\n        uint32_t channel_index_2 = random() % (MATRIX_CHANNEL_NUM_X + MATRIX_CHANNEL_NUM_Y);\n        touch_pad_t channel_1 = (channel_index_1 < MATRIX_CHANNEL_NUM_X) ? x_axis_channel[channel_index_1] : y_axis_channel[channel_index_1 - MATRIX_CHANNEL_NUM_X];\n        touch_pad_t channel_2 = (channel_index_2 < MATRIX_CHANNEL_NUM_X) ? x_axis_channel[channel_index_2] : y_axis_channel[channel_index_2 - MATRIX_CHANNEL_NUM_X];\n        if ((channel_index_1 <= 2 && channel_index_2 <= 2) || (channel_index_1 > 2 && channel_index_2 > 2)) {  //all x channels triggered or all y channels triggered\n            //Should not be triggered\n            BaseType_t os_ret;\n            test_matrix_channel_simulator(channel_1, TOUCH_MATRIX_EVT_ON_PRESS);\n            test_matrix_channel_simulator(channel_2, TOUCH_MATRIX_EVT_ON_PRESS);\n            os_ret = xSemaphoreTake(monitor.response_sig_handle, pdMS_TO_TICKS(500));\n            TEST_ASSERT_MESSAGE(os_ret == pdFAIL, \"Matrix Press event invalid trigger\");\n\n            test_matrix_channel_simulator(channel_1, TOUCH_MATRIX_EVT_ON_RELEASE);\n            test_matrix_channel_simulator(channel_2, TOUCH_MATRIX_EVT_ON_RELEASE);\n            os_ret = xSemaphoreTake(monitor.response_sig_handle, pdMS_TO_TICKS(500));\n            TEST_ASSERT_MESSAGE(os_ret == pdFAIL, \"Matrix Release event invalid trigger\");\n        } else {\n            //Should be triggered\n            uint8_t button_num;\n            if (channel_index_1 <= 2) {\n                button_num = channel_index_1 * matrix_config.y_channel_num + (channel_index_2 - MATRIX_CHANNEL_NUM_X);\n            } else {\n                button_num = channel_index_2 * matrix_config.x_channel_num + (channel_index_1 - MATRIX_CHANNEL_NUM_Y);\n            }\n            test_matrix_callback_trigger_and_check(matrix_handle, TOUCH_MATRIX_EVT_ON_PRESS, button_num, true, &monitor);\n            test_matrix_callback_trigger_and_check(matrix_handle, TOUCH_MATRIX_EVT_ON_RELEASE, button_num, true, &monitor);\n        }\n    }\n    printf(\"Touch matrix random channel trigger test finish\\n\");\n\n    TEST_ESP_OK(touch_element_stop());\n    TEST_ESP_OK(touch_matrix_delete(matrix_handle));\n    touch_matrix_uninstall();\n    vQueueDelete(monitor.valid_msg_handle);\n    vSemaphoreDelete(monitor.response_sig_handle);\n}\n\nstatic void test_matrix_event_change_lp(void)\n{\n    touch_matrix_handle_t matrix_handle = NULL;\n    touch_matrix_global_config_t global_config = TOUCH_MATRIX_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_matrix_install(&global_config));\n    touch_matrix_config_t matrix_config = {\n        .x_channel_array = x_axis_channel,\n        .y_channel_array = y_axis_channel,\n        .x_sensitivity_array = x_axis_channel_sens,\n        .y_sensitivity_array = y_axis_channel_sens,\n        .x_channel_num = MATRIX_CHANNEL_NUM_X,\n        .y_channel_num = MATRIX_CHANNEL_NUM_Y\n    };\n    TEST_ESP_OK(touch_matrix_create(&matrix_config, &matrix_handle));\n    TEST_ESP_OK(touch_matrix_subscribe_event(matrix_handle, TOUCH_ELEM_EVENT_ON_LONGPRESS, NULL));\n    TEST_ESP_OK(touch_matrix_set_dispatch_method(matrix_handle, TOUCH_ELEM_DISP_EVENT));\n    TEST_ESP_OK(touch_element_start());\n\n    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1\n\n    srandom((unsigned int)time(NULL));\n    //10 times random press/longpress/release test\n    printf(\"Touch matrix event change longtime test start\\n\");\n    for (int i = 0; i < 10; i++) {\n        printf(\"Touch matrix event change longtime test... (%d/10)\\n\", i + 1);\n        uint32_t button_num = random() % ( MATRIX_CHANNEL_NUM_X * MATRIX_CHANNEL_NUM_Y );\n        TEST_ESP_OK(touch_matrix_set_longpress(matrix_handle, 200 + (i + 1) * 50));\n        test_matrix_event_trigger_and_check(matrix_handle, TOUCH_MATRIX_EVT_ON_LONGPRESS, button_num);\n        test_matrix_event_simulator(matrix_handle, TOUCH_MATRIX_EVT_ON_RELEASE, button_num); //Reset hardware\n        vTaskDelay(pdMS_TO_TICKS(100));  //Fixme: Waiting for driver core handle release event\n    }\n    printf(\"Touch matrix event change longtime test finish\\n\");\n    TEST_ESP_OK(touch_element_stop());\n    TEST_ESP_OK(touch_matrix_delete(matrix_handle));\n    touch_matrix_uninstall();\n}\n\nstatic void test_matrix_callback_change_lp(void)\n{\n    test_monitor_t monitor;\n    touch_matrix_handle_t matrix_handle = NULL;\n    monitor.valid_msg_handle = xQueueCreate(10, sizeof(touch_elem_message_t));\n    monitor.response_sig_handle = xSemaphoreCreateBinary();\n    TEST_ASSERT(monitor.valid_msg_handle != NULL || monitor.response_sig_handle != NULL);\n\n    touch_matrix_global_config_t global_config = TOUCH_MATRIX_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_matrix_install(&global_config));\n    touch_matrix_config_t matrix_config = {\n        .x_channel_array = x_axis_channel,\n        .y_channel_array = y_axis_channel,\n        .x_sensitivity_array = x_axis_channel_sens,\n        .y_sensitivity_array = y_axis_channel_sens,\n        .x_channel_num = MATRIX_CHANNEL_NUM_X,\n        .y_channel_num = MATRIX_CHANNEL_NUM_Y\n    };\n    TEST_ESP_OK(touch_matrix_create(&matrix_config, &matrix_handle));\n    TEST_ESP_OK(touch_matrix_subscribe_event(matrix_handle, TOUCH_ELEM_EVENT_ON_LONGPRESS, (void *)&monitor));\n    TEST_ESP_OK(touch_matrix_set_longpress(matrix_handle, 300));\n    TEST_ESP_OK(touch_matrix_set_dispatch_method(matrix_handle, TOUCH_ELEM_DISP_CALLBACK));\n    TEST_ESP_OK(touch_matrix_set_callback(matrix_handle, test_matrix_change_lp_handler));\n    TEST_ESP_OK(touch_element_start());\n\n    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1\n\n    srandom((unsigned int)time(NULL));\n    printf(\"Touch matrix callback change longtime test start\\n\");\n    for (int i = 0; i < 10; i++) {\n        printf(\"Touch matrix callback change longtime test... (%d/10)\\n\", i + 1);\n        uint32_t button_num = random() % (MATRIX_CHANNEL_NUM_X * MATRIX_CHANNEL_NUM_Y);\n        test_matrix_callback_trigger_and_check(matrix_handle, TOUCH_MATRIX_EVT_ON_LONGPRESS, button_num, true, &monitor);\n        test_matrix_event_simulator(matrix_handle, TOUCH_MATRIX_EVT_ON_RELEASE, button_num); //Reset hardware\n        vTaskDelay(pdMS_TO_TICKS(100));  //Fixme: Waiting for driver core handle release event\n\n    }\n    printf(\"Touch matrix callback change longtime test finish\\n\");\n\n    TEST_ESP_OK(touch_element_stop());\n    TEST_ESP_OK(touch_matrix_delete(matrix_handle));\n    touch_matrix_uninstall();\n    vQueueDelete(monitor.valid_msg_handle);\n    vSemaphoreDelete(monitor.response_sig_handle);\n}\n\nstatic void test_matrix_change_lp_handler(touch_matrix_handle_t out_handle, touch_matrix_message_t *out_message, void *arg)\n{\n    test_monitor_t *monitor = (test_monitor_t *)arg;\n    touch_elem_message_t valid_message;\n    BaseType_t os_ret = xQueueReceive(monitor->valid_msg_handle, &valid_message, pdMS_TO_TICKS(200));  //500ms timeout\n    TEST_ASSERT_MESSAGE(os_ret == pdPASS, \"test_matrix_handler: queue timeout\");\n    test_matrix_callback_check(out_handle, out_message, &valid_message);\n    xSemaphoreGive(monitor->response_sig_handle);\n    TEST_ESP_OK(touch_matrix_set_longpress(valid_message.handle, 300)); // Always 300ms\n}\n"
  },
  {
    "path": "touch_element/test_apps/main/test_touch_slider.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Unlicense OR CC0-1.0\n */\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <time.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n#include \"freertos/queue.h\"\n#include \"freertos/semphr.h\"\n#include \"unity.h\"\n\n#include \"esp_private/touch_element_private.h\"\n#include \"esp_private/touch_sensor_legacy_ll.h\"\n#include \"touch_element/touch_slider.h\"\n\nstatic const touch_pad_t slider_channel_array[5] = {\n    TOUCH_PAD_NUM1,\n    TOUCH_PAD_NUM2,\n    TOUCH_PAD_NUM3,\n    TOUCH_PAD_NUM4,\n    TOUCH_PAD_NUM5\n};\nstatic const float slider_sens_array[5] = {\n    0.1F,\n    0.1F,\n    0.1F,\n    0.1F,\n    0.1F\n};\nconst uint8_t SLIDER_CHANNEL_NUM = sizeof(slider_channel_array) / sizeof(touch_pad_t);\n\ntypedef struct {\n    QueueHandle_t valid_msg_handle;\n    SemaphoreHandle_t response_sig_handle;\n} test_monitor_t;\n\n/* ------------------------------------------------------------------------------------------------------------------ */\nvoid test_slider_event_simulator(touch_slider_handle_t slider_handle, touch_slider_event_t slider_event, uint32_t random);\nvoid test_slider_event_check(touch_elem_message_t *valid_message, touch_elem_message_t *current_message);\nstatic void test_slider_callback_check(touch_slider_handle_t current_handle, touch_slider_message_t *current_message, touch_elem_message_t *valid_message);\nvoid test_slider_event_trigger_and_check(touch_slider_handle_t handle, touch_slider_event_t slider_event, uint32_t random_channel);\nvoid test_slider_callback_trigger_and_check(touch_slider_handle_t handle, touch_slider_event_t slider_event, bool should_trigger, test_monitor_t *monitor, uint32_t random_channel);\n/* ------------------------------------------------ Dispatch method test -------------------------------------------- */\nstatic void test_slider_disp_event(void);\nstatic void test_slider_disp_callback(void);\nstatic void test_slider_handler(touch_slider_handle_t handle, touch_slider_message_t *message, void *arg);\n/* ------------------------------------------------------------------------------------------------------------------ */\n\nTEST_CASE(\"Touch slider dispatch methods test\", \"[slider][touch_element]\")\n{\n    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_element_install(&global_config));\n    test_slider_disp_event();\n    test_slider_disp_callback();\n    touch_element_uninstall();\n}\n\nvoid test_slider_event_simulator(touch_slider_handle_t slider_handle, touch_slider_event_t slider_event, uint32_t random)\n{\n    te_slider_handle_t te_slider = (te_slider_handle_t) slider_handle;\n    touch_pad_t channel = te_slider->device[random % te_slider->channel_sum]->channel;\n    if (slider_event == TOUCH_SLIDER_EVT_ON_PRESS) {\n        touch_ll_set_slope(channel, TOUCH_PAD_SLOPE_3);\n        touch_ll_set_tie_option(channel, TOUCH_PAD_TIE_OPT_DEFAULT);\n    } else if (slider_event == TOUCH_SLIDER_EVT_ON_RELEASE) {\n        touch_ll_set_slope(channel, TOUCH_PAD_SLOPE_7);\n        touch_ll_set_tie_option(channel, TOUCH_PAD_TIE_OPT_DEFAULT);\n    }\n}\n\nvoid test_slider_event_check(touch_elem_message_t *valid_message, touch_elem_message_t *current_message)\n{\n    TEST_ASSERT_MESSAGE(current_message->handle == valid_message->handle, \"check handle failed\");\n    TEST_ASSERT_MESSAGE(current_message->element_type == valid_message->element_type, \"check element type failed\");\n    const touch_slider_message_t *valid_slider_message = touch_slider_get_message(valid_message);\n    const touch_slider_message_t *current_slider_message = touch_slider_get_message(current_message);\n    TEST_ASSERT_MESSAGE(current_slider_message->event == valid_slider_message->event, \"check event failed\");\n}\n\nstatic void test_slider_callback_check(touch_slider_handle_t current_handle, touch_slider_message_t *current_message, touch_elem_message_t *valid_message)\n{\n    const touch_slider_message_t *valid_slider_message = touch_slider_get_message(valid_message);\n    TEST_ASSERT_MESSAGE(valid_message->handle == current_handle, \"check handle failed\");\n    TEST_ASSERT_MESSAGE(valid_message->element_type == TOUCH_ELEM_TYPE_SLIDER, \"check element type failed\");\n    TEST_ASSERT_MESSAGE(valid_slider_message->event == current_message->event, \"check event failed\");\n}\n\nvoid test_slider_event_trigger_and_check(touch_slider_handle_t handle, touch_slider_event_t slider_event, uint32_t random_channel)\n{\n    touch_elem_message_t valid_message, current_message;\n    touch_slider_message_t slider_message;\n    valid_message.handle = handle;\n    valid_message.element_type = TOUCH_ELEM_TYPE_SLIDER;\n    slider_message.event = slider_event;\n    memcpy(valid_message.child_msg, &slider_message, sizeof(touch_slider_message_t));\n    test_slider_event_simulator(handle, slider_event, random_channel);\n    esp_err_t ret = touch_element_message_receive(&current_message, 300);\n    TEST_ASSERT_MESSAGE(ret == ESP_OK, \"slider event receive timeout\");\n    test_slider_event_check(&valid_message, &current_message);\n}\n\nvoid test_slider_callback_trigger_and_check(touch_slider_handle_t handle, touch_slider_event_t slider_event, bool should_trigger, test_monitor_t *monitor, uint32_t random_channel)\n{\n    if (should_trigger) {\n        touch_elem_message_t valid_message = {\n            .handle = handle,\n            .element_type = TOUCH_ELEM_TYPE_SLIDER,\n            .arg = NULL\n        };\n        touch_slider_message_t slider_message = {\n            .event = slider_event,\n            .position = 0  //No use\n        };\n        memcpy(valid_message.child_msg, &slider_message, sizeof(touch_slider_message_t));  //Construct valid_message\n        xQueueSend(monitor->valid_msg_handle, &valid_message, portMAX_DELAY);\n    }\n\n    test_slider_event_simulator(handle, slider_event, random_channel);  //Trigger signal\n\n    BaseType_t os_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(300));\n    if (should_trigger) {\n        TEST_ASSERT_MESSAGE(os_ret == pdPASS, \"Button queue timeout\");\n    } else {\n        TEST_ASSERT_MESSAGE(os_ret == pdFALSE, \"Button invalid trigger\");\n    }\n}\n\n\nstatic void test_slider_disp_event(void)\n{\n    touch_slider_handle_t slider_handle;\n    touch_slider_global_config_t global_config = TOUCH_SLIDER_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_slider_install(&global_config));\n    /*< Create Touch Slider */\n    touch_slider_config_t slider_config = {\n        .channel_array = slider_channel_array,\n        .sensitivity_array = slider_sens_array,\n        .channel_num = SLIDER_CHANNEL_NUM,\n        .position_range = 101\n    };\n    TEST_ESP_OK(touch_slider_create(&slider_config, &slider_handle));\n    TEST_ESP_OK(touch_slider_subscribe_event(slider_handle, TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE, (void *) slider_handle));\n    TEST_ESP_OK(touch_slider_set_dispatch_method(slider_handle, TOUCH_ELEM_DISP_EVENT));\n    TEST_ESP_OK(touch_element_start());\n\n    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1\n\n    srandom((unsigned int)time(NULL));\n    //10 times random (x channels) press/release test\n    printf(\"Touch slider event test start\\n\");\n    for (int i = 0; i < 10; i++) {\n        printf(\"Touch slider event test... (%d/10)\\n\", i + 1);\n        uint32_t random_channel = random() % SLIDER_CHANNEL_NUM;\n        test_slider_event_trigger_and_check(slider_handle, TOUCH_SLIDER_EVT_ON_PRESS, random_channel);\n        test_slider_event_trigger_and_check(slider_handle, TOUCH_SLIDER_EVT_ON_RELEASE, random_channel);\n    }\n    printf(\"Touch slider event test finish\\n\");\n    TEST_ESP_OK(touch_element_stop());\n    TEST_ESP_OK(touch_slider_delete(slider_handle));\n    touch_slider_uninstall();\n}\n\n\nstatic void test_slider_disp_callback(void)\n{\n    test_monitor_t monitor;\n    monitor.valid_msg_handle = xQueueCreate(10, sizeof(touch_elem_message_t));\n    monitor.response_sig_handle = xSemaphoreCreateBinary();\n    TEST_ASSERT(monitor.valid_msg_handle != NULL || monitor.response_sig_handle != NULL);\n\n    touch_slider_handle_t slider_handle;\n    touch_slider_global_config_t global_config = TOUCH_SLIDER_GLOBAL_DEFAULT_CONFIG();\n    TEST_ESP_OK(touch_slider_install(&global_config));\n    touch_slider_config_t slider_config = {\n        .channel_array = slider_channel_array,\n        .sensitivity_array = slider_sens_array,\n        .channel_num = SLIDER_CHANNEL_NUM,\n        .position_range = 101\n    };\n    TEST_ESP_OK(touch_slider_create(&slider_config, &slider_handle));\n    TEST_ESP_OK(touch_slider_subscribe_event(slider_handle, TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE, (void *) &monitor));\n    TEST_ESP_OK(touch_slider_set_dispatch_method(slider_handle, TOUCH_ELEM_DISP_CALLBACK));\n    TEST_ESP_OK(touch_slider_set_callback(slider_handle, test_slider_handler));\n    TEST_ESP_OK(touch_element_start());\n\n    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1\n\n    srandom((unsigned int)time(NULL));\n    printf(\"Touch slider callback test start\\n\");\n    for (int i = 0; i < 10; i++) {\n        printf(\"Touch slider callback test... (%d/10)\\n\", i + 1);\n        uint32_t random_channel = random() % SLIDER_CHANNEL_NUM;\n        test_slider_callback_trigger_and_check(slider_handle, TOUCH_SLIDER_EVT_ON_PRESS, true, &monitor, random_channel);\n        test_slider_callback_trigger_and_check(slider_handle, TOUCH_SLIDER_EVT_ON_RELEASE, true, &monitor, random_channel);\n    }\n    printf(\"Touch slider callback test finish\\n\");\n\n    TEST_ESP_OK(touch_element_stop());\n    TEST_ESP_OK(touch_slider_delete(slider_handle));\n    touch_slider_uninstall();\n    vQueueDelete(monitor.valid_msg_handle);\n    vSemaphoreDelete(monitor.response_sig_handle);\n}\n\nstatic void test_slider_handler(touch_slider_handle_t handle, touch_slider_message_t *message, void *arg)\n{\n    test_monitor_t *monitor = (test_monitor_t *)arg;\n    touch_elem_message_t valid_message;\n    BaseType_t os_ret = xQueueReceive(monitor->valid_msg_handle, &valid_message, pdMS_TO_TICKS(200));  //Get the valid message for verification, 200ms timeout\n    TEST_ASSERT_MESSAGE(os_ret == pdPASS, \"test_slider_handler: queue timeout\");\n\n    test_slider_callback_check(handle, message, &valid_message);  //Verification\n\n    xSemaphoreGive(monitor->response_sig_handle);\n}\n"
  },
  {
    "path": "touch_element/test_apps/pytest_touch_element.py",
    "content": "# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Unlicense OR CC0-1.0\nimport pytest\nfrom pytest_embedded import Dut\nimport glob\nfrom pathlib import Path\n\n\n@pytest.mark.generic\n@pytest.mark.skipif(\n    not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),\n    reason=\"Skip the idf version that not build\"\n)\ndef test_touch_element(dut: Dut) -> None:\n    dut.run_all_single_board_cases(timeout=120)\n"
  },
  {
    "path": "touch_element/test_apps/sdkconfig.defaults",
    "content": "CONFIG_FREERTOS_HZ=1000\nCONFIG_ESP_TASK_WDT_EN=n\nCONFIG_ESP_MAIN_TASK_STACK_SIZE=8192\n"
  },
  {
    "path": "touch_element/touch_button.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include <sys/queue.h>\n#include <inttypes.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/semphr.h\"\n#include \"esp_log.h\"\n#include \"esp_private/touch_element_private.h\"\n\ntypedef struct te_button_handle_list {\n    te_button_handle_t button_handle;               //Button handle\n    SLIST_ENTRY(te_button_handle_list) next;        //Button handle list entry\n} te_button_handle_list_t;\n\ntypedef struct {\n    SLIST_HEAD(te_button_handle_list_head, te_button_handle_list) handle_list;      //Button handle (instance) list\n    touch_button_global_config_t *global_config;                                    //Button global configuration\n    SemaphoreHandle_t mutex;                                                        //Button object mutex\n} te_button_obj_t;\n\nstatic te_button_obj_t *s_te_btn_obj = NULL;    //Button object\n/* ---------------------------------------- Button handle(instance) methods ----------------------------------------- */\nstatic bool button_channel_check(te_button_handle_t button_handle, touch_pad_t channel_num);\nstatic esp_err_t button_set_threshold(te_button_handle_t button_handle);\nstatic inline te_state_t button_get_state(te_dev_t *device);\nstatic void button_reset_state(te_button_handle_t button_handle);\nstatic void button_update_state(te_button_handle_t button_handle, touch_pad_t channel_num, te_state_t channel_state);\nstatic void button_proc_state(te_button_handle_t button_handle);\nstatic void button_event_give(te_button_handle_t button_handle);\nstatic inline void button_dispatch(te_button_handle_t button_handle, touch_elem_dispatch_t dispatch_method);\n/* ------------------------------------------ Button object(class) methods ------------------------------------------ */\nstatic esp_err_t button_object_add_instance(te_button_handle_t button_handle);\nstatic esp_err_t button_object_remove_instance(te_button_handle_t button_handle);\nstatic bool button_object_check_channel(touch_pad_t channel_num);\nstatic esp_err_t button_object_set_threshold(void);\nstatic void button_object_process_state(void);\nstatic void button_object_update_state(touch_pad_t channel_num, te_state_t channel_state);\n/* ------------------------------------------------------------------------------------------------------------------ */\n\nesp_err_t touch_button_install(const touch_button_global_config_t *global_config)\n{\n    TE_CHECK(te_system_check_state() == true, ESP_ERR_INVALID_STATE);\n    TE_CHECK(global_config != NULL, ESP_ERR_INVALID_ARG);\n    //Fixme: Make it thread-safe\n    s_te_btn_obj = (te_button_obj_t *)calloc(1, sizeof(te_button_obj_t));\n    TE_CHECK(s_te_btn_obj != NULL, ESP_ERR_NO_MEM);\n    s_te_btn_obj->global_config = (touch_button_global_config_t *)calloc(1, sizeof(touch_button_global_config_t));\n    s_te_btn_obj->mutex = xSemaphoreCreateMutex();\n    TE_CHECK_GOTO(s_te_btn_obj->global_config != NULL && s_te_btn_obj->mutex != NULL, cleanup);\n    xSemaphoreTake(s_te_btn_obj->mutex, portMAX_DELAY);\n    SLIST_INIT(&s_te_btn_obj->handle_list);\n    memcpy(s_te_btn_obj->global_config, global_config, sizeof(touch_button_global_config_t));\n    te_object_methods_t button_methods = {\n        .handle = s_te_btn_obj,\n        .check_channel = button_object_check_channel,\n        .set_threshold = button_object_set_threshold,\n        .process_state = button_object_process_state,\n        .update_state = button_object_update_state\n    };\n    te_object_method_register(&button_methods, TE_CLS_TYPE_BUTTON);\n    xSemaphoreGive(s_te_btn_obj->mutex);\n    return ESP_OK;\n\ncleanup:\n    TE_FREE_AND_NULL(s_te_btn_obj->global_config);\n    if (s_te_btn_obj->mutex != NULL) {\n        vSemaphoreDelete(s_te_btn_obj->mutex);\n    }\n    TE_FREE_AND_NULL(s_te_btn_obj);\n    return ESP_ERR_NO_MEM;\n}\n\nvoid touch_button_uninstall(void)\n{\n    xSemaphoreTake(s_te_btn_obj->mutex, portMAX_DELAY);\n    if (s_te_btn_obj == NULL) {\n        xSemaphoreGive(s_te_btn_obj->mutex);\n        return;\n    }\n    te_object_method_unregister(TE_CLS_TYPE_BUTTON);\n    free(s_te_btn_obj->global_config);\n    s_te_btn_obj->global_config = NULL;\n    while (!SLIST_EMPTY(&s_te_btn_obj->handle_list)) {\n        SLIST_REMOVE_HEAD(&s_te_btn_obj->handle_list, next);\n    }\n    xSemaphoreGive(s_te_btn_obj->mutex);\n    vSemaphoreDelete(s_te_btn_obj->mutex);\n    free(s_te_btn_obj);\n    s_te_btn_obj = NULL;\n}\n\nesp_err_t touch_button_create(const touch_button_config_t *button_config, touch_button_handle_t *button_handle)\n{\n    TE_CHECK(s_te_btn_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(button_handle != NULL && button_config != NULL, ESP_ERR_INVALID_ARG);\n    TE_CHECK(button_config->channel_num > TOUCH_PAD_NUM0 &&\n             button_config->channel_num < TOUCH_PAD_MAX &&\n             button_config->channel_sens > 0,\n             ESP_ERR_INVALID_ARG);\n    TE_CHECK(te_object_check_channel(&button_config->channel_num, 1) == false, ESP_ERR_INVALID_ARG);\n    te_button_handle_t te_button = (te_button_handle_t)calloc(1, sizeof(struct te_button_s));\n    TE_CHECK(te_button != NULL, ESP_ERR_NO_MEM);\n\n    esp_err_t ret = ESP_ERR_NO_MEM;\n    te_button->config = (te_button_handle_config_t *)calloc(1, sizeof(te_button_handle_config_t));\n    te_button->device = (te_dev_t *)calloc(1, sizeof(te_dev_t));\n    TE_CHECK_GOTO(te_button->config != NULL && te_button->device != NULL, cleanup);\n\n    ret = te_dev_init(&te_button->device, 1, TOUCH_ELEM_TYPE_BUTTON,\n                      &button_config->channel_num, &button_config->channel_sens, TE_DEFAULT_THRESHOLD_DIVIDER(s_te_btn_obj));\n    TE_CHECK_GOTO(ret == ESP_OK, cleanup);\n\n    te_button->config->event_mask = TOUCH_ELEM_EVENT_NONE;\n    te_button->config->dispatch_method = TOUCH_ELEM_DISP_MAX;\n    te_button->config->callback = NULL;\n    te_button->config->arg = NULL;\n    te_button->current_state = TE_STATE_IDLE;\n    te_button->last_state = TE_STATE_IDLE;\n    te_button->event = TOUCH_BUTTON_EVT_MAX;\n    te_button->trigger_cnt = 0;\n    te_button->trigger_thr = 0xffffffff;\n    ret = button_object_add_instance(te_button);\n    TE_CHECK_GOTO(ret == ESP_OK, cleanup);\n    *button_handle = (touch_elem_handle_t)te_button;\n    ESP_LOGD(TE_DEBUG_TAG, \"channel: %d, channel_sens: %f\", button_config->channel_num, button_config->channel_sens);\n    return ESP_OK;\n\ncleanup:\n    TE_FREE_AND_NULL(te_button->config);\n    TE_FREE_AND_NULL(te_button->device);\n    TE_FREE_AND_NULL(te_button);\n    return ret;\n}\n\nesp_err_t touch_button_delete(touch_button_handle_t button_handle)\n{\n    TE_CHECK(s_te_btn_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(button_handle != NULL, ESP_ERR_INVALID_ARG);\n    esp_err_t ret = button_object_remove_instance(button_handle);\n    TE_CHECK(ret == ESP_OK, ret);\n    te_button_handle_t te_button = (te_button_handle_t)button_handle;\n    te_dev_deinit(&te_button->device, 1);\n    free(te_button->config);\n    free(te_button->device);\n    free(te_button);\n    return ESP_OK;\n}\n\nesp_err_t touch_button_set_dispatch_method(touch_button_handle_t button_handle, touch_elem_dispatch_t dispatch_method)\n{\n    TE_CHECK(s_te_btn_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(button_handle != NULL, ESP_ERR_INVALID_ARG);\n    TE_CHECK(dispatch_method >= TOUCH_ELEM_DISP_EVENT && dispatch_method <= TOUCH_ELEM_DISP_MAX, ESP_ERR_INVALID_ARG);\n    xSemaphoreTake(s_te_btn_obj->mutex, portMAX_DELAY);\n    te_button_handle_t te_button = (te_button_handle_t)button_handle;\n    te_button->config->dispatch_method = dispatch_method;\n    xSemaphoreGive(s_te_btn_obj->mutex);\n    return ESP_OK;\n}\n\nesp_err_t touch_button_subscribe_event(touch_button_handle_t button_handle, uint32_t event_mask, void *arg)\n{\n    TE_CHECK(s_te_btn_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(button_handle != NULL, ESP_ERR_INVALID_ARG);\n    if (!(event_mask & TOUCH_ELEM_EVENT_ON_PRESS) && !(event_mask & TOUCH_ELEM_EVENT_ON_RELEASE) &&\n            !(event_mask & TOUCH_ELEM_EVENT_ON_LONGPRESS) && !(event_mask & TOUCH_ELEM_EVENT_NONE)) {\n        ESP_LOGE(TE_TAG, \"Touch button only support TOUCH_ELEM_EVENT_ON_PRESS, \"\n                 \"TOUCH_ELEM_EVENT_ON_RELEASE, TOUCH_ELEM_EVENT_ON_LONGPRESS event mask\");\n        return ESP_ERR_INVALID_ARG;\n    }\n    if (event_mask & TOUCH_ELEM_EVENT_ON_LONGPRESS) {\n        touch_button_set_longpress(button_handle, TE_DEFAULT_LONGPRESS_TIME(s_te_btn_obj));  //set the default time(1000ms) for long press\n    }\n    xSemaphoreTake(s_te_btn_obj->mutex, portMAX_DELAY);\n    te_button_handle_t te_button = (te_button_handle_t)button_handle;\n    te_button->config->event_mask = event_mask;\n    te_button->config->arg = arg;\n    xSemaphoreGive(s_te_btn_obj->mutex);\n    return ESP_OK;\n}\n\nesp_err_t touch_button_set_callback(touch_button_handle_t button_handle, touch_button_callback_t button_callback)\n{\n    TE_CHECK(s_te_btn_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(button_handle != NULL, ESP_ERR_INVALID_ARG);\n    TE_CHECK(button_callback != NULL, ESP_ERR_INVALID_ARG);\n    te_button_handle_t te_button = (te_button_handle_t)button_handle;\n    xSemaphoreTake(s_te_btn_obj->mutex, portMAX_DELAY);\n    te_button->config->callback = button_callback;\n    xSemaphoreGive(s_te_btn_obj->mutex);\n    return ESP_OK;\n}\n\nesp_err_t touch_button_set_longpress(touch_button_handle_t button_handle, uint32_t threshold_time)\n{\n    TE_CHECK(s_te_btn_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(button_handle != NULL, ESP_ERR_INVALID_ARG);\n    TE_CHECK(threshold_time > 0, ESP_ERR_INVALID_ARG);\n    te_button_handle_t te_button = (te_button_handle_t)button_handle;\n    touch_elem_dispatch_t dispatch_method = te_button->config->dispatch_method;\n    if (dispatch_method == TOUCH_ELEM_DISP_EVENT) {\n        xSemaphoreTake(s_te_btn_obj->mutex, portMAX_DELAY);\n    }\n    uint8_t timer_period = te_get_timer_period();\n    te_button->trigger_thr = threshold_time / timer_period;\n    if (dispatch_method == TOUCH_ELEM_DISP_EVENT) {\n        xSemaphoreGive(s_te_btn_obj->mutex);\n    }\n    return ESP_OK;\n}\n\nconst touch_button_message_t *touch_button_get_message(const touch_elem_message_t *element_message)\n{\n    return (touch_button_message_t *)&element_message->child_msg;\n    _Static_assert(sizeof(element_message->child_msg) >= sizeof(touch_button_message_t), \"Message size overflow\");\n}\n\nstatic bool button_object_check_channel(touch_pad_t channel_num)\n{\n    te_button_handle_list_t *item;\n    SLIST_FOREACH(item, &s_te_btn_obj->handle_list, next) {\n        if (button_channel_check(item->button_handle, channel_num)) {\n            return true;\n        }\n    }\n    return false;\n}\n\nstatic esp_err_t button_object_set_threshold(void)\n{\n    esp_err_t ret = ESP_OK;\n    te_button_handle_list_t *item;\n    SLIST_FOREACH(item, &s_te_btn_obj->handle_list, next) {\n        ret = button_set_threshold(item->button_handle);\n        if (ret != ESP_OK) {\n            break;\n        }\n    }\n    return ret;\n}\n\nstatic void button_object_process_state(void)\n{\n    te_button_handle_list_t *item;\n    SLIST_FOREACH(item, &s_te_btn_obj->handle_list, next) {\n        if (waterproof_check_mask_handle(item->button_handle)) {\n            button_reset_state(item->button_handle);\n            continue;\n        }\n        button_proc_state(item->button_handle);\n    }\n}\n\nstatic void button_object_update_state(touch_pad_t channel_num, te_state_t channel_state)\n{\n    te_button_handle_list_t *item;\n    SLIST_FOREACH(item, &s_te_btn_obj->handle_list, next) {\n        if (waterproof_check_mask_handle(item->button_handle)) {\n            continue;\n        }\n        button_update_state(item->button_handle, channel_num, channel_state);\n    }\n}\n\nstatic esp_err_t button_object_add_instance(te_button_handle_t button_handle)\n{\n    te_button_handle_list_t *item = (te_button_handle_list_t *)calloc(1, sizeof(te_button_handle_list_t));\n    TE_CHECK(item != NULL, ESP_ERR_NO_MEM);\n    item->button_handle = button_handle;\n    xSemaphoreTake(s_te_btn_obj->mutex, portMAX_DELAY);\n    SLIST_INSERT_HEAD(&s_te_btn_obj->handle_list, item, next);\n    xSemaphoreGive(s_te_btn_obj->mutex);\n    return ESP_OK;\n}\n\nstatic esp_err_t button_object_remove_instance(te_button_handle_t button_handle)\n{\n    esp_err_t ret = ESP_ERR_NOT_FOUND;\n    te_button_handle_list_t *item;\n    SLIST_FOREACH(item, &s_te_btn_obj->handle_list, next) {\n        if (button_handle == item->button_handle) {\n            xSemaphoreTake(s_te_btn_obj->mutex, portMAX_DELAY);\n            SLIST_REMOVE(&s_te_btn_obj->handle_list, item, te_button_handle_list, next);\n            xSemaphoreGive(s_te_btn_obj->mutex);\n            free(item);\n            ret = ESP_OK;\n            break;\n        }\n    }\n    return ret;\n}\n\nbool is_button_object_handle(touch_elem_handle_t element_handle)\n{\n    te_button_handle_list_t *item;\n    xSemaphoreTake(s_te_btn_obj->mutex, portMAX_DELAY);\n    SLIST_FOREACH(item, &s_te_btn_obj->handle_list, next) {\n        if (element_handle == item->button_handle) {\n            xSemaphoreGive(s_te_btn_obj->mutex);\n            return true;\n        }\n    }\n    xSemaphoreGive(s_te_btn_obj->mutex);\n    return false;\n}\n\nstatic bool button_channel_check(te_button_handle_t button_handle, touch_pad_t channel_num)\n{\n    return (channel_num == button_handle->device->channel);\n}\n\nstatic esp_err_t button_set_threshold(te_button_handle_t button_handle)\n{\n    return te_dev_set_threshold(button_handle->device);\n}\n\nstatic void button_update_state(te_button_handle_t button_handle, touch_pad_t channel_num, te_state_t channel_state)\n{\n    te_dev_t *device = button_handle->device;\n    if (channel_num != device->channel) {\n        return;\n    }\n    device->state = channel_state;\n}\n\nstatic void button_reset_state(te_button_handle_t button_handle)\n{\n    button_handle->trigger_cnt = 0;\n    button_handle->current_state = TE_STATE_IDLE;\n    button_handle->device->state = TE_STATE_IDLE;\n}\n\nstatic void button_event_give(te_button_handle_t button_handle)\n{\n    touch_elem_message_t element_message;\n    touch_button_message_t button_message = {\n        .event = button_handle->event\n    };\n    element_message.handle = (touch_elem_handle_t)button_handle;\n    element_message.element_type = TOUCH_ELEM_TYPE_BUTTON;\n    element_message.arg = button_handle->config->arg;\n    memcpy(element_message.child_msg, &button_message, sizeof(button_message));\n    te_event_give(element_message);\n}\n\nstatic inline void button_dispatch(te_button_handle_t button_handle, touch_elem_dispatch_t dispatch_method)\n{\n    if (dispatch_method == TOUCH_ELEM_DISP_EVENT) {\n        button_event_give(button_handle);  //Event queue\n    } else if (dispatch_method == TOUCH_ELEM_DISP_CALLBACK) {\n        touch_button_message_t button_info;\n        button_info.event = button_handle->event;\n        button_handle->config->callback(button_handle, &button_info, button_handle->config->arg);  //Event callback\n    }\n}\n\nvoid button_enable_wakeup_calibration(te_button_handle_t button_handle, bool en)\n{\n    button_handle->device->is_use_last_threshold = !en;\n}\n\n/**\n * @brief Button process\n *\n * This function will process the button state and maintain a button FSM:\n *              IDLE ----> Press ----> Release ----> IDLE\n *\n * The state transition procedure is as follow:\n *       (channel state ----> button state)\n *\n * TODO: add state transition diagram\n */\nstatic void button_proc_state(te_button_handle_t button_handle)\n{\n    uint32_t event_mask = button_handle->config->event_mask;\n    touch_elem_dispatch_t dispatch_method = button_handle->config->dispatch_method;\n\n    BaseType_t mux_ret = xSemaphoreTake(s_te_btn_obj->mutex, 0);\n    if (mux_ret != pdPASS) {\n        return;\n    }\n\n    button_handle->current_state = button_get_state(button_handle->device);\n\n    if (button_handle->current_state == TE_STATE_PRESS) {\n        if (button_handle->last_state == TE_STATE_IDLE) {  //IDLE ---> Press = On_Press\n            ESP_LOGD(TE_DEBUG_TAG, \"button press\");\n            if (event_mask & TOUCH_ELEM_EVENT_ON_PRESS) {\n                button_handle->event = TOUCH_BUTTON_EVT_ON_PRESS;\n                button_dispatch(button_handle, dispatch_method);\n            }\n        } else if (button_handle->last_state == TE_STATE_PRESS) {  //Press ---> Press = On_LongPress\n            if (event_mask & TOUCH_ELEM_EVENT_ON_LONGPRESS) {\n                if (++button_handle->trigger_cnt >= button_handle->trigger_thr) {\n                    ESP_LOGD(TE_DEBUG_TAG, \"button longpress\");\n                    button_handle->event = TOUCH_BUTTON_EVT_ON_LONGPRESS;\n                    button_dispatch(button_handle, dispatch_method);\n                    button_handle->trigger_cnt = 0;\n                }\n            }\n        }\n    } else if (button_handle->current_state == TE_STATE_RELEASE) {\n        if (button_handle->last_state == TE_STATE_PRESS) {  //Press ---> Release = On_Release\n            ESP_LOGD(TE_DEBUG_TAG, \"button release\");\n            if (event_mask & TOUCH_ELEM_EVENT_ON_RELEASE) {\n                button_handle->event = TOUCH_BUTTON_EVT_ON_RELEASE;\n                button_dispatch(button_handle, dispatch_method);\n            }\n        } else if (button_handle->last_state == TE_STATE_RELEASE) { // Release ---> Release = On_IDLE (Not dispatch)\n            button_reset_state(button_handle); //Reset the button state for the next time touch action detection\n        }\n    } else if (button_handle->current_state == TE_STATE_IDLE) {\n        if (button_handle->last_state == TE_STATE_RELEASE) {  //Release ---> IDLE = On_IDLE (Not dispatch)\n            //Nothing\n        } else if (button_handle->last_state == TE_STATE_IDLE) { //IDLE ---> IDLE = Running IDLE (Not dispatch)\n            //Nothing\n        }\n    }\n    button_handle->last_state = button_handle->current_state;\n    xSemaphoreGive(s_te_btn_obj->mutex);\n}\n\nstatic inline te_state_t button_get_state(te_dev_t *device)\n{\n    te_state_t button_state;\n    if (device->state == TE_STATE_PRESS) {\n        button_state =  TE_STATE_PRESS;\n    } else if (device->state == TE_STATE_RELEASE) {\n        button_state = TE_STATE_RELEASE;\n    } else {\n        button_state = TE_STATE_IDLE;\n    }\n    return button_state;\n}\n"
  },
  {
    "path": "touch_element/touch_element.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include <inttypes.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/semphr.h\"\n#include \"freertos/queue.h\"\n#include \"esp_sleep.h\"\n#include \"esp_timer.h\"\n#include \"esp_check.h\"\n#include \"esp_intr_alloc.h\"\n#include \"driver/rtc_io.h\"\n#include \"esp_private/rtc_ctrl.h\"\n#include \"esp_private/gpio.h\"\n#include \"soc/rtc_cntl_reg.h\"\n#include \"esp_private/touch_sensor_legacy_hal.h\"\n#include \"esp_private/touch_element_private.h\"\n#include \"esp_rom_sys.h\"\n\n\n#define TE_CLASS_ITEM(cls, cls_type, cls_item)  ((&((cls)[cls_type]))->cls_item)\n\n#define TE_CLASS_FOREACH(cls_var, cls_start, cls_end)                         \\\n    for ((cls_var) = (cls_start);                                             \\\n        (cls_var) < (cls_end);                                                \\\n        (cls_var)++)\n\n#define TE_CLS_METHODS_INITIALIZER(cls, cls_start, cls_end)  do {             \\\n    typeof(cls_start) cls_method;                                             \\\n    TE_CLASS_FOREACH(cls_method, cls_start, cls_end) {                        \\\n        TE_CLASS_ITEM(cls, cls_method, handle) = NULL;                        \\\n    }                                                                         \\\n} while (0)\n\n#define TE_CLASS_FOREACH_CHECK_CHANNEL(cls, cls_start, cls_end, channel) ({   \\\n    bool ret = false;                                                         \\\n    typeof(cls_start) cls_method;                                             \\\n    TE_CLASS_FOREACH(cls_method, cls_start, cls_end) {                        \\\n        if (TE_CLASS_ITEM(cls, cls_method, handle) != NULL) {                 \\\n            ret |= TE_CLASS_ITEM(cls, cls_method, check_channel(channel));    \\\n        }                                                                     \\\n    }                                                                         \\\n    ret;                                                                      \\\n})\n\n#define TE_CLASS_FOREACH_SET_THRESHOLD(cls, cls_start, cls_end) do {          \\\n        typeof(cls_start) cls_method;                                         \\\n        TE_CLASS_FOREACH(cls_method, cls_start, cls_end) {                    \\\n            if (TE_CLASS_ITEM(cls, cls_method, handle) != NULL) {             \\\n                TE_CLASS_ITEM(cls, cls_method, set_threshold());              \\\n            }                                                                 \\\n        }                                                                     \\\n} while (0)\n\n#define TE_CLASS_FOREACH_PROCESS_STATE(cls, cls_start, cls_end) do {          \\\n        typeof(cls_start) cls_method;                                         \\\n        TE_CLASS_FOREACH(cls_method, cls_start, cls_end) {                    \\\n            if (TE_CLASS_ITEM(cls, cls_method, handle) != NULL) {             \\\n                TE_CLASS_ITEM(cls, cls_method, process_state());              \\\n            }                                                                 \\\n        }                                                                     \\\n} while (0)\n\n#define TE_CLASS_FOREACH_UPDATE_STATE(cls, cls_start, cls_end, channel, state) do {\\\n        typeof(cls_start) cls_method;                                         \\\n        TE_CLASS_FOREACH(cls_method, cls_start, cls_end) {                    \\\n            if (TE_CLASS_ITEM(cls, cls_method, handle) != NULL) {             \\\n                TE_CLASS_ITEM(cls, cls_method, update_state(channel, state)); \\\n            }                                                                 \\\n        }                                                                     \\\n} while (0)\n\n#define TE_PROCESSING_PERIOD(obj)                 ((obj)->global_config->software.processing_period)\n#define TE_WATERPROOF_DIVIDER(obj)                ((obj)->global_config->software.waterproof_threshold_divider)\n\n#define TOUCH_GET_IO_NUM(channel) (touch_sensor_channel_io_map[channel])\n\ntypedef enum {\n    TE_INTR_PRESS = 0,          //Touch sensor press interrupt(TOUCH_LL_INTR_MASK_DONE)\n    TE_INTR_RELEASE,            //Touch sensor release interrupt(TOUCH_LL_INTR_MASK_DONE)\n    TE_INTR_TIMEOUT,            //Touch sensor scan timeout interrupt(TOUCH_LL_INTR_MASK_TIMEOUT)\n    TE_INTR_SCAN_DONE,          //Touch sensor scan done interrupt(TOUCH_LL_INTR_MASK_SCAN_DONE), now just use for setting threshold\n    TE_INTR_MAX\n} te_intr_t;\n\ntypedef struct {\n    te_intr_t intr_type;                //channel interrupt type\n    te_state_t channel_state;           //channel state\n    touch_pad_t channel_num;            //channel index\n} te_intr_msg_t;\n\ntypedef struct {\n    te_object_methods_t object_methods[TE_CLS_TYPE_MAX];    //Class(object) methods\n    touch_elem_global_config_t *global_config;              //Global initialization\n    te_waterproof_handle_t waterproof_handle;               //Waterproof configuration\n    te_sleep_handle_t sleep_handle;\n    esp_timer_handle_t proc_timer;                          //Processing timer handle\n    QueueHandle_t event_msg_queue;                          //Application event message queue (for user)\n    QueueHandle_t intr_msg_queue;                           //Interrupt message (for internal)\n    SemaphoreHandle_t mutex;                                //Global resource mutex\n    bool is_set_threshold;                                  //Threshold configuration state bit\n    uint32_t denoise_channel_raw;                           //De-noise channel(TO) raw signal\n} te_obj_t;\n\nstatic te_obj_t *s_te_obj = NULL;\nRTC_FAST_ATTR uint32_t threshold_shadow[TOUCH_PAD_MAX - 1] = {0};\n\n/* Store IO number corresponding to the Touch Sensor channel number. */\n/* Note: T0 is an internal channel that does not have a corresponding external GPIO. */\nconst int touch_sensor_channel_io_map[TOUCH_LL_CHAN_NUM] = {\n    -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14\n    };\n\n/**\n * Internal de-noise channel(Touch channel 0) equivalent capacitance table, depends on hardware design\n *\n * Units: pF\n */\nstatic const float denoise_channel_equ_cap[TOUCH_PAD_DENOISE_CAP_MAX] = {5.0f, 6.4f, 7.8f, 9.2f, 10.6f, 12.0f, 13.4f, 14.8f};\n\n/**\n * Waterproof shield channel(Touch channel 14) equivalent capacitance table, depends on hardware design\n *\n * Units: pF\n */\nstatic const float shield_channel_ref_cap[TOUCH_PAD_SHIELD_DRV_MAX] = {40.0f, 80.0f, 120.0f, 160.0f, 200.0f, 240.0f, 280.0f, 320.0f};\n\n/* -------------------------------------------- Internal shared methods --------------------------------------------- */\n/*                                 -------------------------------------------------                                  */\n/* ------------------------------------------------- System methods ------------------------------------------------- */\nstatic esp_err_t te_hw_init(const touch_elem_hw_config_t *hardware_init);\nstatic esp_err_t te_sw_init(const touch_elem_sw_config_t *software_init);\nstatic inline float te_get_internal_equ_cap(touch_pad_denoise_cap_t denoise_level);\nstatic float te_channel_get_equ_cap(touch_pad_t channel_num);\nstatic uint32_t te_read_raw_signal(touch_pad_t channel_num);\nstatic void te_intr_cb(void *arg);\nstatic void te_proc_timer_cb(void *arg);\nstatic inline esp_err_t te_object_set_threshold(void);\nstatic inline void te_object_process_state(void);\nstatic inline void te_object_update_state(te_intr_msg_t te_intr_msg);\n/* ----------------------------------------------- Waterproof methods ----------------------------------------------- */\nstatic inline bool waterproof_check_state(void);\nstatic inline bool waterproof_shield_check_state(void);\nstatic inline bool waterproof_guard_check_state(void);\nstatic bool waterproof_channel_check(touch_pad_t channel_num);\nstatic void waterproof_guard_set_threshold(void);\nstatic void waterproof_guard_update_state(touch_pad_t current_channel, te_state_t current_state);\nstatic touch_pad_shield_driver_t waterproof_get_shield_level(touch_pad_t guard_channel_num);\n/* ------------------------------------------------------------------------------------------------------------------ */\n\nesp_err_t touch_element_install(const touch_elem_global_config_t *global_config)\n{\n    TE_CHECK(s_te_obj == NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(global_config != NULL, ESP_ERR_INVALID_ARG);\n\n    s_te_obj = (te_obj_t *)calloc(1, sizeof(te_obj_t));\n    TE_CHECK(s_te_obj != NULL, ESP_ERR_NO_MEM);\n\n    esp_err_t ret = ESP_ERR_NO_MEM;\n    s_te_obj->global_config = (touch_elem_global_config_t *)calloc(1, sizeof(touch_elem_global_config_t));\n    s_te_obj->mutex = xSemaphoreCreateMutex();\n    TE_CHECK_GOTO(s_te_obj->global_config != NULL && s_te_obj->mutex != NULL, cleanup);\n    xSemaphoreTake(s_te_obj->mutex, portMAX_DELAY);\n    TE_CLS_METHODS_INITIALIZER(s_te_obj->object_methods, TE_CLS_TYPE_BUTTON, TE_CLS_TYPE_MAX);\n    ret = te_hw_init(&global_config->hardware);\n    if (ret != ESP_OK) {\n        abort();\n    }\n    ret = te_sw_init(&global_config->software);\n    if (ret != ESP_OK) {\n        xSemaphoreGive(s_te_obj->mutex);\n        goto cleanup;\n    }\n    xSemaphoreGive(s_te_obj->mutex);\n    return ESP_OK;\n\ncleanup:\n    TE_FREE_AND_NULL(s_te_obj->global_config);\n    if (s_te_obj->mutex != NULL) {\n        vSemaphoreDelete(s_te_obj->mutex);\n    }\n    TE_FREE_AND_NULL(s_te_obj);\n    return ret;\n}\n\nesp_err_t touch_element_start(void)\n{\n    TE_CHECK(s_te_obj != NULL, ESP_ERR_INVALID_STATE);\n    esp_err_t ret = ESP_OK;\n    uint16_t inited_channel_mask;\n    do {\n        xSemaphoreTake(s_te_obj->mutex, portMAX_DELAY);\n        touch_ll_get_channel_mask(&inited_channel_mask);\n        if (inited_channel_mask == 0x0) {\n            ESP_LOGE(TE_TAG, \"Can not find Touch Sensor channel that has been initialized\");\n            ret = ESP_ERR_INVALID_STATE;\n            break;\n        }\n        s_te_obj->is_set_threshold = false;  //Threshold configuration will be set on touch sense start\n        ret = esp_timer_start_periodic(s_te_obj->proc_timer, TE_PROCESSING_PERIOD(s_te_obj) * 1000);\n        if (ret != ESP_OK) {\n            break;\n        }\n        touch_ll_intr_enable((touch_pad_intr_mask_t)TOUCH_LL_INTR_MASK_SCAN_DONE); //Use scan done interrupt to set threshold\n        touch_ll_start_fsm();\n        xQueueReset(s_te_obj->event_msg_queue);\n        xQueueReset(s_te_obj->intr_msg_queue);\n        xSemaphoreGive(s_te_obj->mutex);\n        return ESP_OK;\n    } while (0);\n\n    ESP_LOGE(TE_TAG, \"Touch interface start failed:(%s)\", __FUNCTION__ );\n    xSemaphoreGive(s_te_obj->mutex);\n    return ret;\n}\n\nesp_err_t touch_element_stop(void)\n{\n    TE_CHECK(s_te_obj != NULL, ESP_ERR_INVALID_STATE);\n    esp_err_t ret = ESP_OK;\n    xSemaphoreTake(s_te_obj->mutex, portMAX_DELAY);\n    touch_ll_stop_fsm();\n    touch_ll_intr_disable((touch_pad_intr_mask_t)TOUCH_LL_INTR_MASK_SCAN_DONE);\n    ret = esp_timer_stop(s_te_obj->proc_timer);\n    if (ret != ESP_OK) {\n        return ret;\n    }\n    xSemaphoreGive(s_te_obj->mutex);\n    return ESP_OK;\n}\n\n//TODO: add a new api that output system's run-time state\n\nvoid touch_element_uninstall(void)\n{\n    xSemaphoreTake(s_te_obj->mutex, portMAX_DELAY);\n    if (s_te_obj == NULL) {\n        xSemaphoreGive(s_te_obj->mutex);\n        return;\n    }\n    esp_err_t ret = ESP_OK;\n    touch_hal_deinit();\n    ret = esp_timer_delete(s_te_obj->proc_timer);\n    if (ret != ESP_OK) {\n        abort();\n    }\n    touch_ll_intr_disable((touch_pad_intr_mask_t)(TOUCH_LL_INTR_MASK_ACTIVE | TOUCH_LL_INTR_MASK_INACTIVE | TOUCH_LL_INTR_MASK_TIMEOUT));\n    ret = rtc_isr_deregister(te_intr_cb, NULL);\n    if (ret != ESP_OK) {\n        abort();\n    }\n    vQueueDelete(s_te_obj->event_msg_queue);\n    vQueueDelete(s_te_obj->intr_msg_queue);\n    xSemaphoreGive(s_te_obj->mutex);\n    vSemaphoreDelete(s_te_obj->mutex);\n    free(s_te_obj->global_config);\n    s_te_obj->global_config = NULL;\n    free(s_te_obj);\n    s_te_obj = NULL;\n}\n\nesp_err_t touch_element_message_receive(touch_elem_message_t *element_message, uint32_t ticks_to_wait)\n{\n    //TODO: Use the generic data struct to refactor this api\n    TE_CHECK(s_te_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(element_message != NULL, ESP_ERR_INVALID_ARG);\n    TE_CHECK(s_te_obj->event_msg_queue != NULL, ESP_ERR_INVALID_STATE);\n    int ret = xQueueReceive(s_te_obj->event_msg_queue, element_message, ticks_to_wait);\n    return (ret == pdTRUE) ? ESP_OK : ESP_ERR_TIMEOUT;\n}\n\nstatic uint32_t te_read_raw_signal(touch_pad_t channel_num)\n{\n    uint32_t raw_signal = 0;\n    touch_pad_sleep_channel_t sleep_channel_info;\n    touch_hal_sleep_channel_get_config(&sleep_channel_info);\n    if (channel_num != sleep_channel_info.touch_num) {\n        raw_signal = touch_ll_read_raw_data(channel_num);\n    } else {\n        touch_ll_sleep_read_data(&raw_signal);\n    }\n    return raw_signal;\n}\n\nuint32_t te_read_smooth_signal(touch_pad_t channel_num)\n{\n    uint32_t smooth_signal = 0;\n    touch_pad_sleep_channel_t sleep_channel_info;\n    touch_hal_sleep_channel_get_config(&sleep_channel_info);\n    if (channel_num != sleep_channel_info.touch_num) {\n        touch_ll_filter_read_smooth(channel_num, &smooth_signal);\n    } else {\n        touch_ll_sleep_read_smooth(&smooth_signal);\n    }\n    return smooth_signal;\n}\n\nesp_err_t te_event_give(touch_elem_message_t te_message)\n{\n    //TODO: add queue overwrite here when the queue is full\n    int ret = xQueueSend(s_te_obj->event_msg_queue, &te_message, 0);\n    if (ret != pdTRUE) {\n        ESP_LOGE(TE_TAG, \"event queue send failed, event message queue is full\");\n        return ESP_ERR_TIMEOUT;\n    }\n    return ESP_OK;\n}\n\nuint32_t te_get_threshold(touch_pad_t channel_num)\n{\n    uint32_t threshold = 0;\n    touch_pad_sleep_channel_t sleep_channel_info;\n    touch_hal_sleep_channel_get_config(&sleep_channel_info);\n    if (channel_num != sleep_channel_info.touch_num) {\n        touch_ll_get_threshold(channel_num, &threshold);\n    } else {\n        touch_ll_sleep_get_threshold(&threshold);\n    }\n    return threshold;\n}\n\nbool te_is_touch_dsleep_wakeup(void)\n{\n    soc_reset_reason_t reset_reason = esp_rom_get_reset_reason(0);\n    if (reset_reason != RESET_REASON_CORE_DEEP_SLEEP) {\n        return false;\n    }\n#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0))\n    return !!(esp_sleep_get_wakeup_causes() & BIT(ESP_SLEEP_WAKEUP_TOUCHPAD));\n#else\n    return esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_TOUCHPAD;\n#endif\n}\n\ntouch_pad_t te_get_sleep_channel(void)\n{\n    touch_pad_sleep_channel_t sleep_channel_info;\n    touch_hal_sleep_channel_get_config(&sleep_channel_info);\n    return sleep_channel_info.touch_num;\n}\n\n/**\n * @brief Touch sensor interrupt service routine\n *\n * This function is touch sensor ISR, all the touch\n * sensor channel state will be updated here.\n */\nstatic void te_intr_cb(void *arg)\n{\n    TE_UNUSED(arg);\n    static int scan_done_cnt = 0;\n    static uint32_t touch_pre_trig_status = 0;\n    int task_awoken = pdFALSE;\n    te_intr_msg_t te_intr_msg = {};\n    /*< Figure out which touch sensor channel is triggered and the trigger type */\n    uint32_t intr_mask = touch_ll_read_intr_status_mask();\n#if CONFIG_IDF_TARGET_ESP32S2\n    /*< Workaround: For ESP32S2, the scan done interrupt may occur earlier,\n        so we need to ignore the fake scan done interrupt */\n    if (intr_mask & TOUCH_LL_INTR_MASK_SCAN_DONE) {\n        uint32_t curr_pad = touch_ll_get_current_meas_channel();\n        uint16_t ch_mask = 0;\n        touch_ll_get_channel_mask(&ch_mask);\n        /* If the current channel is not the last channel, it means the scan done interrupt is fake */\n        if (__builtin_clz((uint32_t)ch_mask) != __builtin_clz(BIT(curr_pad))) {\n            touch_ll_intr_clear((touch_pad_intr_mask_t)TOUCH_LL_INTR_MASK_SCAN_DONE);\n            intr_mask &= ~TOUCH_LL_INTR_MASK_SCAN_DONE;\n        }\n    }\n#endif\n    if (intr_mask == 0x0) {  //For dummy interrupt\n        return;\n    }\n\n    bool need_send_queue = true;\n    uint8_t pad_num = 0;\n    uint32_t touch_trig_status = 0;\n    touch_ll_read_trigger_status_mask(&touch_trig_status);\n    uint32_t touch_trig_diff = touch_trig_status ^ touch_pre_trig_status;\n    while (touch_trig_diff) {\n        if (touch_trig_diff & 0x1) {\n            if (touch_trig_status & BIT(pad_num)) {\n                if (s_te_obj->sleep_handle != NULL) {\n#ifdef CONFIG_PM_ENABLE\n                    esp_pm_lock_acquire(s_te_obj->sleep_handle->pm_lock);\n#endif\n                }\n                te_intr_msg.channel_state = TE_STATE_PRESS;\n                te_intr_msg.intr_type = TE_INTR_PRESS;\n            } else {\n                te_intr_msg.channel_state = TE_STATE_RELEASE;\n                te_intr_msg.intr_type = TE_INTR_RELEASE;\n            }\n            touch_pre_trig_status = touch_trig_status;\n            te_intr_msg.channel_num = pad_num;\n        }\n        pad_num++;\n        touch_trig_diff >>= 1;\n    }\n\n    if (intr_mask & TOUCH_LL_INTR_MASK_TIMEOUT) {\n        te_intr_msg.channel_state = TE_STATE_IDLE;\n        te_intr_msg.intr_type = TE_INTR_TIMEOUT;\n    } else if (intr_mask & TOUCH_LL_INTR_MASK_SCAN_DONE) {\n        te_intr_msg.channel_state = TE_STATE_IDLE;\n        te_intr_msg.intr_type = TE_INTR_SCAN_DONE;\n        need_send_queue = false;\n        /*< Due to a hardware issue, all of the data read operation(read raw, read smooth, read benchmark) */\n        /*< must be after the second times of measure_done interrupt. */\n        if (++scan_done_cnt >= 5) {\n            touch_ll_intr_disable((touch_pad_intr_mask_t)TOUCH_LL_INTR_MASK_SCAN_DONE);  //TODO: remove hal\n            scan_done_cnt = 0;\n            need_send_queue = true;\n        }\n        /*< De-noise channel signal must be read at the time between SCAN_DONE and next measurement beginning(sleep)!!! */\n        touch_ll_denoise_read_data(&s_te_obj->denoise_channel_raw); //Update de-noise signal\n    }\n    if (need_send_queue) {\n        xQueueSendFromISR(s_te_obj->intr_msg_queue, &te_intr_msg, &task_awoken);\n    }\n    if (task_awoken == pdTRUE) {\n        portYIELD_FROM_ISR();\n    }\n}\n\n/**\n * @brief esp-timer callback routine\n *\n * This function is an esp-timer daemon routine, all the touch sensor\n * application(button, slider, etc...) will be processed in here.\n *\n */\nstatic void te_proc_timer_cb(void *arg)\n{\n    TE_UNUSED(arg);\n    te_intr_msg_t te_intr_msg;\n    te_intr_msg.intr_type = TE_INTR_MAX;\n    BaseType_t ret = xSemaphoreTake(s_te_obj->mutex, 0);\n    if (ret != pdPASS) {\n        return;\n    }\n    ret = xQueueReceive(s_te_obj->intr_msg_queue, &te_intr_msg, 0);\n    if (ret == pdPASS) {\n        if (te_intr_msg.intr_type == TE_INTR_PRESS || te_intr_msg.intr_type == TE_INTR_RELEASE) {\n            te_object_update_state(te_intr_msg);\n            if ((s_te_obj->sleep_handle != NULL) && (te_intr_msg.intr_type == TE_INTR_RELEASE)) {\n#ifdef CONFIG_PM_ENABLE\n                esp_pm_lock_release(s_te_obj->sleep_handle->pm_lock);\n#endif\n            }\n        } else if (te_intr_msg.intr_type == TE_INTR_SCAN_DONE) {\n            if (s_te_obj->is_set_threshold != true) {\n                s_te_obj->is_set_threshold = true;\n                te_object_set_threshold();  //TODO: add set threshold error processing\n                ESP_LOGD(TE_DEBUG_TAG, \"Set threshold\");\n                if (s_te_obj->sleep_handle != NULL) {\n#ifdef CONFIG_PM_ENABLE\n                    esp_pm_lock_release(s_te_obj->sleep_handle->pm_lock);\n#endif\n                }\n            }\n            if (waterproof_check_state()) {\n                te_waterproof_handle_t waterproof_handle = s_te_obj->waterproof_handle;\n                if (waterproof_handle->is_shield_level_set != true) {\n                    waterproof_handle->is_shield_level_set = true;\n                    touch_pad_waterproof_t wp_conf;\n                    wp_conf.shield_driver = waterproof_get_shield_level(waterproof_handle->shield_channel);\n                    wp_conf.guard_ring_pad = (waterproof_guard_check_state() ? waterproof_handle->guard_device->channel : TOUCH_WATERPROOF_GUARD_NOUSE);\n                    touch_hal_waterproof_set_config(&wp_conf);\n                    touch_hal_waterproof_enable();\n                    ESP_LOGD(TE_DEBUG_TAG, \"Set waterproof shield level\");\n                }\n            }\n            ESP_LOGD(TE_DEBUG_TAG, \"read denoise channel %\"PRIu32, s_te_obj->denoise_channel_raw);\n        } else if (te_intr_msg.intr_type == TE_INTR_TIMEOUT) { //Timeout processing\n            touch_ll_timer_force_done();\n        }\n    }\n    te_object_process_state();\n    xSemaphoreGive(s_te_obj->mutex);\n}\n\nvoid te_object_method_register(te_object_methods_t *object_methods, te_class_type_t object_type)\n{\n    xSemaphoreTake(s_te_obj->mutex, portMAX_DELAY);\n    TE_CLASS_ITEM(s_te_obj->object_methods, object_type, handle) = object_methods->handle;\n    TE_CLASS_ITEM(s_te_obj->object_methods, object_type, check_channel) = object_methods->check_channel;\n    TE_CLASS_ITEM(s_te_obj->object_methods, object_type, set_threshold) = object_methods->set_threshold;\n    TE_CLASS_ITEM(s_te_obj->object_methods, object_type, process_state) = object_methods->process_state;\n    TE_CLASS_ITEM(s_te_obj->object_methods, object_type, update_state) = object_methods->update_state;\n    xSemaphoreGive(s_te_obj->mutex);\n}\n\nvoid te_object_method_unregister(te_class_type_t object_type)\n{\n    xSemaphoreTake(s_te_obj->mutex, portMAX_DELAY);\n    TE_CLASS_ITEM(s_te_obj->object_methods, object_type, handle) = NULL;\n    TE_CLASS_ITEM(s_te_obj->object_methods, object_type, check_channel) = NULL;\n    TE_CLASS_ITEM(s_te_obj->object_methods, object_type, set_threshold) = NULL;\n    TE_CLASS_ITEM(s_te_obj->object_methods, object_type, process_state) = NULL;\n    TE_CLASS_ITEM(s_te_obj->object_methods, object_type, update_state) = NULL;\n    xSemaphoreGive(s_te_obj->mutex);\n}\n\n/**\n * @brief Touch Sense channel check\n *\n * This function will check the input channel whether is\n * associated with the Touch Sense Object\n *\n * @return\n *      - true:  Channel has been initialized, pls adjust the input channel\n *      - false: Channel has not been initialized, pass\n */\nbool te_object_check_channel(const touch_pad_t *channel_array, uint8_t channel_sum)\n{\n    touch_pad_t current_channel;\n    for (int idx = 0; idx < channel_sum; idx++) {\n        current_channel = channel_array[idx];\n        if (waterproof_channel_check(current_channel)) {\n            goto INITIALIZED;\n        }\n        if (TE_CLASS_FOREACH_CHECK_CHANNEL(s_te_obj->object_methods, TE_CLS_TYPE_BUTTON, TE_CLS_TYPE_MAX, current_channel)) {\n            goto INITIALIZED;\n        }\n    }\n    return false;\n\nINITIALIZED:\n    ESP_LOGE(TE_TAG, \"Current channel [%d] has been initialized:(%s)\", current_channel, __FUNCTION__ );\n    return true;\n}\n\n\nstatic inline esp_err_t te_object_set_threshold(void)\n{\n    if (waterproof_guard_check_state() == true) {   //TODO: add to object methods\n        waterproof_guard_set_threshold();\n    }\n\n    TE_CLASS_FOREACH_SET_THRESHOLD(s_te_obj->object_methods, TE_CLS_TYPE_BUTTON, TE_CLS_TYPE_MAX);\n    return ESP_OK;\n}\n\nstatic inline void te_object_process_state(void)\n{\n    TE_CLASS_FOREACH_PROCESS_STATE(s_te_obj->object_methods, TE_CLS_TYPE_BUTTON, TE_CLS_TYPE_MAX);\n}\n\nstatic inline void te_object_update_state(te_intr_msg_t te_intr_msg)\n{\n    if (waterproof_guard_check_state()) {\n        waterproof_guard_update_state(te_intr_msg.channel_num, te_intr_msg.channel_state);\n    }\n    TE_CLASS_FOREACH_UPDATE_STATE(s_te_obj->object_methods, TE_CLS_TYPE_BUTTON, TE_CLS_TYPE_MAX,\n                                  te_intr_msg.channel_num, te_intr_msg.channel_state);\n}\n\nuint8_t te_get_timer_period(void)\n{\n    return (TE_PROCESSING_PERIOD(s_te_obj));\n}\n\nesp_err_t te_dev_init(te_dev_t **device, uint8_t device_num, te_dev_type_t type, const touch_pad_t *channel, const float *sens, float divider)\n{\n    for (int idx = 0; idx < device_num; idx++) {\n        device[idx]->channel = channel[idx];\n        device[idx]->sens = sens[idx] * divider;\n        device[idx]->type = type;\n        device[idx]->state = TE_STATE_IDLE;\n        device[idx]->is_use_last_threshold = false;\n        int touch_num = TOUCH_GET_IO_NUM(device[idx]->channel);\n        esp_err_t ret = ESP_OK;\n#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0))\n        ret = gpio_config_as_analog(touch_num);\n#else\n        rtc_gpio_init(touch_num);\n        rtc_gpio_set_direction(touch_num, RTC_GPIO_MODE_DISABLED);\n        rtc_gpio_pulldown_dis(touch_num);\n        rtc_gpio_pullup_dis(touch_num);\n#endif\n        touch_hal_config(touch_num);\n        touch_ll_set_channel_mask(BIT(touch_num));\n        TE_CHECK(ret == ESP_OK, ret);\n    }\n    return ESP_OK;\n}\n\nvoid te_dev_deinit(te_dev_t **device, uint8_t device_num)\n{\n    for (int idx = 0; idx < device_num; idx++) {\n        touch_ll_clear_channel_mask((1UL << device[idx]->channel));\n    }\n}\n\nstatic esp_err_t te_config_thresh(touch_pad_t channel_num, uint32_t threshold)\n{\n    touch_pad_sleep_channel_t sleep_channel_info;\n    touch_hal_sleep_channel_get_config(&sleep_channel_info);\n    if (channel_num != sleep_channel_info.touch_num) {\n        touch_ll_set_threshold(channel_num, threshold);\n    } else {\n        touch_ll_sleep_set_threshold(threshold);\n    }\n    return ESP_OK;\n}\n\nesp_err_t te_dev_set_threshold(te_dev_t *device)\n{\n    esp_err_t ret = ESP_OK;\n    uint32_t smo_val = 0;\n\n    if (s_te_obj->sleep_handle && device->is_use_last_threshold) {\n        if (te_is_touch_dsleep_wakeup()) {  //Deep sleep wakeup reset\n            ret = te_config_thresh(device->channel, s_te_obj->sleep_handle->non_volatile_threshold[device->channel - 1]);\n        } else {  //Other reset\n            smo_val = te_read_smooth_signal(device->channel);\n            ret = te_config_thresh(device->channel, device->sens * smo_val);\n            uint32_t threshold = te_get_threshold(device->channel);\n            s_te_obj->sleep_handle->non_volatile_threshold[device->channel - 1] = threshold;  //Write threshold into RTC Fast Memory\n        }\n    } else {\n        smo_val = te_read_smooth_signal(device->channel);\n        ret = te_config_thresh(device->channel, device->sens * smo_val);\n    }\n    ESP_LOGD(TE_DEBUG_TAG, \"channel: %\"PRIu8\", smo_val: %\"PRIu32, (uint8_t)device->channel, smo_val);\n    return ret;\n}\n\n/**\n * This function returns the s_te_obj whether is initialized\n *\n * @return\n *      - true: initialized\n *      - false: not initialized\n */\nbool te_system_check_state(void)\n{\n    return (s_te_obj != NULL);\n}\n\nstatic inline float te_get_internal_equ_cap(touch_pad_denoise_cap_t denoise_level)\n{\n    return denoise_channel_equ_cap[denoise_level];\n}\n\n/**\n * @brief   Get channel equivalent capacitance\n *\n * This function calculates the equivalent capacitance of input channel by\n * using the Touch channel 0 equivalent capacitance. The formula is:\n *\n *                      Raw_N / Raw_0 = Cap_N / Cap_0\n *\n * Note that Raw_N and Raw_0 are the raw data of touch channel N and touch channel 0 respectively,\n * Cap_N and Cap_0 are the equivalent capacitance of touch channel N and touch channel 0.\n *\n * @param[in] channel_num   Input touch sensor channel\n *\n * @note The unit is pF\n *\n * @return  Specified channel equivalent capacitance.\n */\nstatic float te_channel_get_equ_cap(touch_pad_t channel_num)\n{\n    //Fixme: add a mutex in here and prevent the system call this function\n    TE_CHECK(channel_num >= TOUCH_PAD_NUM1 && channel_num < TOUCH_PAD_MAX, 0);\n    uint32_t tn_raw, t0_raw;\n    float tn_ref_cap, t0_ref_cap;\n    touch_pad_denoise_t denoise_channel_conf;\n    touch_hal_denoise_get_config(&denoise_channel_conf);\n    tn_raw = te_read_raw_signal(channel_num);\n    t0_raw = s_te_obj->denoise_channel_raw;\n    t0_ref_cap = te_get_internal_equ_cap(denoise_channel_conf.cap_level);\n    if (t0_raw == 0) {\n        return 0;\n    }\n    tn_ref_cap = (float)tn_raw / t0_raw * t0_ref_cap;\n    return tn_ref_cap;\n}\n\n/**\n * @brief  Touch sensor driver default init [ESP32S2 only]\n *\n * 1. Channel measure time: Raw_value / RTC_FAST_CLK  ==> Raw_value / 8000 000\n * 2. Channel sleep time: TOUCH_PAD_SLEEP_CYCLE_DEFAULT / RTC_SLOW_CLK ==> 0xf / 90 000(default) = 0.16ms\n * 3. Channel charge voltage threshold(upper/lower):  2.7V upper voltage, 0.5V lower voltage, 0.5V attenuation voltage\n * 4. IDLE channel processing:  Connecting to GND\n * 5. Interrupt type:  ACTIVE, INACTIVE, TIMEOUT\n *\n * @note A touch sensor channel will spend the time = measure time + sleep time, RTC_FAST_CLK is 8M\n *\n */\nstatic esp_err_t te_hw_init(const touch_elem_hw_config_t *hardware_init)\n{\n    esp_err_t ret = ESP_OK;\n    touch_hal_init();\n    touch_ll_set_fsm_mode(TOUCH_FSM_MODE_TIMER);\n    touch_ll_set_sleep_time(hardware_init->sleep_cycle);\n    touch_ll_set_meas_times(hardware_init->sample_count);\n    touch_ll_set_voltage_high(hardware_init->upper_voltage);\n    touch_ll_set_voltage_low(hardware_init->lower_voltage);\n    touch_ll_set_voltage_attenuation(hardware_init->voltage_attenuation);\n    touch_ll_set_idle_channel_connect(hardware_init->suspend_channel_polarity);\n    uint32_t intr_mask = RTC_CNTL_TOUCH_ACTIVE_INT_ST_M | RTC_CNTL_TOUCH_INACTIVE_INT_ST_M |\n                         RTC_CNTL_TOUCH_TIMEOUT_INT_ST_M | RTC_CNTL_TOUCH_SCAN_DONE_INT_ST_M;\n    ret = rtc_isr_register(te_intr_cb, NULL, intr_mask, 0);\n    TE_CHECK(ret == ESP_OK, ret);\n    touch_ll_intr_enable((touch_pad_intr_mask_t)(TOUCH_LL_INTR_MASK_ACTIVE | TOUCH_LL_INTR_MASK_SCAN_DONE |\n                         TOUCH_LL_INTR_MASK_INACTIVE | TOUCH_LL_INTR_MASK_TIMEOUT));\n    TE_CHECK(ret == ESP_OK, ret);\n    /*< Internal de-noise configuration */\n    touch_pad_denoise_t denoise_config;\n    denoise_config.grade = hardware_init->denoise_level;\n    denoise_config.cap_level = hardware_init->denoise_equivalent_cap;\n    touch_ll_set_slope((touch_pad_t)TOUCH_LL_DENOISE_CHANNEL, TOUCH_PAD_SLOPE_DEFAULT);\n    touch_ll_set_tie_option((touch_pad_t)TOUCH_LL_DENOISE_CHANNEL, TOUCH_PAD_TIE_OPT_DEFAULT);\n    touch_hal_denoise_set_config(&denoise_config);\n    touch_hal_denoise_enable();\n\n    /*< benchmark filter configuration */\n    touch_filter_config_t filter_config;\n    filter_config.smh_lvl = hardware_init->smooth_filter_mode;\n    filter_config.mode = hardware_init->benchmark_filter_mode;\n    filter_config.debounce_cnt = hardware_init->benchmark_debounce_count;\n    filter_config.noise_thr = hardware_init->benchmark_calibration_threshold;\n    filter_config.jitter_step = hardware_init->benchmark_jitter_step;\n    touch_hal_filter_set_config(&filter_config);\n    touch_ll_filter_enable(true);\n    memcpy(&s_te_obj->global_config->hardware, hardware_init, sizeof(touch_elem_hw_config_t));\n    return ESP_OK;\n}\n\nstatic esp_err_t te_sw_init(const touch_elem_sw_config_t *software_init)\n{\n    TE_CHECK(software_init->processing_period > 1, ESP_ERR_INVALID_ARG);\n    TE_CHECK(software_init->waterproof_threshold_divider > 0, ESP_ERR_INVALID_ARG);\n    TE_CHECK(software_init->intr_message_size >= (TOUCH_PAD_MAX - 1), ESP_ERR_INVALID_ARG);\n    TE_CHECK(software_init->event_message_size > 0, ESP_ERR_INVALID_ARG);\n\n    esp_err_t ret = ESP_ERR_NO_MEM;\n    s_te_obj->intr_msg_queue = xQueueCreate(software_init->intr_message_size, sizeof(te_intr_msg_t));\n    s_te_obj->event_msg_queue = xQueueCreate(software_init->event_message_size, sizeof(touch_elem_message_t));\n    TE_CHECK_GOTO(s_te_obj->event_msg_queue != NULL && s_te_obj->intr_msg_queue != NULL, cleanup);\n\n    const esp_timer_create_args_t te_proc_timer_args = {\n        .name = \"te_proc_timer_cb\",\n        .arg  = NULL,\n        .callback = &te_proc_timer_cb,\n        .skip_unhandled_events = true,\n    };\n    ret = esp_timer_create(&te_proc_timer_args, &s_te_obj->proc_timer);\n    TE_CHECK_GOTO(ret == ESP_OK, cleanup);\n    memcpy(&s_te_obj->global_config->software, software_init, sizeof(touch_elem_sw_config_t));\n    return ret;\n\ncleanup:\n    if (s_te_obj->event_msg_queue != NULL) {\n        vQueueDelete(s_te_obj->event_msg_queue);\n    }\n    if (s_te_obj->intr_msg_queue != NULL) {\n        vQueueDelete(s_te_obj->intr_msg_queue);\n    }\n    return ret;\n}\n\n//TODO: add waterproof guard-lock hysteresis\nesp_err_t touch_element_waterproof_install(const touch_elem_waterproof_config_t *waterproof_config)\n{\n    TE_CHECK(s_te_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(waterproof_config != NULL, ESP_ERR_INVALID_ARG);\n    TE_CHECK(waterproof_config->guard_channel >= TOUCH_PAD_NUM0 &&\n             waterproof_config->guard_channel < TOUCH_PAD_MAX,\n             ESP_ERR_INVALID_ARG);\n    te_waterproof_handle_t waterproof_handle = (te_waterproof_handle_t)calloc(1, sizeof(struct te_waterproof_s));\n    TE_CHECK(waterproof_handle != NULL, ESP_ERR_NO_MEM);\n    waterproof_handle->shield_channel = TOUCH_PAD_NUM14;\n\n    esp_err_t ret = ESP_OK;\n    if (waterproof_config->guard_channel != TOUCH_WATERPROOF_GUARD_NOUSE) { //Use guard sensor\n        if (te_object_check_channel(&waterproof_config->guard_channel, 1)) {\n            ret = ESP_ERR_INVALID_ARG;\n            goto cleanup;\n        }\n        ret = ESP_ERR_NO_MEM;\n        waterproof_handle->mask_handle = (touch_elem_handle_t *) calloc(TOUCH_PAD_MAX, sizeof(touch_elem_handle_t));\n        waterproof_handle->guard_device = (te_dev_t *)calloc(1, sizeof(te_dev_t));\n        TE_CHECK_GOTO(waterproof_handle->mask_handle != NULL && waterproof_handle->guard_device, cleanup);\n\n        ret = te_dev_init(&waterproof_handle->guard_device, 1, TOUCH_ELEM_TYPE_BUTTON,\n                          &waterproof_config->guard_channel, &waterproof_config->guard_sensitivity,\n                          TE_WATERPROOF_DIVIDER(s_te_obj));\n        TE_CHECK_GOTO(ret == ESP_OK, cleanup);\n        waterproof_handle->guard_device->state = TE_STATE_RELEASE;\n        for (int idx = 0; idx < TOUCH_PAD_MAX; idx++) {\n            waterproof_handle->mask_handle[idx] = NULL;\n        }\n    } else {  //No use waterproof guard sensor\n        waterproof_handle->guard_device = NULL;\n        waterproof_handle->mask_handle = NULL;\n    }\n    waterproof_handle->is_shield_level_set = 0; //Set a state bit so as to configure the shield level at the run-time\n    touch_pad_waterproof_t wp_conf;\n    wp_conf.shield_driver = TOUCH_PAD_SHIELD_DRV_L0; //Set a default shield level\n    wp_conf.guard_ring_pad = waterproof_config->guard_channel;\n    touch_hal_waterproof_set_config(&wp_conf);\n    touch_hal_waterproof_enable();\n    s_te_obj->waterproof_handle = waterproof_handle;  //Fixme: add mutex\n    return ret;\n\ncleanup:\n    TE_FREE_AND_NULL(waterproof_handle->mask_handle);\n    TE_FREE_AND_NULL(waterproof_handle->guard_device);\n    TE_FREE_AND_NULL(waterproof_handle);\n    return ret;\n}\n\nesp_err_t touch_element_waterproof_add(touch_elem_handle_t element_handle)\n{\n    TE_CHECK(s_te_obj->waterproof_handle != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(s_te_obj->waterproof_handle->guard_device != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(element_handle != NULL, ESP_ERR_INVALID_ARG);\n    te_waterproof_handle_t waterproof_handle = s_te_obj->waterproof_handle;\n    xSemaphoreTake(s_te_obj->mutex, portMAX_DELAY);\n    for (int idx = 0; idx < TOUCH_PAD_MAX; idx++) {\n        if (waterproof_handle->mask_handle[idx] == NULL) {\n            waterproof_handle->mask_handle[idx] = element_handle;\n            break;\n        }\n    }\n    xSemaphoreGive(s_te_obj->mutex);\n    return ESP_OK;\n}\n\nesp_err_t touch_element_waterproof_remove(touch_elem_handle_t element_handle)\n{\n    TE_CHECK(s_te_obj->waterproof_handle != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(element_handle != NULL, ESP_ERR_INVALID_ARG);\n    esp_err_t ret = ESP_ERR_NOT_FOUND;\n    te_waterproof_handle_t waterproof_handle = s_te_obj->waterproof_handle;\n    xSemaphoreTake(s_te_obj->mutex, portMAX_DELAY);\n    for (int idx = 0; idx < TOUCH_PAD_MAX; idx++) {\n        if (waterproof_handle->mask_handle[idx] == element_handle) {\n            waterproof_handle->mask_handle[idx] = NULL;\n            ret = ESP_OK;\n            break;\n        }\n    }\n    xSemaphoreGive(s_te_obj->mutex);\n    return ret;\n}\n\nvoid touch_element_waterproof_uninstall(void)\n{\n    xSemaphoreTake(s_te_obj->mutex, portMAX_DELAY);\n    touch_ll_waterproof_enable(false);\n    free(s_te_obj->waterproof_handle->guard_device);\n    free(s_te_obj->waterproof_handle->mask_handle);\n    free(s_te_obj->waterproof_handle);\n    s_te_obj->waterproof_handle = NULL;\n    xSemaphoreGive(s_te_obj->mutex);\n}\n\nstatic touch_pad_shield_driver_t waterproof_get_shield_level(touch_pad_t guard_channel_num)\n{\n    touch_pad_shield_driver_t shield_level = TOUCH_PAD_SHIELD_DRV_L7;\n    float guard_ref_cap = te_channel_get_equ_cap(guard_channel_num);\n    for (int level = 0; level < TOUCH_PAD_SHIELD_DRV_MAX; level++) {\n        if (guard_ref_cap <= shield_channel_ref_cap[level]) {\n            shield_level = (touch_pad_shield_driver_t)level;\n            break;\n        }\n    }\n    return shield_level;\n}\n\n/**\n * This function returns the waterproof_handle whether is initialized\n *\n * @return\n *      - true: initialized\n *      - false: not initialized\n */\nstatic inline bool waterproof_check_state(void)\n{\n    return (s_te_obj->waterproof_handle != NULL);\n}\n\nstatic inline bool waterproof_shield_check_state(void)\n{\n    return waterproof_check_state();  //Driver does not allow to disable shield sensor after waterproof enabling\n}\n\nstatic inline bool waterproof_guard_check_state(void)\n{\n    if (waterproof_check_state() == false) {\n        return false;\n    }\n    if (s_te_obj->waterproof_handle->guard_device == NULL || s_te_obj->waterproof_handle->mask_handle == NULL) {\n        return false;\n    }\n    return true;\n}\n\nstatic bool waterproof_channel_check(touch_pad_t channel_num)\n{\n    if (waterproof_check_state() == false) {\n        return false;\n    }\n    te_waterproof_handle_t waterproof_handle = s_te_obj->waterproof_handle;\n    if (waterproof_shield_check_state()) {\n        if (channel_num == waterproof_handle->shield_channel) {\n            ESP_LOGE(TE_TAG, \"TOUCH_PAD_NUM%\"PRIu8\" has been used for waterproof shield channel,\"\n                     \" please change the touch sensor channel or disable waterproof\", (uint8_t)channel_num);\n            return true;\n        }\n    }\n    if (waterproof_guard_check_state()) {\n        if (channel_num == waterproof_handle->guard_device->channel) {\n            ESP_LOGE(TE_TAG, \"TOUCH_PAD_NUM%\"PRIu8\" has been used for waterproof guard channel,\"\n                     \" please change the touch sensor channel or disable waterproof\", (uint8_t)channel_num);\n            return true;\n        }\n    }\n    return false;\n}\n\nstatic void waterproof_guard_set_threshold(void)\n{\n    if (waterproof_check_state() == false) {\n        return;\n    }\n    if (waterproof_guard_check_state() == false) {\n        return;\n    }\n    te_dev_set_threshold(s_te_obj->waterproof_handle->guard_device);\n}\n\n/**\n *  This function will figure out current handle whether is a masked channel\n *  while guard channel is triggered.\n *\n * @param[in] te_handle     Touch sensor application handle\n * @return\n *      - true  current handle is a masked channel\n *      - false current handle is not a masked channel\n */\nbool waterproof_check_mask_handle(touch_elem_handle_t te_handle)\n{\n    if (waterproof_check_state() == false) {\n        return false;\n    }\n    if (waterproof_guard_check_state() == false) {\n        return false;\n    }\n    te_waterproof_handle_t waterproof_handle = s_te_obj->waterproof_handle;\n    bool ret = false;\n    if (waterproof_handle->guard_device->state == TE_STATE_PRESS) {\n        for (int idx = 0; idx < TOUCH_PAD_MAX; idx++) {\n            if (waterproof_handle->mask_handle[idx] == NULL) {\n                break;\n            }\n            if (waterproof_handle->mask_handle[idx] == te_handle) {\n                ret = true;\n            }\n        }\n    }\n    return ret;\n}\n\nstatic void waterproof_guard_update_state(touch_pad_t current_channel, te_state_t current_state)\n{\n    te_dev_t *guard_device = s_te_obj->waterproof_handle->guard_device;\n    if (current_channel == guard_device->channel) {\n        guard_device->state = current_state;\n    }\n    ESP_LOGD(TE_DEBUG_TAG, \"waterproof guard state update  %d\", guard_device->state);\n}\n\nesp_err_t touch_element_enable_light_sleep(const touch_elem_sleep_config_t *sleep_config)\n{\n    TE_CHECK(s_te_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(s_te_obj->sleep_handle == NULL, ESP_ERR_INVALID_STATE);\n    uint16_t sample_count = 500;\n    uint16_t sleep_cycle = 0x0f;\n    if (sleep_config) {\n        sample_count = sleep_config->sample_count;\n        sleep_cycle = sleep_config->sleep_cycle;\n    }\n\n    s_te_obj->sleep_handle = calloc(1, sizeof(struct te_sleep_s));\n    TE_CHECK(s_te_obj->sleep_handle, ESP_ERR_NO_MEM);\n\n    esp_err_t ret = ESP_OK;\n    touch_hal_sleep_channel_set_work_time(sleep_cycle, sample_count);\n    TE_CHECK_GOTO(esp_sleep_enable_touchpad_wakeup() == ESP_OK,  cleanup);\n\n    TE_CHECK_GOTO(esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON) == ESP_OK,  cleanup);\n    s_te_obj->sleep_handle->non_volatile_threshold = threshold_shadow;\n\n#ifdef CONFIG_PM_ENABLE\n    TE_CHECK_GOTO(esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, \"touch_element\", &s_te_obj->sleep_handle->pm_lock) == ESP_OK,  cleanup);\n    TE_CHECK_GOTO(esp_pm_lock_acquire(s_te_obj->sleep_handle->pm_lock) == ESP_OK,  cleanup);\n#endif\n\n    return ESP_OK;\n\ncleanup:\n#ifdef CONFIG_PM_ENABLE\n    if (s_te_obj->sleep_handle->pm_lock != NULL) {\n        if (esp_pm_lock_delete(s_te_obj->sleep_handle->pm_lock) != ESP_OK) {\n            abort();\n        }\n    }\n#endif\n    TE_FREE_AND_NULL(s_te_obj->sleep_handle);\n    return ret;\n}\n\nesp_err_t touch_element_disable_light_sleep(void)\n{\n    TE_CHECK(s_te_obj->sleep_handle, ESP_ERR_INVALID_STATE);\n#ifdef CONFIG_PM_ENABLE\n    if (s_te_obj->sleep_handle->pm_lock != NULL) {\n        /* Sleep channel is going to uninstall, pm lock is not needed anymore,\n           but we need to make sure that pm lock has been released before delete it. */\n        while (esp_pm_lock_release(s_te_obj->sleep_handle->pm_lock) == ESP_OK);\n        esp_err_t ret = esp_pm_lock_delete(s_te_obj->sleep_handle->pm_lock);\n        TE_CHECK(ret == ESP_OK, ret);\n        s_te_obj->sleep_handle->pm_lock = NULL;\n    }\n#endif\n    esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TOUCHPAD);\n    TE_FREE_AND_NULL(s_te_obj->sleep_handle);\n    return ESP_OK;\n}\n\nesp_err_t touch_element_enable_deep_sleep(touch_elem_handle_t wakeup_elem_handle, const touch_elem_sleep_config_t *sleep_config)\n{\n    TE_CHECK(s_te_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(s_te_obj->sleep_handle == NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(wakeup_elem_handle != NULL, ESP_ERR_INVALID_ARG);\n    TE_CHECK(sleep_config != NULL, ESP_ERR_INVALID_ARG);\n    uint16_t sample_count = 500;\n    uint16_t sleep_cycle = 0x0f;\n    if (sleep_config) {\n        sample_count = sleep_config->sample_count;\n        sleep_cycle = sleep_config->sleep_cycle;\n    }\n\n    s_te_obj->sleep_handle = calloc(1, sizeof(struct te_sleep_s));\n    TE_CHECK(s_te_obj->sleep_handle, ESP_ERR_NO_MEM);\n\n    esp_err_t ret = ESP_OK;\n    touch_hal_sleep_channel_set_work_time(sleep_cycle, sample_count);\n    TE_CHECK_GOTO(esp_sleep_enable_touchpad_wakeup() == ESP_OK,  cleanup);\n\n    TE_CHECK_GOTO(esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON) == ESP_OK, cleanup);\n    s_te_obj->sleep_handle->non_volatile_threshold = threshold_shadow;\n\n#ifdef CONFIG_PM_ENABLE\n    TE_CHECK_GOTO(esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, \"touch_element\", &s_te_obj->sleep_handle->pm_lock) == ESP_OK,  cleanup);\n    TE_CHECK_GOTO(esp_pm_lock_acquire(s_te_obj->sleep_handle->pm_lock) == ESP_OK,  cleanup);\n#endif\n    //Only support one channel/element as the deep sleep wakeup channel/element\n    TE_CHECK(is_button_object_handle(wakeup_elem_handle), ESP_ERR_NOT_SUPPORTED);\n    s_te_obj->sleep_handle->wakeup_handle = wakeup_elem_handle;\n    te_button_handle_t button_handle = wakeup_elem_handle;\n    touch_hal_sleep_channel_enable(button_handle->device->channel, true);\n\n    return ESP_OK;\n\ncleanup:\n#ifdef CONFIG_PM_ENABLE\n    if (s_te_obj->sleep_handle->pm_lock != NULL) {\n        if (esp_pm_lock_delete(s_te_obj->sleep_handle->pm_lock) != ESP_OK) {\n            abort();\n        }\n    }\n#endif\n    TE_FREE_AND_NULL(s_te_obj->sleep_handle);\n    return ret;\n}\n\nesp_err_t touch_element_disable_deep_sleep(void)\n{\n    TE_CHECK(s_te_obj->sleep_handle, ESP_ERR_INVALID_STATE);\n#ifdef CONFIG_PM_ENABLE\n    if (s_te_obj->sleep_handle->pm_lock != NULL) {\n        /* Sleep channel is going to uninstall, pm lock is not needed anymore,\n           but we need to make sure that pm lock has been released before delete it. */\n        while (esp_pm_lock_release(s_te_obj->sleep_handle->pm_lock) == ESP_OK);\n        ret = esp_pm_lock_delete(s_te_obj->sleep_handle->pm_lock);\n        TE_CHECK(ret == ESP_OK, ret);\n        s_te_obj->sleep_handle->pm_lock = NULL;\n    }\n#endif\n    te_button_handle_t button_handle = s_te_obj->sleep_handle->wakeup_handle;\n    touch_hal_sleep_channel_enable(button_handle->device->channel, false);\n    esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TOUCHPAD);\n    s_te_obj->sleep_handle->wakeup_handle = NULL;\n    TE_FREE_AND_NULL(s_te_obj->sleep_handle);\n    return ESP_OK;\n}\n\nesp_err_t touch_element_sleep_enable_wakeup_calibration(touch_elem_handle_t element_handle, bool en)\n{\n    TE_CHECK(element_handle != NULL, ESP_ERR_INVALID_ARG);\n    if (is_button_object_handle(element_handle)) {\n        button_enable_wakeup_calibration(element_handle, en);\n    } else if (is_slider_object_handle(element_handle)) {\n        slider_enable_wakeup_calibration(element_handle, en);\n    } else if (is_matrix_object_handle(element_handle)) {\n        matrix_enable_wakeup_calibration(element_handle, en);\n    } else {\n        return ESP_ERR_NOT_FOUND;\n    }\n    return ESP_OK;\n}\n"
  },
  {
    "path": "touch_element/touch_matrix.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include <sys/queue.h>\n#include <inttypes.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/semphr.h\"\n#include \"esp_log.h\"\n#include \"esp_private/touch_element_private.h\"\n\n#define TE_MAT_POS_MAX  (0xff)      //!< Matrix button startup position\n\ntypedef struct te_matrix_handle_list {\n    te_matrix_handle_t matrix_handle;               //Matrix handle\n    SLIST_ENTRY(te_matrix_handle_list) next;        //Matrix handle list entry\n} te_matrix_handle_list_t;\n\ntypedef struct {\n    SLIST_HEAD(te_matrix_handle_list_head, te_matrix_handle_list) handle_list;      //Matrix handle (instance) list\n    touch_matrix_global_config_t *global_config;                                                   //Matrix global configuration\n    SemaphoreHandle_t mutex;                                                        //Matrix object mutex\n} te_matrix_obj_t;\n\nte_matrix_obj_t *s_te_mat_obj = NULL;\n/* ---------------------------------------- Matrix handle(instance) methods ----------------------------------------- */\nstatic bool matrix_channel_check(te_matrix_handle_t matrix_handle, touch_pad_t channel_num);\nstatic esp_err_t matrix_set_threshold(te_matrix_handle_t matrix_handle);\nstatic inline te_state_t matrix_get_state(te_matrix_state_t x_axis_state, te_matrix_state_t y_axis_state);\nstatic void matrix_reset_state(te_matrix_handle_t matrix_handle);\nstatic void matrix_update_state(te_matrix_handle_t matrix_handle, touch_pad_t channel_num, te_state_t channel_state);\nstatic void matrix_update_position(te_matrix_handle_t matrix_handle, touch_matrix_position_t new_pos);\nstatic void matrix_proc_state(te_matrix_handle_t matrix_handle);\nstatic void matrix_event_give(te_matrix_handle_t matrix_handle);\nstatic inline void matrix_dispatch(te_matrix_handle_t matrix_handle, touch_elem_dispatch_t dispatch_method);\n/* ------------------------------------------ Matrix object(class) methods ------------------------------------------ */\nstatic esp_err_t matrix_object_add_instance(te_matrix_handle_t matrix_handle);\nstatic esp_err_t matrix_object_remove_instance(te_matrix_handle_t matrix_handle);\nstatic bool matrix_object_check_channel(touch_pad_t channel_num);\nstatic esp_err_t matrix_object_set_threshold(void);\nstatic void matrix_object_process_state(void);\nstatic void matrix_object_update_state(touch_pad_t channel_num, te_state_t channel_state);\n/* ------------------------------------------------------------------------------------------------------------------ */\n\nesp_err_t touch_matrix_install(const touch_matrix_global_config_t *global_config)\n{\n    TE_CHECK(te_system_check_state() == true, ESP_ERR_INVALID_STATE);\n    TE_CHECK(global_config != NULL, ESP_ERR_INVALID_ARG);\n\n    //Fixme: Make it thread-safe\n    s_te_mat_obj = (te_matrix_obj_t *)calloc(1, sizeof(te_matrix_obj_t));\n    TE_CHECK(s_te_mat_obj != NULL, ESP_ERR_NO_MEM);\n    s_te_mat_obj->global_config = (touch_matrix_global_config_t *)calloc(1, sizeof(touch_matrix_global_config_t));\n    s_te_mat_obj->mutex = xSemaphoreCreateMutex();\n    TE_CHECK_GOTO(s_te_mat_obj->global_config != NULL && s_te_mat_obj->mutex != NULL, cleanup);\n    xSemaphoreTake(s_te_mat_obj->mutex, portMAX_DELAY);\n    SLIST_INIT(&s_te_mat_obj->handle_list);\n    memcpy(s_te_mat_obj->global_config, global_config, sizeof(touch_matrix_global_config_t));\n    te_object_methods_t matrix_methods = {\n        .handle = s_te_mat_obj,\n        .check_channel = matrix_object_check_channel,\n        .set_threshold = matrix_object_set_threshold,\n        .process_state = matrix_object_process_state,\n        .update_state = matrix_object_update_state\n    };\n    te_object_method_register(&matrix_methods, TE_CLS_TYPE_MATRIX);\n    xSemaphoreGive(s_te_mat_obj->mutex);\n    return ESP_OK;\n\ncleanup:\n    TE_FREE_AND_NULL(s_te_mat_obj->global_config);\n    if (s_te_mat_obj->mutex != NULL) {\n        vSemaphoreDelete(s_te_mat_obj->mutex);\n    }\n    TE_FREE_AND_NULL(s_te_mat_obj);\n    return ESP_ERR_NO_MEM;\n}\n\nvoid touch_matrix_uninstall(void)\n{\n    xSemaphoreTake(s_te_mat_obj->mutex, portMAX_DELAY);\n    if (s_te_mat_obj == NULL) {\n        xSemaphoreGive(s_te_mat_obj->mutex);\n        return;\n    }\n    te_object_method_unregister(TE_CLS_TYPE_MATRIX);\n    free(s_te_mat_obj->global_config);\n    s_te_mat_obj->global_config = NULL;\n    while (!SLIST_EMPTY(&s_te_mat_obj->handle_list)) {\n        SLIST_REMOVE_HEAD(&s_te_mat_obj->handle_list, next);\n    }\n    xSemaphoreGive(s_te_mat_obj->mutex);\n    vSemaphoreDelete(s_te_mat_obj->mutex);\n    free(s_te_mat_obj);\n    s_te_mat_obj = NULL;\n}\n\nesp_err_t touch_matrix_create(const touch_matrix_config_t *matrix_config, touch_matrix_handle_t *matrix_handle)\n{\n    TE_CHECK(s_te_mat_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(matrix_handle != NULL && matrix_config != NULL, ESP_ERR_INVALID_ARG);\n    TE_CHECK(matrix_config->x_channel_array != NULL &&\n             matrix_config->y_channel_array != NULL &&\n             matrix_config->x_sensitivity_array != NULL &&\n             matrix_config->y_sensitivity_array != NULL &&\n             matrix_config->x_channel_num > 1 &&\n             matrix_config->x_channel_num < TOUCH_PAD_MAX &&\n             matrix_config->y_channel_num > 1 &&\n             matrix_config->y_channel_num < TOUCH_PAD_MAX,\n             ESP_ERR_INVALID_ARG);\n    TE_CHECK(te_object_check_channel(matrix_config->x_channel_array, matrix_config->x_channel_num) == false &&\n             te_object_check_channel(matrix_config->y_channel_array, matrix_config->y_channel_num) == false,\n             ESP_ERR_INVALID_ARG);\n    te_matrix_handle_t te_matrix = (te_matrix_handle_t)calloc(1, sizeof(struct te_matrix_s));\n    TE_CHECK(te_matrix != NULL, ESP_ERR_NO_MEM);\n\n    esp_err_t ret = ESP_ERR_NO_MEM;\n    te_matrix->config = (te_matrix_handle_config_t *)calloc(1, sizeof(te_matrix_handle_config_t));\n    te_matrix->device = (te_dev_t **)calloc(matrix_config->x_channel_num + matrix_config->y_channel_num, sizeof(te_dev_t *));\n    TE_CHECK_GOTO(te_matrix->config != NULL && te_matrix->device != NULL, cleanup);\n    for (int idx = 0; idx < matrix_config->x_channel_num + matrix_config->y_channel_num; idx++) {\n        te_matrix->device[idx] = (te_dev_t *)calloc(1, sizeof(te_dev_t));\n        if (te_matrix->device[idx] == NULL) {\n            ret = ESP_ERR_NO_MEM;\n            goto cleanup;\n        }\n    }\n    /*< Initialize x-axis */\n    ret = te_dev_init(&te_matrix->device[0], matrix_config->x_channel_num, TOUCH_ELEM_TYPE_MATRIX,\n                      matrix_config->x_channel_array, matrix_config->x_sensitivity_array,\n                      TE_DEFAULT_THRESHOLD_DIVIDER(s_te_mat_obj));\n    TE_CHECK_GOTO(ret == ESP_OK, cleanup);\n    /*< Initialize y-axis */\n    ret = te_dev_init(&te_matrix->device[matrix_config->x_channel_num], matrix_config->y_channel_num,\n                      TOUCH_ELEM_TYPE_MATRIX, matrix_config->y_channel_array, matrix_config->y_sensitivity_array,\n                      TE_DEFAULT_THRESHOLD_DIVIDER(s_te_mat_obj));\n    TE_CHECK_GOTO(ret == ESP_OK, cleanup);\n\n    te_matrix->config->event_mask = TOUCH_ELEM_EVENT_NONE;\n    te_matrix->config->dispatch_method = TOUCH_ELEM_DISP_MAX;\n    te_matrix->config->callback = NULL;\n    te_matrix->config->arg = NULL;\n    te_matrix->current_state = TE_STATE_IDLE;\n    te_matrix->last_state = TE_STATE_IDLE;\n    te_matrix->event = TOUCH_MATRIX_EVT_MAX;\n    te_matrix->x_channel_num = matrix_config->x_channel_num;\n    te_matrix->y_channel_num = matrix_config->y_channel_num;\n    te_matrix->trigger_cnt = 0;\n    te_matrix->trigger_thr = 0xffffffff;\n    te_matrix->position.x_axis = TE_MAT_POS_MAX;\n    te_matrix->position.y_axis = TE_MAT_POS_MAX;\n    te_matrix->position.index = TE_MAT_POS_MAX;\n    ret = matrix_object_add_instance(te_matrix);\n    TE_CHECK_GOTO(ret == ESP_OK, cleanup);\n    *matrix_handle = (touch_elem_handle_t) te_matrix;\n    return ESP_OK;\n\ncleanup:\n    TE_FREE_AND_NULL(te_matrix->config);\n    if (te_matrix->device != NULL) {\n        for (int idx = 0; idx < matrix_config->x_channel_num + matrix_config->y_channel_num; idx++) {\n            TE_FREE_AND_NULL(te_matrix->device[idx]);\n        }\n        free(te_matrix->device);\n        te_matrix->device = NULL;\n    }\n    TE_FREE_AND_NULL(te_matrix);\n    return ret;\n}\n\nesp_err_t touch_matrix_delete(touch_matrix_handle_t matrix_handle)\n{\n    TE_CHECK(s_te_mat_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(matrix_handle != NULL, ESP_ERR_INVALID_ARG);\n    /*< Release touch sensor application resource */\n    esp_err_t ret = matrix_object_remove_instance(matrix_handle);\n    TE_CHECK(ret == ESP_OK, ret);\n    te_matrix_handle_t te_matrix = (te_matrix_handle_t)matrix_handle;\n    /*< Release touch sensor device resource */\n    te_dev_deinit(te_matrix->device, te_matrix->x_channel_num + te_matrix->y_channel_num);\n    for (int idx = 0; idx < te_matrix->x_channel_num + te_matrix->y_channel_num; idx++) {\n        free(te_matrix->device[idx]);\n    }\n    free(te_matrix->config);\n    free(te_matrix->device);\n    free(te_matrix);\n    return ESP_OK;\n}\n\nesp_err_t touch_matrix_set_dispatch_method(touch_matrix_handle_t matrix_handle, touch_elem_dispatch_t dispatch_method)\n{\n    TE_CHECK(s_te_mat_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(matrix_handle != NULL, ESP_ERR_INVALID_ARG);\n    TE_CHECK(dispatch_method >= TOUCH_ELEM_DISP_EVENT && dispatch_method <= TOUCH_ELEM_DISP_MAX, ESP_ERR_INVALID_ARG);\n    xSemaphoreTake(s_te_mat_obj->mutex, portMAX_DELAY);\n    te_matrix_handle_t te_matrix = (te_matrix_handle_t)matrix_handle;\n    te_matrix->config->dispatch_method = dispatch_method;\n    xSemaphoreGive(s_te_mat_obj->mutex);\n    return ESP_OK;\n}\n\nesp_err_t touch_matrix_subscribe_event(touch_matrix_handle_t matrix_handle, uint32_t event_mask, void *arg)\n{\n    TE_CHECK(s_te_mat_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(matrix_handle != NULL, ESP_ERR_INVALID_ARG);\n    if (!(event_mask & TOUCH_ELEM_EVENT_ON_PRESS) && !(event_mask & TOUCH_ELEM_EVENT_ON_RELEASE) &&\n            !(event_mask & TOUCH_ELEM_EVENT_ON_LONGPRESS) && !(event_mask & TOUCH_ELEM_EVENT_NONE)) {\n        ESP_LOGE(TE_TAG, \"Touch button only support TOUCH_ELEM_EVENT_ON_PRESS, \"\n                 \"TOUCH_ELEM_EVENT_ON_RELEASE, TOUCH_ELEM_EVENT_ON_LONGPRESS event mask\");\n        return ESP_ERR_INVALID_ARG;\n    }\n    if (event_mask & TOUCH_ELEM_EVENT_ON_LONGPRESS) {\n        touch_matrix_set_longpress(matrix_handle, TE_DEFAULT_LONGPRESS_TIME(s_te_mat_obj));  //set the default time(1000ms) for long press\n    }\n    xSemaphoreTake(s_te_mat_obj->mutex, portMAX_DELAY);\n    te_matrix_handle_t te_matrix = (te_matrix_handle_t)matrix_handle;\n    te_matrix->config->event_mask = event_mask;\n    te_matrix->config->arg = arg;\n    xSemaphoreGive(s_te_mat_obj->mutex);\n    return ESP_OK;\n}\n\nesp_err_t touch_matrix_set_callback(touch_matrix_handle_t matrix_handle, touch_matrix_callback_t matrix_callback)\n{\n    TE_CHECK(s_te_mat_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(matrix_handle != NULL, ESP_ERR_INVALID_ARG);\n    TE_CHECK(matrix_callback != NULL, ESP_ERR_INVALID_ARG);\n    te_matrix_handle_t te_matrix = (te_matrix_handle_t)matrix_handle;\n    xSemaphoreTake(s_te_mat_obj->mutex, portMAX_DELAY);\n    te_matrix->config->callback = matrix_callback;\n    xSemaphoreGive(s_te_mat_obj->mutex);\n    return ESP_OK;\n}\n\nesp_err_t touch_matrix_set_longpress(touch_matrix_handle_t matrix_handle, uint32_t threshold_time)\n{\n    TE_CHECK(s_te_mat_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(matrix_handle != NULL, ESP_ERR_INVALID_ARG);\n    TE_CHECK(threshold_time > 0, ESP_ERR_INVALID_ARG);\n    te_matrix_handle_t te_matrix = (te_matrix_handle_t)matrix_handle;\n    touch_elem_dispatch_t dispatch_method = te_matrix->config->dispatch_method;\n    if (dispatch_method == TOUCH_ELEM_DISP_EVENT) {\n        xSemaphoreTake(s_te_mat_obj->mutex, portMAX_DELAY);\n    }\n    uint8_t timer_period = te_get_timer_period();\n    te_matrix->trigger_thr = threshold_time / timer_period;\n    if (dispatch_method == TOUCH_ELEM_DISP_EVENT) {\n        xSemaphoreGive(s_te_mat_obj->mutex);\n    }\n    return ESP_OK;\n}\n\nconst touch_matrix_message_t *touch_matrix_get_message(const touch_elem_message_t *element_message)\n{\n    return (touch_matrix_message_t *)&element_message->child_msg;\n    _Static_assert(sizeof(element_message->child_msg) >= sizeof(touch_matrix_message_t), \"Message size overflow\");\n}\n\nstatic bool matrix_object_check_channel(touch_pad_t channel_num)\n{\n    te_matrix_handle_list_t *item;\n    SLIST_FOREACH(item, &s_te_mat_obj->handle_list, next) {\n        if (matrix_channel_check(item->matrix_handle, channel_num)) {\n            return true;\n        }\n    }\n    return false;\n}\n\nstatic esp_err_t matrix_object_set_threshold(void)\n{\n    esp_err_t ret = ESP_OK;\n    te_matrix_handle_list_t *item;\n    SLIST_FOREACH(item, &s_te_mat_obj->handle_list, next) {\n        ret = matrix_set_threshold(item->matrix_handle);\n        if (ret != ESP_OK) {\n            break;\n        }\n    }\n    return ret;\n}\n\nstatic void matrix_object_process_state(void)\n{\n    te_matrix_handle_list_t *item;\n    SLIST_FOREACH(item, &s_te_mat_obj->handle_list, next) {\n        if (waterproof_check_mask_handle(item->matrix_handle)) {\n            matrix_reset_state(item->matrix_handle);\n            continue;\n        }\n        matrix_proc_state(item->matrix_handle);\n    }\n}\n\nstatic void matrix_object_update_state(touch_pad_t channel_num, te_state_t channel_state)\n{\n    te_matrix_handle_list_t *item;\n    SLIST_FOREACH(item, &s_te_mat_obj->handle_list, next) {\n        if (waterproof_check_mask_handle(item->matrix_handle)) {\n            continue;\n        }\n        matrix_update_state(item->matrix_handle, channel_num, channel_state);\n    }\n}\n\nstatic esp_err_t matrix_object_add_instance(te_matrix_handle_t matrix_handle)\n{\n    te_matrix_handle_list_t *item = (te_matrix_handle_list_t *)calloc(1, sizeof(te_matrix_handle_list_t));\n    TE_CHECK(item != NULL, ESP_ERR_NO_MEM);\n    item->matrix_handle = matrix_handle;\n    xSemaphoreTake(s_te_mat_obj->mutex, portMAX_DELAY);\n    SLIST_INSERT_HEAD(&s_te_mat_obj->handle_list, item, next);\n    xSemaphoreGive(s_te_mat_obj->mutex);\n    return ESP_OK;\n}\n\nstatic esp_err_t matrix_object_remove_instance(te_matrix_handle_t matrix_handle)\n{\n    esp_err_t ret = ESP_ERR_NOT_FOUND;\n    te_matrix_handle_list_t *item;\n    SLIST_FOREACH(item, &s_te_mat_obj->handle_list, next) {\n        if (matrix_handle == item->matrix_handle) {\n            xSemaphoreTake(s_te_mat_obj->mutex, portMAX_DELAY);\n            SLIST_REMOVE(&s_te_mat_obj->handle_list, item, te_matrix_handle_list, next);\n            xSemaphoreGive(s_te_mat_obj->mutex);\n            free(item);\n            ret = ESP_OK;\n            break;\n        }\n    }\n    return ret;\n}\n\nbool is_matrix_object_handle(touch_elem_handle_t element_handle)\n{\n    te_matrix_handle_list_t *item;\n    xSemaphoreTake(s_te_mat_obj->mutex, portMAX_DELAY);\n    SLIST_FOREACH(item, &s_te_mat_obj->handle_list, next) {\n        if (element_handle == item->matrix_handle) {\n            xSemaphoreGive(s_te_mat_obj->mutex);\n            return true;\n        }\n    }\n    xSemaphoreGive(s_te_mat_obj->mutex);\n    return false;\n}\n\nstatic bool matrix_channel_check(te_matrix_handle_t matrix_handle, touch_pad_t channel_num)\n{\n    te_dev_t *device;\n    for (int idx = 0; idx < matrix_handle->x_channel_num + matrix_handle->y_channel_num; idx++) {\n        device = matrix_handle->device[idx];\n        if (device->channel == channel_num) {\n            return true;\n        }\n    }\n    return false;\n}\n\nstatic esp_err_t matrix_set_threshold(te_matrix_handle_t matrix_handle)\n{\n    esp_err_t ret = ESP_OK;\n    for (int idx = 0; idx < matrix_handle->x_channel_num + matrix_handle->y_channel_num; idx++) {\n        ret |= te_dev_set_threshold(matrix_handle->device[idx]);\n    }\n    return ret;\n}\n\nstatic void matrix_update_state(te_matrix_handle_t matrix_handle, touch_pad_t channel_num, te_state_t channel_state)\n{\n    te_dev_t *device;\n    for (int idx = 0; idx < matrix_handle->x_channel_num + matrix_handle->y_channel_num; idx++) {\n        device = matrix_handle->device[idx];\n        if (channel_num == device->channel) {\n            device->state = channel_state;\n        }\n    }\n}\n\nstatic void matrix_reset_state(te_matrix_handle_t matrix_handle)\n{\n    for (int idx = 0; idx < matrix_handle->x_channel_num + matrix_handle->y_channel_num; idx++) {\n        matrix_handle->device[idx]->state = TE_STATE_IDLE;\n    }\n    matrix_handle->trigger_cnt = 0;\n    matrix_handle->current_state = TE_STATE_IDLE;\n}\n\nstatic void matrix_event_give(te_matrix_handle_t matrix_handle)\n{\n    touch_elem_message_t element_message;\n    touch_matrix_message_t matrix_message = {\n        .event = matrix_handle->event,\n        .position = matrix_handle->position\n    };\n    element_message.handle = (touch_elem_handle_t)matrix_handle;\n    element_message.element_type = TOUCH_ELEM_TYPE_MATRIX;\n    element_message.arg = matrix_handle->config->arg;\n    memcpy(element_message.child_msg, &matrix_message, sizeof(matrix_message));\n    te_event_give(element_message);\n}\n\nstatic inline void matrix_dispatch(te_matrix_handle_t matrix_handle, touch_elem_dispatch_t dispatch_method)\n{\n    if (dispatch_method == TOUCH_ELEM_DISP_EVENT) {\n        matrix_event_give(matrix_handle);  //Event queue\n    } else if (dispatch_method == TOUCH_ELEM_DISP_CALLBACK) {\n        touch_matrix_message_t matrix_info;\n        matrix_info.event = matrix_handle->event;\n        matrix_info.position = matrix_handle->position;\n        void *arg = matrix_handle->config->arg;\n        matrix_handle->config->callback(matrix_handle, &matrix_info, arg);  //Event callback\n    }\n}\n\nvoid matrix_enable_wakeup_calibration(te_matrix_handle_t matrix_handle, bool en)\n{\n    for (int idx = 0; idx < matrix_handle->x_channel_num + matrix_handle->y_channel_num; ++idx) {\n        matrix_handle->device[idx]->is_use_last_threshold = !en;\n    }\n}\n\n/**\n * @brief   Scan the matrix channel\n *\n * This function will output the press position and release position info\n * so as to determine which operation(press/release) is happening, since there\n * will get the invalid state if user operates multi-points at the same time.\n *\n */\nstatic void matrix_scan_axis(te_matrix_handle_t matrix_handle, touch_matrix_position_t *press_pos,\n                             uint8_t *press_cnt, touch_matrix_position_t *release_pos, uint8_t *release_cnt)\n{\n    press_pos->x_axis = TE_MAT_POS_MAX;\n    press_pos->y_axis = TE_MAT_POS_MAX;\n    release_pos->x_axis = TE_MAT_POS_MAX;\n    release_pos->y_axis = TE_MAT_POS_MAX;\n    for (int idx = 0; idx < matrix_handle->x_channel_num + matrix_handle->y_channel_num; idx++) {\n        te_dev_t *device = matrix_handle->device[idx];\n        if (device->state == TE_STATE_PRESS) {\n            if (idx < matrix_handle->x_channel_num) {\n                press_pos->x_axis = idx;                             //Write down the x axis info\n            } else {\n                press_pos->y_axis = idx - matrix_handle->x_channel_num;  //Write down the y axis info\n            }\n            (*press_cnt)++;\n        } else if (device->state == TE_STATE_RELEASE) {\n            if (idx < matrix_handle->x_channel_num) {\n                release_pos->x_axis = idx;\n            } else {\n                release_pos->y_axis = idx - matrix_handle->x_channel_num;\n            }\n            (*release_cnt)++;\n        }\n    }\n}\n\n/**\n * @brief   Pre-check and fix\n *\n * This function will pre-check and fix the invalid state, preparing for the\n * next detection.\n *\n */\nstatic void matrix_pre_fixed(te_matrix_handle_t matrix_handle, touch_matrix_position_t *press_pos,\n                             uint8_t press_cnt, touch_matrix_position_t *release_pos, uint8_t release_cnt)\n{\n    te_dev_t *device;\n    te_matrix_state_t last_state = matrix_handle->current_state;\n    touch_matrix_position_t last_pos = {\n        .x_axis = matrix_handle->position.x_axis,\n        .y_axis = matrix_handle->position.y_axis\n    };\n    if (last_state == TE_STATE_IDLE) {\n        if (release_cnt > 0) {\n            /*< Release is not allowed while matrix is in IDLE state, */\n            /*< if that happened, reset it from Release into IDLE.    */\n            for (int idx = 0; idx < matrix_handle->x_channel_num + matrix_handle->y_channel_num; idx++) {\n                device = matrix_handle->device[idx];\n                if (device->state != TE_STATE_RELEASE) {\n                    continue;\n                }\n                device->state = TE_STATE_IDLE;  //Reset to IDLE\n            }\n        }\n    } else if (last_state == TE_STATE_PRESS) {\n        if (release_cnt > 0) {\n            /*< Release position must be the same as the last Press position, */\n            /*< if it is not, reset it into IDLE.                             */\n            if (release_pos->x_axis != TE_MAT_POS_MAX && release_pos->x_axis != last_pos.x_axis) {\n                device = matrix_handle->device[release_pos->x_axis];\n                device->state = TE_STATE_IDLE;\n            }\n            if (release_pos->y_axis != TE_MAT_POS_MAX && release_pos->y_axis != last_pos.y_axis) {\n                device = matrix_handle->device[release_pos->y_axis + matrix_handle->x_channel_num];\n                device->state = TE_STATE_IDLE;\n            }\n        }\n        if (press_cnt > 2) { //TODO: remove or rewrite here\n            /*< If the last state is Press and current press count more than 2, */\n            /*< there must be multi-touch occurred, reset all of the channels   */\n            /*< into IDLE except the last position channels.                    */\n            if (press_pos->x_axis != TE_MAT_POS_MAX && press_pos->x_axis != last_pos.x_axis) {\n                device = matrix_handle->device[press_pos->x_axis];\n                device->state = TE_STATE_IDLE;\n            }\n            if (press_pos->y_axis != TE_MAT_POS_MAX && press_pos->y_axis != last_pos.y_axis) {\n                device = matrix_handle->device[press_pos->y_axis + matrix_handle->x_channel_num];\n                device->state = TE_STATE_IDLE;\n            }\n        }\n    }\n}\n\n//TODO: refactor this ugly implementation\nstatic esp_err_t matrix_get_axis_state(touch_matrix_position_t *press_pos, uint8_t press_cnt, touch_matrix_position_t *release_pos,\n                                       uint8_t release_cnt, te_matrix_state_t *x_axis_state, te_matrix_state_t *y_axis_state)\n{\n    esp_err_t ret = ESP_OK;\n    if (press_cnt >= 2) {\n        if (press_pos->x_axis != TE_MAT_POS_MAX && press_pos->y_axis != TE_MAT_POS_MAX) {\n            *x_axis_state = TE_STATE_PRESS;\n            *y_axis_state = TE_STATE_PRESS;\n            ret = ESP_OK;\n        } else {\n            ret = ESP_ERR_INVALID_STATE;\n        }\n\n    } else if (release_cnt >= 2) {\n        if (release_pos->x_axis != TE_MAT_POS_MAX && release_pos->y_axis != TE_MAT_POS_MAX) {\n            *x_axis_state = TE_STATE_RELEASE;\n            *y_axis_state = TE_STATE_RELEASE;\n            ret = ESP_OK;\n        } else {\n            ret = ESP_ERR_INVALID_STATE;\n        }\n    } else {\n        ret = ESP_ERR_INVALID_STATE;\n    }\n    return ret;\n}\n\n/**\n * @brief Matrix button process\n *\n * This function will process the matrix button state and maintain a matrix FSM:\n *              IDLE ----> Press ----> Release ----> IDLE\n *\n * The state transition procedure is as follow:\n *       (channel state ----> x,y axis state ----> matrix button state)\n *\n * TODO: add state transition diagram\n */\nstatic void matrix_proc_state(te_matrix_handle_t matrix_handle)\n{\n    esp_err_t ret = ESP_OK;\n    uint8_t press_cnt = 0;\n    uint8_t release_cnt = 0;\n    touch_matrix_position_t press_pos;\n    touch_matrix_position_t release_pos;\n    te_matrix_state_t x_axis_state = TE_STATE_IDLE;\n    te_matrix_state_t y_axis_state = TE_STATE_IDLE;\n    uint32_t event_mask = matrix_handle->config->event_mask;\n    touch_elem_dispatch_t dispatch_method = matrix_handle->config->dispatch_method;\n\n    BaseType_t mux_ret = xSemaphoreTake(s_te_mat_obj->mutex, 0);\n    if (mux_ret != pdPASS) {\n        return;\n    }\n\n    //TODO: refactor those functions\n    /*< Scan the state of all the matrix buttons channel */\n    matrix_scan_axis(matrix_handle, &press_pos, &press_cnt, &release_pos, &release_cnt);\n\n    /*< Pre check and fixed the invalid state */\n    matrix_pre_fixed(matrix_handle, &press_pos, press_cnt, &release_pos, release_cnt);\n\n    /*< Figure out x,y axis state and take the position */\n    ret = matrix_get_axis_state(&press_pos, press_cnt, &release_pos, release_cnt, &x_axis_state, &y_axis_state);\n    if (ret != ESP_OK) { //TODO: remove return\n        xSemaphoreGive(s_te_mat_obj->mutex);\n        return;\n    }\n\n    matrix_handle->current_state = matrix_get_state(x_axis_state, y_axis_state);\n\n    if (matrix_handle->current_state == TE_STATE_PRESS) {\n        if (matrix_handle->last_state == TE_STATE_IDLE) { //IDLE ---> Press = On_Press\n            matrix_update_position(matrix_handle, press_pos);\n            ESP_LOGD(TE_DEBUG_TAG, \"matrix press  (%\"PRIu8\", %\"PRIu8\")\", matrix_handle->position.x_axis, matrix_handle->position.y_axis);\n            if (event_mask & TOUCH_ELEM_EVENT_ON_PRESS) {\n                matrix_handle->event = TOUCH_MATRIX_EVT_ON_PRESS;\n                matrix_dispatch(matrix_handle, dispatch_method);\n            }\n        } else if (matrix_handle->last_state == TE_STATE_PRESS) { //Press ---> Press = On_LongPress\n            if (event_mask & TOUCH_ELEM_EVENT_ON_LONGPRESS) {\n                if (++matrix_handle->trigger_cnt >= matrix_handle->trigger_thr) {\n                    ESP_LOGD(TE_DEBUG_TAG, \"matrix longpress (%\"PRIu8\", %\"PRIu8\")\", matrix_handle->position.x_axis, matrix_handle->position.y_axis);\n                    matrix_handle->event = TOUCH_MATRIX_EVT_ON_LONGPRESS;\n                    matrix_dispatch(matrix_handle, dispatch_method);\n                    matrix_handle->trigger_cnt = 0;\n                }\n            }\n        }\n    } else if (matrix_handle->current_state == TE_STATE_RELEASE) {\n        if (matrix_handle->last_state == TE_STATE_PRESS) {  //Press ---> Release = On_Release\n            ESP_LOGD(TE_DEBUG_TAG, \"matrix release (%\"PRIu8\", %\"PRIu8\")\", matrix_handle->position.x_axis, matrix_handle->position.y_axis);\n            if (event_mask & TOUCH_ELEM_EVENT_ON_RELEASE) {\n                matrix_handle->event = TOUCH_MATRIX_EVT_ON_RELEASE;\n                matrix_dispatch(matrix_handle, dispatch_method);\n            }\n        } else if (matrix_handle->last_state == TE_STATE_RELEASE) {  // Release ---> Release = On_IDLE (Not dispatch)\n            matrix_reset_state(matrix_handle);\n        }\n    } else if (matrix_handle->current_state == TE_STATE_IDLE) {\n        if (matrix_handle->last_state == TE_STATE_RELEASE) {  //Release ---> IDLE = On_IDLE (Not dispatch)\n            //Nothing\n        } else if (matrix_handle->last_state == TE_STATE_IDLE) { //IDLE ---> IDLE = Running IDLE (Not dispatch)\n            //Move Pre-fix into here\n        }\n    }\n    matrix_handle->last_state = matrix_handle->current_state;\n    xSemaphoreGive(s_te_mat_obj->mutex);\n}\n\nstatic inline te_state_t matrix_get_state(te_matrix_state_t x_axis_state, te_matrix_state_t y_axis_state)\n{\n    te_state_t matrix_state;\n    if ((x_axis_state == TE_STATE_PRESS) && (y_axis_state == TE_STATE_PRESS)) {\n        matrix_state = TE_STATE_PRESS;\n    } else if ((x_axis_state == TE_STATE_RELEASE) && (y_axis_state == TE_STATE_RELEASE)) {\n        matrix_state = TE_STATE_RELEASE;\n    } else {\n        matrix_state = TE_STATE_IDLE;\n    }\n    return matrix_state;\n}\n\nstatic void matrix_update_position(te_matrix_handle_t matrix_handle, touch_matrix_position_t new_pos)\n{\n    matrix_handle->position.x_axis = new_pos.x_axis;\n    matrix_handle->position.y_axis = new_pos.y_axis;\n    matrix_handle->position.index = matrix_handle->position.x_axis * matrix_handle->y_channel_num + matrix_handle->position.y_axis;\n}\n"
  },
  {
    "path": "touch_element/touch_sensor_legacy_hal.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include \"esp_private/touch_sensor_legacy_ll.h\"\n#include \"esp_private/touch_sensor_legacy_hal.h\"\n#include \"touch_element/touch_sensor_legacy_types.h\"\n\nstatic int s_sleep_cycle = -1;\nstatic int s_meas_times = -1;\n\nvoid touch_hal_init(void)\n{\n    touch_ll_stop_fsm();\n    touch_ll_reset();   // Reset the touch sensor FSM.\n    touch_ll_intr_disable((touch_pad_intr_mask_t)TOUCH_LL_INTR_MASK_ALL);\n    touch_ll_intr_clear((touch_pad_intr_mask_t)TOUCH_LL_INTR_MASK_ALL);\n    touch_ll_clear_channel_mask(TOUCH_PAD_BIT_MASK_ALL);\n    touch_ll_clear_trigger_status_mask();\n    touch_ll_set_meas_times(TOUCH_PAD_MEASURE_CYCLE_DEFAULT);\n    touch_ll_set_sleep_time(TOUCH_PAD_SLEEP_CYCLE_DEFAULT);\n    /* Configure the touch-sensor power domain into self-bias since bandgap-bias\n     * level is different under sleep-mode compared to running-mode. self-bias is\n     * always on after chip startup. */\n    touch_ll_sleep_low_power(true);\n    touch_ll_set_voltage_high(TOUCH_PAD_HIGH_VOLTAGE_THRESHOLD);\n    touch_ll_set_voltage_low(TOUCH_PAD_LOW_VOLTAGE_THRESHOLD);\n    touch_ll_set_voltage_attenuation(TOUCH_PAD_ATTEN_VOLTAGE_THRESHOLD);\n    touch_ll_set_idle_channel_connect(TOUCH_PAD_IDLE_CH_CONNECT_DEFAULT);\n    /* Clear touch channels to initialize the channel value (benchmark, raw_data).\n     * Note: Should call it after enable clock gate. */\n    touch_ll_clkgate(true);  // Enable clock gate for touch sensor.\n    touch_ll_reset_benchmark(TOUCH_PAD_MAX);\n    touch_ll_sleep_reset_benchmark();\n}\n\nvoid touch_hal_deinit(void)\n{\n    touch_ll_reset_benchmark(TOUCH_PAD_MAX);\n    touch_ll_sleep_reset_benchmark();\n    touch_ll_stop_fsm();\n    touch_ll_clkgate(false);\n    touch_ll_clear_channel_mask(TOUCH_PAD_BIT_MASK_ALL);\n    touch_ll_clear_trigger_status_mask();\n    touch_ll_intr_disable((touch_pad_intr_mask_t)TOUCH_LL_INTR_MASK_ALL);\n    touch_ll_timeout_disable();\n    touch_ll_waterproof_enable(false);\n    touch_ll_denoise_enable(false);\n    touch_pad_t prox_pad[TOUCH_LL_PROXIMITY_CHANNEL_NUM] = {[0 ... (TOUCH_LL_PROXIMITY_CHANNEL_NUM - 1)] = 0};\n    touch_ll_proximity_set_channel_num((const touch_pad_t *)prox_pad);\n    touch_ll_sleep_set_channel_num(0);\n    touch_ll_sleep_enable_proximity_sensing(false);\n    touch_ll_reset();   // Reset the touch sensor FSM.\n}\n\nvoid touch_hal_config(touch_pad_t touch_num)\n{\n    touch_ll_set_threshold(touch_num, TOUCH_PAD_THRESHOLD_MAX);\n    touch_ll_set_slope(touch_num, TOUCH_PAD_SLOPE_DEFAULT);\n    touch_ll_set_tie_option(touch_num, TOUCH_PAD_TIE_OPT_DEFAULT);\n}\n\nvoid touch_hal_set_voltage(const touch_hal_volt_t *volt)\n{\n    touch_ll_set_voltage_high(volt->refh);\n    touch_ll_set_voltage_low(volt->refl);\n    touch_ll_set_voltage_attenuation(volt->atten);\n}\n\nvoid touch_hal_get_voltage(touch_hal_volt_t *volt)\n{\n    touch_ll_get_voltage_high(&volt->refh);\n    touch_ll_get_voltage_low(&volt->refl);\n    touch_ll_get_voltage_attenuation(&volt->atten);\n}\n\nvoid touch_hal_set_meas_mode(touch_pad_t touch_num, const touch_hal_meas_mode_t *meas)\n{\n    touch_ll_set_slope(touch_num, meas->slope);\n    touch_ll_set_tie_option(touch_num, meas->tie_opt);\n}\n\nvoid touch_hal_get_meas_mode(touch_pad_t touch_num, touch_hal_meas_mode_t *meas)\n{\n    touch_ll_get_slope(touch_num, &meas->slope);\n    touch_ll_get_tie_option(touch_num, &meas->tie_opt);\n}\n\nvoid touch_hal_filter_set_config(const touch_filter_config_t *filter_info)\n{\n    touch_ll_filter_set_filter_mode(filter_info->mode);\n    touch_ll_filter_set_debounce(filter_info->debounce_cnt);\n    touch_ll_filter_set_noise_thres(filter_info->noise_thr);\n    touch_ll_filter_set_jitter_step(filter_info->jitter_step);\n    touch_ll_filter_set_smooth_mode(filter_info->smh_lvl);\n}\n\nvoid touch_hal_filter_get_config(touch_filter_config_t *filter_info)\n{\n    touch_ll_filter_get_filter_mode(&filter_info->mode);\n    touch_ll_filter_get_debounce(&filter_info->debounce_cnt);\n    touch_ll_filter_get_noise_thres(&filter_info->noise_thr);\n    touch_ll_filter_get_jitter_step(&filter_info->jitter_step);\n    touch_ll_filter_get_smooth_mode(&filter_info->smh_lvl);\n}\n\nvoid touch_hal_denoise_set_config(const touch_pad_denoise_t *denoise)\n{\n    touch_ll_denoise_set_cap_level(denoise->cap_level);\n    touch_ll_denoise_set_grade(denoise->grade);\n}\n\nvoid touch_hal_denoise_get_config(touch_pad_denoise_t *denoise)\n{\n    touch_ll_denoise_get_cap_level(&denoise->cap_level);\n    touch_ll_denoise_get_grade(&denoise->grade);\n}\n\nvoid touch_hal_denoise_enable(void)\n{\n    touch_ll_clear_channel_mask(1U << TOUCH_LL_DENOISE_CHANNEL);\n    touch_ll_denoise_enable(true);\n}\n\nvoid touch_hal_waterproof_set_config(const touch_pad_waterproof_t *waterproof)\n{\n    touch_ll_waterproof_set_guard_pad(waterproof->guard_ring_pad);\n    touch_ll_waterproof_set_shield_driver(waterproof->shield_driver);\n}\n\nvoid touch_hal_waterproof_get_config(touch_pad_waterproof_t *waterproof)\n{\n    touch_ll_waterproof_get_guard_pad(&waterproof->guard_ring_pad);\n    touch_ll_waterproof_get_shield_driver(&waterproof->shield_driver);\n}\n\nvoid touch_hal_waterproof_enable(void)\n{\n    touch_ll_clear_channel_mask(1U << TOUCH_LL_SHIELD_CHANNEL);\n    touch_ll_waterproof_enable(true);\n}\n\nbool touch_hal_enable_proximity(touch_pad_t touch_num, bool enabled)\n{\n    int i = 0;\n    touch_pad_t ch_num[TOUCH_LL_PROXIMITY_CHANNEL_NUM] = {0};\n    touch_ll_proximity_get_channel_num(ch_num);\n    if (enabled) {\n        for (i = 0; i < TOUCH_LL_PROXIMITY_CHANNEL_NUM; i++) {\n            if (ch_num[i] == TOUCH_PAD_NUM0 || ch_num[i] >= TOUCH_PAD_MAX || ch_num[i] == touch_num) {\n                ch_num[i] = touch_num;\n                break;\n            }\n        }\n        if (i == TOUCH_LL_PROXIMITY_CHANNEL_NUM) {\n            return false;\n        }\n    } else {\n        for (i = 0; i < TOUCH_LL_PROXIMITY_CHANNEL_NUM; i++) {\n            if (ch_num[i] == touch_num) {\n                ch_num[i] = TOUCH_PAD_NUM0;\n                break;\n            }\n        }\n    }\n    touch_ll_proximity_set_channel_num(ch_num);\n    return true;\n}\n\nvoid touch_hal_sleep_channel_enable(touch_pad_t pad_num, bool enable)\n{\n    if (enable) {\n        touch_ll_sleep_set_channel_num(pad_num);\n        touch_ll_sleep_set_threshold(TOUCH_PAD_THRESHOLD_MAX);\n        touch_ll_sleep_reset_benchmark();\n    } else {\n        touch_ll_sleep_set_channel_num(TOUCH_PAD_NUM0);\n    }\n}\n\nvoid touch_hal_sleep_channel_get_config(touch_pad_sleep_channel_t *slp_config)\n{\n    touch_ll_sleep_get_channel_num((uint32_t *)&slp_config->touch_num);\n    slp_config->en_proximity = touch_ll_sleep_is_proximity_enabled();\n}\n\nvoid touch_hal_sleep_channel_set_work_time(uint16_t sleep_cycle, uint16_t meas_times)\n{\n    s_sleep_cycle = (int)sleep_cycle;\n    s_meas_times = (int)meas_times;\n}\n\nvoid touch_hal_sleep_channel_get_work_time(uint16_t *sleep_cycle, uint16_t *meas_times)\n{\n    if (s_meas_times < 0) {\n        touch_ll_get_measure_times(meas_times);\n    } else {\n        *meas_times = (uint16_t)s_meas_times;\n    }\n    if (s_sleep_cycle < 0) {\n        touch_ll_get_sleep_time(sleep_cycle);\n    } else {\n        *sleep_cycle = (uint16_t)s_sleep_cycle;\n    }\n}\n"
  },
  {
    "path": "touch_element/touch_slider.c",
    "content": "/*\n * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n#include <string.h>\n#include <sys/queue.h>\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/semphr.h\"\n#include \"esp_log.h\"\n#include \"esp_private/touch_element_private.h\"\n\n#define TE_SLD_DEFAULT_QTF_THR(obj)                       ((obj)->global_config->quantify_lower_threshold)\n#define TE_SLD_DEFAULT_POS_FILTER_FACTOR(obj)             ((obj)->global_config->position_filter_factor)\n#define TE_SLD_DEFAULT_CALCULATE_CHANNEL(obj)             ((obj)->global_config->calculate_channel_count)\n#define TE_SLD_DEFAULT_BCM_UPDATE_TIME(obj)               ((obj)->global_config->benchmark_update_time)\n#define TE_SLD_DEFAULT_FILTER_RESET_TIME(obj)             ((obj)->global_config->filter_reset_time)\n#define TE_SLD_DEFAULT_POS_FILTER_SIZE(obj)               ((obj)->global_config->position_filter_size)\n\ntypedef struct te_slider_handle_list {\n    te_slider_handle_t slider_handle;           //Slider handle\n    SLIST_ENTRY(te_slider_handle_list) next;    //Slider handle list entry\n} te_slider_handle_list_t;\n\ntypedef struct {\n    SLIST_HEAD(te_slider_handle_list_head, te_slider_handle_list) handle_list;    //Slider handle (instance) list\n    touch_slider_global_config_t *global_config;                                  //Slider global configuration\n    SemaphoreHandle_t mutex;                                                      //Slider object mutex\n} te_slider_obj_t;\n\nte_slider_obj_t *s_te_sld_obj = NULL;\n/* ---------------------------------------- Slider handle(instance) methods ----------------------------------------- */\nstatic bool slider_channel_check(te_slider_handle_t slider_handle, touch_pad_t channel_num);\nstatic esp_err_t slider_set_threshold(te_slider_handle_t slider_handle);\nstatic inline te_state_t slider_get_state(te_dev_t **device, int device_num);\nstatic void slider_reset_state(te_slider_handle_t slider_handle);\nstatic void slider_update_position(te_slider_handle_t slider_handle);\nstatic void slider_reset_position(te_slider_handle_t slider_handle);\nstatic void slider_update_benchmark(te_slider_handle_t slider_handle);\nstatic void slider_update_state(te_slider_handle_t slider_handle, touch_pad_t channel_num, te_state_t channel_state);\nstatic void slider_proc_state(te_slider_handle_t slider_handle);\nstatic void slider_event_give(te_slider_handle_t slider_handle);\nstatic inline void slider_dispatch(te_slider_handle_t slider_handle, touch_elem_dispatch_t dispatch_method);\n/* ------------------------------------------ Slider object(class) methods ------------------------------------------ */\nstatic esp_err_t slider_object_add_instance(te_slider_handle_t slider_handle);\nstatic esp_err_t slider_object_remove_instance(te_slider_handle_t slider_handle);\nstatic bool slider_object_check_channel(touch_pad_t channel_num);\nstatic esp_err_t slider_object_set_threshold(void);\nstatic void slider_object_process_state(void);\nstatic void slider_object_update_state(touch_pad_t channel_num, te_state_t channel_state);\n/* ------------------------------------------------------------------------------------------------------------------ */\n\nesp_err_t touch_slider_install(const touch_slider_global_config_t *global_config)\n{\n    TE_CHECK(te_system_check_state() == true, ESP_ERR_INVALID_STATE);\n    TE_CHECK(global_config != NULL, ESP_ERR_INVALID_ARG);\n    //Fixme: Make it thread-safe\n    s_te_sld_obj = (te_slider_obj_t *)calloc(1, sizeof(te_slider_obj_t));\n    TE_CHECK(s_te_sld_obj != NULL, ESP_ERR_NO_MEM);\n    s_te_sld_obj->global_config = (touch_slider_global_config_t *)calloc(1, sizeof(touch_slider_global_config_t));\n    s_te_sld_obj->mutex = xSemaphoreCreateMutex();\n    TE_CHECK_GOTO(s_te_sld_obj->global_config != NULL && s_te_sld_obj->mutex != NULL, cleanup);\n    xSemaphoreTake(s_te_sld_obj->mutex, portMAX_DELAY);\n    SLIST_INIT(&s_te_sld_obj->handle_list);\n    memcpy(s_te_sld_obj->global_config, global_config, sizeof(touch_slider_global_config_t));\n    te_object_methods_t slider_methods = {\n        .handle = s_te_sld_obj,\n        .check_channel = slider_object_check_channel,\n        .set_threshold = slider_object_set_threshold,\n        .process_state = slider_object_process_state,\n        .update_state = slider_object_update_state\n    };\n    te_object_method_register(&slider_methods, TE_CLS_TYPE_SLIDER);\n    xSemaphoreGive(s_te_sld_obj->mutex);\n    return ESP_OK;\n\ncleanup:\n    TE_FREE_AND_NULL(s_te_sld_obj->global_config);\n    if (s_te_sld_obj->mutex != NULL) {\n        vSemaphoreDelete(s_te_sld_obj->mutex);\n    }\n    TE_FREE_AND_NULL(s_te_sld_obj);\n    return ESP_ERR_NO_MEM;\n}\n\nvoid touch_slider_uninstall(void)\n{\n    xSemaphoreTake(s_te_sld_obj->mutex, portMAX_DELAY);\n    if (s_te_sld_obj == NULL) {\n        xSemaphoreGive(s_te_sld_obj->mutex);\n        return;\n    }\n    te_object_method_unregister(TE_CLS_TYPE_SLIDER);\n    free(s_te_sld_obj->global_config);\n    s_te_sld_obj->global_config = NULL;\n    while (!SLIST_EMPTY(&s_te_sld_obj->handle_list)) {\n        SLIST_REMOVE_HEAD(&s_te_sld_obj->handle_list, next);\n    }\n    xSemaphoreGive(s_te_sld_obj->mutex);\n    vSemaphoreDelete(s_te_sld_obj->mutex);\n    free(s_te_sld_obj);\n    s_te_sld_obj = NULL;\n}\n\nesp_err_t touch_slider_create(const touch_slider_config_t *slider_config, touch_slider_handle_t *slider_handle)\n{\n    TE_CHECK(s_te_sld_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(slider_handle != NULL && slider_config != NULL, ESP_ERR_INVALID_ARG);\n    TE_CHECK(slider_config->channel_num > 2 &&\n             slider_config->channel_num < TOUCH_PAD_MAX &&\n             slider_config->channel_array != NULL &&\n             slider_config->sensitivity_array != NULL &&\n             slider_config->position_range > slider_config->channel_num,\n             ESP_ERR_INVALID_ARG);\n    TE_CHECK(te_object_check_channel(slider_config->channel_array, slider_config->channel_num) == false,\n             ESP_ERR_INVALID_ARG);\n    te_slider_handle_t te_slider = (te_slider_handle_t)calloc(1, sizeof(struct te_slider_s));\n    TE_CHECK(te_slider != NULL, ESP_ERR_NO_MEM);\n\n    esp_err_t ret = ESP_ERR_NO_MEM;\n    te_slider->config = (te_slider_handle_config_t *)calloc(1, sizeof(te_slider_handle_config_t));\n    te_slider->pos_filter_window = calloc(TE_SLD_DEFAULT_POS_FILTER_SIZE(s_te_sld_obj), sizeof(uint8_t));\n    te_slider->device = (te_dev_t **)calloc(slider_config->channel_num, sizeof(te_dev_t *));\n    te_slider->channel_bcm = (uint32_t *)calloc(slider_config->channel_num, sizeof(uint32_t));\n    te_slider->quantify_signal_array = (float *)calloc(slider_config->channel_num, sizeof(float));\n    TE_CHECK_GOTO(te_slider->config != NULL &&\n                  te_slider->pos_filter_window != NULL &&\n                  te_slider->device != NULL &&\n                  te_slider->channel_bcm &&\n                  te_slider->quantify_signal_array,\n                  cleanup);\n    for (int idx = 0; idx < slider_config->channel_num; idx++) {\n        te_slider->device[idx] = (te_dev_t *)calloc(1, sizeof(te_dev_t));\n        if (te_slider->device[idx] == NULL) {\n            ret = ESP_ERR_NO_MEM;\n            goto cleanup;\n        }\n    }\n    ret = te_dev_init(te_slider->device, slider_config->channel_num, TOUCH_ELEM_TYPE_SLIDER,\n                      slider_config->channel_array, slider_config->sensitivity_array,\n                      TE_DEFAULT_THRESHOLD_DIVIDER(s_te_sld_obj));\n    TE_CHECK_GOTO(ret == ESP_OK, cleanup);\n\n    te_slider->config->event_mask = TOUCH_ELEM_EVENT_NONE;\n    te_slider->config->dispatch_method = TOUCH_ELEM_DISP_MAX;\n    te_slider->config->callback = NULL;\n    te_slider->config->arg = NULL;\n    te_slider->channel_bcm_update_cnt = TE_SLD_DEFAULT_BCM_UPDATE_TIME(s_te_sld_obj); //update at first time\n    te_slider->filter_reset_cnt = TE_SLD_DEFAULT_FILTER_RESET_TIME(s_te_sld_obj);     //reset at first time\n    te_slider->channel_sum = slider_config->channel_num;\n    te_slider->position_range = slider_config->position_range;\n    te_slider->position_scale = (float)(slider_config->position_range) / (slider_config->channel_num - 1);\n    te_slider->current_state = TE_STATE_IDLE;\n    te_slider->last_state = TE_STATE_IDLE;\n    te_slider->event = TOUCH_SLIDER_EVT_MAX;\n    te_slider->position = 0;\n    te_slider->last_position = 0;\n    te_slider->pos_window_idx = 0;\n    te_slider->is_first_sample = true;\n    ret = slider_object_add_instance(te_slider);\n    TE_CHECK_GOTO(ret == ESP_OK, cleanup);\n    *slider_handle = (touch_elem_handle_t)te_slider;\n    return ESP_OK;\n\ncleanup:\n    TE_FREE_AND_NULL(te_slider->config);\n    TE_FREE_AND_NULL(te_slider->pos_filter_window);\n    TE_FREE_AND_NULL(te_slider->channel_bcm);\n    TE_FREE_AND_NULL(te_slider->quantify_signal_array);\n    if (te_slider->device != NULL) {\n        for (int idx = 0; idx < slider_config->channel_num; idx++) {\n            TE_FREE_AND_NULL(te_slider->device[idx]);\n        }\n        free(te_slider->device);\n        te_slider->device = NULL;\n    }\n    TE_FREE_AND_NULL(te_slider);\n    return ret;\n}\n\nesp_err_t touch_slider_delete(touch_slider_handle_t slider_handle)\n{\n    TE_CHECK(s_te_sld_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(slider_handle != NULL, ESP_ERR_INVALID_ARG);\n    /*< Release touch sensor application resource */\n    esp_err_t ret = slider_object_remove_instance(slider_handle);\n    TE_CHECK(ret == ESP_OK, ret);\n    te_slider_handle_t te_slider = (te_slider_handle_t)slider_handle;\n    /*< Release touch sensor device resource */\n    te_dev_deinit(te_slider->device, te_slider->channel_sum);\n    for (int idx = 0; idx < te_slider->channel_sum; idx++) {\n        free(te_slider->device[idx]);\n    }\n    free(te_slider->config);\n    free(te_slider->quantify_signal_array);\n    free(te_slider->pos_filter_window);\n    free(te_slider->channel_bcm);\n    free(te_slider->device);\n    free(te_slider);\n    return ESP_OK;\n}\n\nesp_err_t touch_slider_set_dispatch_method(touch_slider_handle_t slider_handle, touch_elem_dispatch_t dispatch_method)\n{\n    TE_CHECK(s_te_sld_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(slider_handle != NULL, ESP_ERR_INVALID_ARG);\n    TE_CHECK(dispatch_method >= TOUCH_ELEM_DISP_EVENT && dispatch_method <= TOUCH_ELEM_DISP_MAX, ESP_ERR_INVALID_ARG);\n    xSemaphoreTake(s_te_sld_obj->mutex, portMAX_DELAY);\n    te_slider_handle_t te_slider = (te_slider_handle_t)slider_handle;\n    te_slider->config->dispatch_method = dispatch_method;\n    xSemaphoreGive(s_te_sld_obj->mutex);\n    return ESP_OK;\n}\n\nesp_err_t touch_slider_subscribe_event(touch_slider_handle_t slider_handle, uint32_t event_mask, void *arg)\n{\n    TE_CHECK(s_te_sld_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(slider_handle != NULL, ESP_ERR_INVALID_ARG);\n    if (!(event_mask & TOUCH_ELEM_EVENT_ON_PRESS) && !(event_mask & TOUCH_ELEM_EVENT_ON_RELEASE) &&\n            !(event_mask & TOUCH_ELEM_EVENT_NONE) && !(event_mask & TOUCH_ELEM_EVENT_ON_CALCULATION)) {\n        ESP_LOGE(TE_TAG, \"Touch button only support TOUCH_ELEM_EVENT_ON_PRESS, \"\n                 \"TOUCH_ELEM_EVENT_ON_RELEASE, TOUCH_ELEM_EVENT_ON_CALCULATION event mask\");\n        return ESP_ERR_INVALID_ARG;\n    }\n    xSemaphoreTake(s_te_sld_obj->mutex, portMAX_DELAY);\n    te_slider_handle_t te_slider = (te_slider_handle_t)slider_handle;\n    te_slider->config->event_mask = event_mask;\n    te_slider->config->arg = arg;\n    xSemaphoreGive(s_te_sld_obj->mutex);\n    return ESP_OK;\n}\n\nesp_err_t touch_slider_set_callback(touch_slider_handle_t slider_handle, touch_slider_callback_t slider_callback)\n{\n    TE_CHECK(s_te_sld_obj != NULL, ESP_ERR_INVALID_STATE);\n    TE_CHECK(slider_handle != NULL, ESP_ERR_INVALID_ARG);\n    TE_CHECK(slider_callback != NULL, ESP_ERR_INVALID_ARG);\n    te_slider_handle_t te_slider = (te_slider_handle_t)slider_handle;\n    xSemaphoreTake(s_te_sld_obj->mutex, portMAX_DELAY);\n    te_slider->config->callback = slider_callback;\n    xSemaphoreGive(s_te_sld_obj->mutex);\n    return ESP_OK;\n}\n\nconst touch_slider_message_t *touch_slider_get_message(const touch_elem_message_t *element_message)\n{\n    return (touch_slider_message_t *)&element_message->child_msg;\n    _Static_assert(sizeof(element_message->child_msg) >= sizeof(touch_slider_message_t), \"Message size overflow\");\n}\n\nstatic bool slider_object_check_channel(touch_pad_t channel_num)\n{\n    te_slider_handle_list_t *item;\n    SLIST_FOREACH(item, &s_te_sld_obj->handle_list, next) {\n        if (slider_channel_check(item->slider_handle, channel_num)) {\n            return true;\n        }\n    }\n    return false;\n}\n\nstatic esp_err_t slider_object_set_threshold(void)\n{\n    esp_err_t ret = ESP_OK;\n    te_slider_handle_list_t *item;\n    SLIST_FOREACH(item, &s_te_sld_obj->handle_list, next) {\n        ret = slider_set_threshold(item->slider_handle);\n        if (ret != ESP_OK) {\n            break;\n        }\n    }\n    return ret;\n}\n\n// workaround for compilation error on xtensa-esp32s3-elf-gcc (crosstool-NG esp-2022r1-RC1) 11.2.0 (IDF-5725)\n__attribute__((optimize(\"-Os\")))\nstatic void slider_object_process_state(void)\n{\n    te_slider_handle_list_t *item;\n    SLIST_FOREACH(item, &s_te_sld_obj->handle_list, next) {\n        if (waterproof_check_mask_handle(item->slider_handle)) {\n            slider_reset_state(item->slider_handle);\n            slider_reset_position(item->slider_handle);\n            continue;\n        }\n        slider_proc_state(item->slider_handle);\n    }\n}\n\nstatic void slider_object_update_state(touch_pad_t channel_num, te_state_t channel_state)\n{\n    te_slider_handle_list_t *item;\n    SLIST_FOREACH(item, &s_te_sld_obj->handle_list, next) {\n        if (waterproof_check_mask_handle(item->slider_handle)) {\n            continue;\n        }\n        slider_update_state(item->slider_handle, channel_num, channel_state);\n    }\n}\n\nstatic esp_err_t slider_object_add_instance(te_slider_handle_t slider_handle)\n{\n    te_slider_handle_list_t *item = (te_slider_handle_list_t *)calloc(1, sizeof(te_slider_handle_list_t));\n    TE_CHECK(item != NULL, ESP_ERR_NO_MEM);\n    item->slider_handle = slider_handle;\n    xSemaphoreTake(s_te_sld_obj->mutex, portMAX_DELAY);\n    SLIST_INSERT_HEAD(&s_te_sld_obj->handle_list, item, next);\n    xSemaphoreGive(s_te_sld_obj->mutex);\n    return ESP_OK;\n}\n\nstatic esp_err_t slider_object_remove_instance(te_slider_handle_t slider_handle)\n{\n    esp_err_t ret = ESP_ERR_NOT_FOUND;\n    te_slider_handle_list_t *item;\n    SLIST_FOREACH(item, &s_te_sld_obj->handle_list, next) {\n        if (slider_handle == item->slider_handle) {\n            xSemaphoreTake(s_te_sld_obj->mutex, portMAX_DELAY);\n            SLIST_REMOVE(&s_te_sld_obj->handle_list, item, te_slider_handle_list, next);\n            xSemaphoreGive(s_te_sld_obj->mutex);\n            free(item);\n            ret = ESP_OK;\n            break;\n        }\n    }\n    return ret;\n}\n\nbool is_slider_object_handle(touch_elem_handle_t element_handle)\n{\n    te_slider_handle_list_t *item;\n    xSemaphoreTake(s_te_sld_obj->mutex, portMAX_DELAY);\n    SLIST_FOREACH(item, &s_te_sld_obj->handle_list, next) {\n        if (element_handle == item->slider_handle) {\n            xSemaphoreGive(s_te_sld_obj->mutex);\n            return true;\n        }\n    }\n    xSemaphoreGive(s_te_sld_obj->mutex);\n    return false;\n}\n\nstatic bool slider_channel_check(te_slider_handle_t slider_handle, touch_pad_t channel_num)\n{\n    te_dev_t *device;\n    for (int idx = 0; idx < slider_handle->channel_sum; idx++) {\n        device = slider_handle->device[idx];\n        if (device->channel == channel_num) {\n            return true;\n        }\n    }\n    return false;\n}\n\nstatic esp_err_t slider_set_threshold(te_slider_handle_t slider_handle)\n{\n    esp_err_t ret = ESP_OK;\n    for (int idx = 0; idx < slider_handle->channel_sum; idx++) {\n        ret |= te_dev_set_threshold(slider_handle->device[idx]);\n    }\n    slider_update_benchmark(slider_handle);  //Update benchmark at startup\n    return ret;\n}\n\nstatic void slider_update_benchmark(te_slider_handle_t slider_handle)\n{\n    for (int idx = 0; idx < slider_handle->channel_sum; idx++) {\n        uint32_t bcm_val;\n        te_dev_t *device = slider_handle->device[idx];\n        bcm_val = te_read_smooth_signal(device->channel);\n        slider_handle->channel_bcm[idx] = bcm_val;\n    }\n}\n\nstatic void slider_update_state(te_slider_handle_t slider_handle, touch_pad_t channel_num, te_state_t channel_state)\n{\n    te_dev_t *device;\n    for (int idx = 0; idx < slider_handle->channel_sum; idx++) {\n        device = slider_handle->device[idx];\n        if (channel_num == device->channel) {\n            device->state = channel_state;\n        }\n    }\n}\n\nstatic void slider_reset_state(te_slider_handle_t slider_handle)\n{\n    for (int idx = 0; idx < slider_handle->channel_sum; idx++) {\n        slider_handle->device[idx]->state = TE_STATE_IDLE;\n    }\n    slider_handle->current_state = TE_STATE_IDLE;\n}\n\nstatic void slider_event_give(te_slider_handle_t slider_handle)\n{\n    touch_elem_message_t element_message;\n    touch_slider_message_t slider_message = {\n        .event = slider_handle->event,\n        .position = slider_handle->position\n    };\n    element_message.handle = (touch_elem_handle_t)slider_handle;\n    element_message.element_type = TOUCH_ELEM_TYPE_SLIDER;\n    element_message.arg = slider_handle->config->arg;\n    memcpy(element_message.child_msg, &slider_message, sizeof(slider_message));\n    te_event_give(element_message);\n}\n\nstatic inline void slider_dispatch(te_slider_handle_t slider_handle, touch_elem_dispatch_t dispatch_method)\n{\n    if (dispatch_method == TOUCH_ELEM_DISP_EVENT) {\n        slider_event_give(slider_handle);  //Event queue\n    } else if (dispatch_method == TOUCH_ELEM_DISP_CALLBACK) {\n        touch_slider_message_t slider_info;\n        slider_info.event = slider_handle->event;\n        slider_info.position = slider_handle->position;\n        void *arg = slider_handle->config->arg;\n        slider_handle->config->callback(slider_handle, &slider_info, arg);  //Event callback\n    }\n}\n\nvoid slider_enable_wakeup_calibration(te_slider_handle_t slider_handle, bool en)\n{\n    for (int idx = 0; idx < slider_handle->channel_sum; ++idx) {\n        slider_handle->device[idx]->is_use_last_threshold = !en;\n    }\n}\n\n/**\n * @brief Slider process\n *\n * This function will process the slider state and maintain a slider FSM:\n *              IDLE ----> Press ----> Release ----> IDLE\n *\n * The state transition procedure is as follow:\n *       (channel state ----> slider state)\n *\n * TODO: add state transition diagram\n */\nstatic void slider_proc_state(te_slider_handle_t slider_handle)\n{\n    uint32_t event_mask = slider_handle->config->event_mask;\n    touch_elem_dispatch_t dispatch_method = slider_handle->config->dispatch_method;\n    BaseType_t mux_ret = xSemaphoreTake(s_te_sld_obj->mutex, 0);\n    if (mux_ret != pdPASS) {\n        return;\n    }\n\n    slider_handle->current_state = slider_get_state(slider_handle->device, slider_handle->channel_sum);\n\n    if (slider_handle->current_state == TE_STATE_PRESS) {\n        slider_handle->channel_bcm_update_cnt = 0;  // Reset benchmark update counter\n        slider_update_position(slider_handle);\n        if (slider_handle->last_state == TE_STATE_IDLE) { //IDLE ---> Press = On_Press\n            ESP_LOGD(TE_DEBUG_TAG, \"slider press\");\n            if (event_mask & TOUCH_ELEM_EVENT_ON_PRESS) {\n                slider_handle->event = TOUCH_SLIDER_EVT_ON_PRESS;\n                slider_dispatch(slider_handle, dispatch_method);\n            }\n        } else if (slider_handle->last_state == TE_STATE_PRESS) { //Press ---> Press = On_Calculation\n            ESP_LOGD(TE_DEBUG_TAG, \"slider calculation\");\n            if (event_mask & TOUCH_ELEM_EVENT_ON_CALCULATION) {\n                slider_handle->event = TOUCH_SLIDER_EVT_ON_CALCULATION;\n                slider_dispatch(slider_handle, dispatch_method);\n            }\n        }\n    } else if (slider_handle->current_state == TE_STATE_RELEASE) {\n        if (slider_handle->last_state == TE_STATE_PRESS) { //Press ---> Release = On_Release\n            ESP_LOGD(TE_DEBUG_TAG, \"slider release\");\n            if (event_mask & TOUCH_ELEM_EVENT_ON_RELEASE) {\n                slider_handle->event = TOUCH_SLIDER_EVT_ON_RELEASE;\n                slider_dispatch(slider_handle, dispatch_method);\n            }\n        } else if (slider_handle->last_state == TE_STATE_RELEASE) {  // Release ---> Release = On_IDLE (Not dispatch)\n            slider_reset_state(slider_handle);//Reset the slider state for the next time touch action detection\n        }\n    } else if (slider_handle->current_state == TE_STATE_IDLE) {\n        if (slider_handle->last_state == TE_STATE_RELEASE) { //Release ---> IDLE = On_IDLE (Not dispatch)\n            //Nothing\n        } else if (slider_handle->last_state == TE_STATE_IDLE)  { //IDLE ---> IDLE = Running IDLE (Not dispatch)\n            if (++slider_handle->channel_bcm_update_cnt >= TE_SLD_DEFAULT_BCM_UPDATE_TIME(s_te_sld_obj)) {  //Update channel benchmark\n                slider_handle->channel_bcm_update_cnt = 0;\n                slider_update_benchmark(slider_handle);\n                ESP_LOGD(TE_DEBUG_TAG, \"slider bcm update\");\n            }\n            if (++slider_handle->filter_reset_cnt >= TE_SLD_DEFAULT_FILTER_RESET_TIME(s_te_sld_obj)) {\n                slider_reset_position(slider_handle);  //Reset slider filter so as to speed up next time position calculation\n            }\n        }\n    }\n    slider_handle->last_state = slider_handle->current_state;\n    xSemaphoreGive(s_te_sld_obj->mutex);\n}\n\nstatic inline te_state_t slider_get_state(te_dev_t **device, int device_num)\n{\n    /*< Scan the state of all the slider channel and calculate the number of them if the state is Press*/\n    uint8_t press_cnt = 0;\n    uint8_t idle_cnt = 0;\n    for (int idx = 0; idx < device_num; idx++) {  //Calculate how many channel is pressed\n        if (device[idx]->state == TE_STATE_PRESS) {\n            press_cnt++;\n        } else if (device[idx]->state == TE_STATE_IDLE) {\n            idle_cnt++;\n        }\n    }\n    if (press_cnt > 0) {\n        return TE_STATE_PRESS;\n    } else if (idle_cnt == device_num) {\n        return TE_STATE_IDLE;\n    } else {\n        return TE_STATE_RELEASE;\n    }\n}\n\n/**\n * @brief Slider channel difference-rate re-quantization\n *\n * This function will re-quantifies the touch sensor slider channel difference-rate\n * so as to make the different size of touch pad in PCB has the same difference value\n *\n */\nstatic inline void slider_quantify_signal(te_slider_handle_t slider_handle)\n{\n    float weight_sum = 0;\n    for (int idx = 0; idx < slider_handle->channel_sum; idx++) {\n        te_dev_t *device = slider_handle->device[idx];\n        weight_sum += device->sens;\n        uint32_t current_signal = te_read_smooth_signal(device->channel);\n        int ans = current_signal - slider_handle->channel_bcm[idx];\n        float diff_rate = (float)ans / slider_handle->channel_bcm[idx];\n        slider_handle->quantify_signal_array[idx] = diff_rate / device->sens;\n        if (slider_handle->quantify_signal_array[idx] < TE_SLD_DEFAULT_QTF_THR(s_te_sld_obj)) {\n            slider_handle->quantify_signal_array[idx] = 0;\n        }\n    }\n    for (int idx = 0; idx < slider_handle->channel_sum; idx++) {\n        te_dev_t *device = slider_handle->device[idx];\n        slider_handle->quantify_signal_array[idx] = slider_handle->quantify_signal_array[idx] * weight_sum / device->sens;\n    }\n}\n\n/**\n * @brief Calculate max sum subarray\n *\n * This function will figure out the max sum subarray from the\n * input array, return the max sum and max sum start index\n *\n */\nstatic inline float slider_search_max_subarray(const float *array, int array_size, int *max_array_idx)\n{\n    *max_array_idx = 0;\n    float max_array_sum = 0;\n    float current_array_sum = 0;\n    for (int idx = 0; idx <= (array_size - TE_SLD_DEFAULT_CALCULATE_CHANNEL(s_te_sld_obj)); idx++) {\n        for (int x = idx; x < idx + TE_SLD_DEFAULT_CALCULATE_CHANNEL(s_te_sld_obj); x++) {\n            current_array_sum += array[x];\n        }\n        if (max_array_sum < current_array_sum) {\n            max_array_sum = current_array_sum;\n            *max_array_idx = idx;\n        }\n        current_array_sum = 0;\n    }\n    return max_array_sum;\n}\n\n/**\n * @brief Calculate zero number\n *\n * This function will figure out the number of non-zero items from\n * the subarray\n */\nstatic inline uint8_t slider_get_non_zero_num(const float *array, uint8_t array_idx)\n{\n    uint8_t zero_cnt = 0;\n    for (int idx = array_idx; idx < array_idx + TE_SLD_DEFAULT_CALCULATE_CHANNEL(s_te_sld_obj); idx++) {\n        zero_cnt += (array[idx] > 0) ? 1 : 0;\n    }\n    return zero_cnt;\n}\n\nstatic inline uint32_t slider_calculate_position(te_slider_handle_t slider_handle, int subarray_index, float subarray_sum, int non_zero_num)\n{\n    int range = slider_handle->position_range;\n    int array_size = slider_handle->channel_sum;\n    float scale = slider_handle->position_scale;\n    const float *array = slider_handle->quantify_signal_array;\n    uint32_t position = 0;\n    if (non_zero_num == 0) {\n        position = slider_handle->position;\n    } else if (non_zero_num == 1) {\n        for (int index = subarray_index; index < subarray_index + TE_SLD_DEFAULT_CALCULATE_CHANNEL(s_te_sld_obj); index++) {\n            if (0 != array[index]) {\n                if (index == array_size - 1) {\n                    position = range;\n                } else {\n                    position = (uint32_t)((float)index * scale);\n                }\n                break;\n            }\n        }\n    } else {\n        for (int idx = subarray_index; idx < subarray_index + TE_SLD_DEFAULT_CALCULATE_CHANNEL(s_te_sld_obj); idx++) {\n            position += ((float)idx * array[idx]);\n        }\n        position = position * scale / subarray_sum;\n    }\n    return position;\n}\n\nstatic uint32_t slider_filter_average(te_slider_handle_t slider_handle, uint32_t current_position)\n{\n    uint32_t position_average = 0;\n    if (slider_handle->is_first_sample) {\n        for (int win_idx = 0; win_idx < TE_SLD_DEFAULT_POS_FILTER_SIZE(s_te_sld_obj); win_idx++) {\n            slider_handle->pos_filter_window[win_idx] = current_position;  //Preload filter buffer\n        }\n        slider_handle->is_first_sample = false;\n    } else {\n        slider_handle->pos_filter_window[slider_handle->pos_window_idx++] = current_position; //Moving average filter\n        if (slider_handle->pos_window_idx >= TE_SLD_DEFAULT_POS_FILTER_SIZE(s_te_sld_obj)) {\n            slider_handle->pos_window_idx = 0;\n        }\n    }\n\n    for (int win_idx = 0; win_idx < TE_SLD_DEFAULT_POS_FILTER_SIZE(s_te_sld_obj); win_idx++) { //Moving average filter\n        position_average += slider_handle->pos_filter_window[win_idx];\n    }\n    position_average = (uint32_t)((float)position_average / TE_SLD_DEFAULT_POS_FILTER_SIZE(s_te_sld_obj) + 0.5F);\n    return position_average;\n}\n\nstatic inline uint32_t slider_filter_iir(uint32_t in_now, uint32_t out_last, uint32_t k)\n{\n    if (k == 0) {\n        return in_now;\n    } else {\n        uint32_t out_now = (in_now + (k - 1) * out_last) / k;\n        return out_now;\n    }\n}\n\n/**\n * @brief touch sensor slider position update\n *\n * This function is the core algorithm about touch sensor slider\n * position update, mainly has several steps:\n *      1. Re-quantization\n *      2. Figure out changed channel\n *      3. Calculate position\n *      4. Filter\n *\n */\nstatic void slider_update_position(te_slider_handle_t slider_handle)\n{\n    int max_array_idx = 0;\n    float max_array_sum;\n    uint8_t non_zero_num;\n    uint32_t current_position;\n\n    slider_quantify_signal(slider_handle);\n    max_array_sum = slider_search_max_subarray(slider_handle->quantify_signal_array, slider_handle->channel_sum, &max_array_idx);\n    non_zero_num = slider_get_non_zero_num(slider_handle->quantify_signal_array, max_array_idx);\n    current_position = slider_calculate_position(slider_handle, max_array_idx, max_array_sum, non_zero_num);\n    uint32_t position_average = slider_filter_average(slider_handle, current_position);\n    slider_handle->last_position = slider_handle->last_position == 0 ? (position_average << 4) : slider_handle->last_position;\n    slider_handle->last_position = slider_filter_iir((position_average << 4), slider_handle->last_position, TE_SLD_DEFAULT_POS_FILTER_FACTOR(s_te_sld_obj));\n    slider_handle->position = ((slider_handle->last_position + 8) >> 4);  //(x + 8) >> 4 ---->  (x + 8) / 16 ----> x/16 + 0.5\n}\n\nstatic void slider_reset_position(te_slider_handle_t slider_handle)\n{\n    slider_handle->is_first_sample = true;\n    slider_handle->last_position   = 0;\n    slider_handle->pos_window_idx  = 0;\n}\n"
  },
  {
    "path": "unit-test-app/CMakeLists.txt",
    "content": ""
  },
  {
    "path": "unit-test-app/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "unit-test-app/README.md",
    "content": "# ESP-IDF Legacy Unit-Test-App\n\nOlder version of ESP-IDF, all Unity tests were built using a common app, this project's unit-test-app. ESP-IDF has since migrated to a more modular approach, where each component has its own set of test apps. These test apps are built for the specified sdkconfigs using [idf-build-apps](https://github.com/espressif/idf-build-apps) and running the tests are automated with [pytest-embedded](https://github.com/espressif/pytest-embedded).   \n\nThis component has the unit-test-app as an example, to allow for easy integration by creating a project from it with:\n\n`idf.py create-project-from-example \"espressif/unit-test-app:unit-test-app`\n\nFor instructions on how to use the unit-test-app please see the [example README.md](examples/unit-test-app/README.md).\n"
  },
  {
    "path": "unit-test-app/examples/unit-test-app/CMakeLists.txt",
    "content": "# The following lines of boilerplate have to be in your project's\n# CMakeLists in this exact order for cmake to work correctly\ncmake_minimum_required(VERSION 3.16)\n\nif(EXISTS \"$ENV{IDF_PATH}/tools/test_apps/components\")\n    list(APPEND EXTRA_COMPONENT_DIRS \"$ENV{IDF_PATH}/tools/test_apps/components\")\nelse()\n    # Backwards compatibility for building with older IDF versions\n    list(APPEND EXTRA_COMPONENT_DIRS \"$ENV{IDF_PATH}/tools/unit-test-app/components\")\nendif()\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nproject(unit-test-app)\n"
  },
  {
    "path": "unit-test-app/examples/unit-test-app/README.md",
    "content": "# Unit Test App\n\nThis app can be built with the unit tests for a specific component. Unit tests are in `test` subdirectories of respective components.\n\n# Building Unit Test App\n\n## CMake\n\n* Follow the setup instructions in the top-level esp-idf README.\n* Set IDF_PATH environment variable to point to the path to the esp-idf top-level directory.\n* Change into `unit-test-app` directory\n* `idf.py menuconfig` to configure the Unit Test App.\n* `idf.py -T <component> -T <component> ... build` with `component` set to names of the components to be included in the test app. Or `idf.py -T all build` to build the test app with all the tests for components having `test` subdirectory.\n* Follow the printed instructions to flash, or run `idf.py -p PORT flash`.\n* Unit test have a few preset sdkconfigs. It provides command `idf.py ut-clean-config_name` and `idf.py ut-build-config_name` (where `config_name` is the file name under `unit-test-app/configs` folder) to build with preset configs. For example, you can use `idf.py -T all ut-build-default` to build with config file `unit-test-app/configs/default`. Built binary for this config will be copied to `unit-test-app/output/config_name` folder.\n* You may extract the test cases presented in the built elf file by calling `ElfUnitTestParser.py <your_elf>`.\n\n# Flash Size\n\nThe unit test partition table assumes a 4MB flash size. When testing `-T all`, this additional factory app partition size is required.\n\nIf building unit tests to run on a smaller flash size, edit `partition_table_unit_tests_app.csv` and use `-T <component> <component> ...` or instead of `-T all` tests don't fit in a smaller factory app partition (exact size will depend on configured options).\n\n# Running Unit Tests\n\nThe unit test loader will prompt by showing a menu of available tests to run:\n\n* Type a number to run a single test.\n* `*` to run all tests.\n* `[tagname]` to run tests with \"tag\"\n* `![tagname]` to run tests without \"tag\" (`![ignore]` is very useful as it runs all CI-enabled tests.)\n* `\"test name here\"` to run test with given name\n"
  },
  {
    "path": "unit-test-app/examples/unit-test-app/configs/.gitkeep",
    "content": ""
  },
  {
    "path": "unit-test-app/examples/unit-test-app/idf_ext.py",
    "content": "import copy\nimport glob\nimport os\nimport os.path\nimport re\nimport shutil\n\n\ndef action_extensions(base_actions, project_path=os.getcwd()):\n    \"\"\" Describes extensions for unit tests. This function expects that actions \"all\" and \"reconfigure\" \"\"\"\n\n    PROJECT_NAME = 'unit-test-app'\n\n    # List of unit-test-app configurations.\n    # Each file in configs/ directory defines a configuration. The format is the\n    # same as sdkconfig file. Configuration is applied on top of sdkconfig.defaults\n    # file from the project directory\n    CONFIG_NAMES = os.listdir(os.path.join(project_path, 'configs'))\n\n    # Build (intermediate) and output (artifact) directories\n    BUILDS_DIR = os.path.join(project_path, 'builds')\n    BINARIES_DIR = os.path.join(project_path, 'output')\n\n    def parse_file_to_dict(path, regex):\n        \"\"\"\n        Parse the config file at 'path'\n\n        Returns a dict of name:value.\n        \"\"\"\n        compiled_regex = re.compile(regex)\n        result = {}\n        with open(path) as f:\n            for line in f:\n                m = compiled_regex.match(line)\n                if m:\n                    result[m.group(1)] = m.group(2)\n        return result\n\n    def parse_config(path):\n        \"\"\"\n        Expected format with default regex is \"key=value\"\n        \"\"\"\n\n        return parse_file_to_dict(path, r'^([^=]+)=(.+)$')\n\n    def ut_apply_config(ut_apply_config_name, ctx, args):\n        config_name = re.match(r'ut-apply-config-(.*)', ut_apply_config_name).group(1)\n        # Make sure that define_cache_entry is list\n        args.define_cache_entry = list(args.define_cache_entry)\n        new_cache_values = {}\n        sdkconfig_set = list(filter(lambda s: 'SDKCONFIG=' in s, args.define_cache_entry))\n        sdkconfig_path = os.path.join(args.project_dir, 'sdkconfig')\n\n        if sdkconfig_set:\n            sdkconfig_path = sdkconfig_set[-1].split('=')[1]\n            sdkconfig_path = os.path.abspath(sdkconfig_path)\n\n        try:\n            os.remove(sdkconfig_path)\n        except OSError:\n            pass\n\n        if config_name in CONFIG_NAMES:\n            # Parse the sdkconfig for components to be included/excluded and tests to be run\n            config_path = os.path.join(project_path, 'configs', config_name)\n            config = parse_config(config_path)\n\n            target = config.get('CONFIG_IDF_TARGET', 'esp32').strip(\"'\").strip('\"')\n\n            print('Reconfigure: config %s, target %s' % (config_name, target))\n\n            # Clean up and set idf-target\n            base_actions['actions']['fullclean']['callback']('fullclean', ctx, args)\n\n            new_cache_values['EXCLUDE_COMPONENTS'] = config.get('EXCLUDE_COMPONENTS', \"''\")\n            new_cache_values['TEST_EXCLUDE_COMPONENTS'] = config.get('TEST_EXCLUDE_COMPONENTS', \"''\")\n            new_cache_values['TEST_COMPONENTS'] = config.get('TEST_COMPONENTS', \"''\")\n            new_cache_values['TESTS_ALL'] = int(new_cache_values['TEST_COMPONENTS'] == \"''\")\n            new_cache_values['IDF_TARGET'] = target\n            new_cache_values['SDKCONFIG_DEFAULTS'] = ';'.join([os.path.join(project_path, 'sdkconfig.defaults'), config_path])\n\n            args.define_cache_entry.extend(['%s=%s' % (k, v) for k, v in new_cache_values.items()])\n\n            reconfigure = base_actions['actions']['reconfigure']['callback']\n            reconfigure(None, ctx, args)\n\n    # This target builds the configuration. It does not currently track dependencies,\n    # but is good enough for CI builds if used together with clean-all-configs.\n    # For local builds, use 'apply-config-NAME' target and then use normal 'all'\n    # and 'flash' targets.\n    def ut_build(ut_build_name, ctx, args):\n        # Create a copy of the passed arguments to prevent arg modifications to accrue if\n        # all configs are being built\n        build_args = copy.copy(args)\n\n        config_name = re.match(r'ut-build-(.*)', ut_build_name).group(1)\n\n        if config_name in CONFIG_NAMES:\n            build_args.build_dir = os.path.join(BUILDS_DIR, config_name)\n\n            src = os.path.join(BUILDS_DIR, config_name)\n            dest = os.path.join(BINARIES_DIR, config_name)\n\n            try:\n                os.makedirs(dest)\n            except OSError:\n                pass\n\n            # Build, tweaking paths to sdkconfig and sdkconfig.defaults\n            ut_apply_config('ut-apply-config-' + config_name, ctx, build_args)\n\n            build_target = base_actions['actions']['all']['callback']\n\n            build_target('all', ctx, build_args)\n\n            # Copy artifacts to the output directory\n            shutil.copyfile(\n                os.path.join(build_args.project_dir, 'sdkconfig'),\n                os.path.join(dest, 'sdkconfig'),\n            )\n\n            binaries = [PROJECT_NAME + x for x in ['.elf', '.bin', '.map']]\n\n            for binary in binaries:\n                shutil.copyfile(os.path.join(src, binary), os.path.join(dest, binary))\n\n            try:\n                os.mkdir(os.path.join(dest, 'bootloader'))\n            except OSError:\n                pass\n\n            shutil.copyfile(\n                os.path.join(src, 'bootloader', 'bootloader.bin'),\n                os.path.join(dest, 'bootloader', 'bootloader.bin'),\n            )\n\n            for partition_table in glob.glob(os.path.join(src, 'partition_table', 'partition-table*.bin')):\n                try:\n                    os.mkdir(os.path.join(dest, 'partition_table'))\n                except OSError:\n                    pass\n                shutil.copyfile(\n                    partition_table,\n                    os.path.join(dest, 'partition_table', os.path.basename(partition_table)),\n                )\n\n            shutil.copyfile(\n                os.path.join(src, 'flasher_args.json'),\n                os.path.join(dest, 'flasher_args.json'),\n            )\n\n            binaries = glob.glob(os.path.join(src, '*.bin'))\n            binaries = [os.path.basename(s) for s in binaries]\n\n            for binary in binaries:\n                shutil.copyfile(os.path.join(src, binary), os.path.join(dest, binary))\n\n    def ut_clean(ut_clean_name, ctx, args):\n        config_name = re.match(r'ut-clean-(.*)', ut_clean_name).group(1)\n        if config_name in CONFIG_NAMES:\n            shutil.rmtree(os.path.join(BUILDS_DIR, config_name), ignore_errors=True)\n            shutil.rmtree(os.path.join(BINARIES_DIR, config_name), ignore_errors=True)\n\n    def test_component_callback(ctx, global_args, tasks):\n        \"\"\" Convert the values passed to the -T and -E parameter to corresponding cache entry definitions TESTS_ALL and TEST_COMPONENTS \"\"\"\n        test_components = global_args.test_components\n        test_exclude_components = global_args.test_exclude_components\n\n        cache_entries = {}\n\n        if test_components:\n            if 'all' in test_components:\n                cache_entries['TESTS_ALL'] = 1\n                cache_entries['TEST_COMPONENTS'] = \"''\"\n            else:\n                cache_entries['TESTS_ALL'] = 0\n                cache_entries['TEST_COMPONENTS'] = ' '.join(test_components)\n\n        if test_exclude_components:\n            cache_entries['TEST_EXCLUDE_COMPONENTS'] = ' '.join(test_exclude_components)\n\n        if cache_entries:\n            global_args.define_cache_entry = list(global_args.define_cache_entry)\n            global_args.define_cache_entry.extend(['%s=%s' % (k, v) for k, v in cache_entries.items()])\n\n    # Add global options\n    extensions = {\n        'global_options': [{\n            'names': ['-T', '--test-components'],\n            'help': 'Specify the components to test.',\n            'scope': 'shared',\n            'multiple': True,\n        }, {\n            'names': ['-E', '--test-exclude-components'],\n            'help': 'Specify the components to exclude from testing.',\n            'scope': 'shared',\n            'multiple': True,\n        }],\n        'global_action_callbacks': [test_component_callback],\n        'actions': {},\n    }\n\n    # This generates per-config targets (clean, build, apply-config).\n    build_all_config_deps = []\n    clean_all_config_deps = []\n\n    for config in CONFIG_NAMES:\n        config_build_action_name = 'ut-build-' + config\n        config_clean_action_name = 'ut-clean-' + config\n        config_apply_config_action_name = 'ut-apply-config-' + config\n\n        extensions['actions'][config_build_action_name] = {\n            'callback':\n            ut_build,\n            'help':\n            'Build unit-test-app with configuration provided in configs/NAME. ' +\n            'Build directory will be builds/%s/, ' % config_build_action_name +\n            'output binaries will be under output/%s/' % config_build_action_name,\n        }\n\n        extensions['actions'][config_clean_action_name] = {\n            'callback': ut_clean,\n            'help': 'Remove build and output directories for configuration %s.' % config_clean_action_name,\n        }\n\n        extensions['actions'][config_apply_config_action_name] = {\n            'callback':\n            ut_apply_config,\n            'help':\n            'Generates configuration based on configs/%s in sdkconfig file.' % config_apply_config_action_name +\n            'After this, normal all/flash targets can be used. Useful for development/debugging.',\n        }\n\n        build_all_config_deps.append(config_build_action_name)\n        clean_all_config_deps.append(config_clean_action_name)\n\n    extensions['actions']['ut-build-all-configs'] = {\n        'callback': ut_build,\n        'help': 'Build all configurations defined in configs/ directory.',\n        'dependencies': build_all_config_deps,\n    }\n\n    extensions['actions']['ut-clean-all-configs'] = {\n        'callback': ut_clean,\n        'help': 'Remove build and output directories for all configurations defined in configs/ directory.',\n        'dependencies': clean_all_config_deps,\n    }\n\n    return extensions\n"
  },
  {
    "path": "unit-test-app/examples/unit-test-app/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"app_main.c\"\n                    INCLUDE_DIRS \"\")\n"
  },
  {
    "path": "unit-test-app/examples/unit-test-app/main/app_main.c",
    "content": "#include \"test_utils.h\"\n\nvoid app_main(void)\n{\n    test_main();\n}\n"
  },
  {
    "path": "unit-test-app/examples/unit-test-app/partition_table_unit_test_app.csv",
    "content": "# Special partition table for unit test app\n#\n# Name,     Type, SubType, Offset,   Size, Flags\n# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap\nnvs,        data, nvs,      0xb000,  0x5000\notadata,    data, ota,      0x10000,  0x2000\nphy_init,   data, phy,      0x12000,  0x1000\nfactory,    0,    0,        0x20000, 0x260000\nota_0,      0,    ota_0,    ,        256K\nota_1,      0,    ota_1,    ,        256K\n# flash_test partition used for SPI flash tests, WL FAT tests, and SPIFFS tests\nflash_test, data, fat,      ,        528K\nnvs_key,    data, nvs_keys, ,        0x1000, encrypted\n\n# Note: still 1MB of a 4MB flash left free for some other purpose\n"
  },
  {
    "path": "unit-test-app/examples/unit-test-app/partition_table_unit_test_app_2m.csv",
    "content": "# Special partition table for unit test app\n#\n# Name,     Type, SubType, Offset,   Size, Flags\n# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap\nnvs,        data, nvs,      0xb000,  0x5000\notadata,    data, ota,      0x10000,  0x2000\nphy_init,   data, phy,      0x12000,  0x1000\nfactory,    0,    0,        0x20000, 0x150000\nota_0,      0,    ota_0,    ,        156K\nota_1,      0,    ota_1,    ,        156K\n# flash_test partition used for SPI flash tests, WL FAT tests, and SPIFFS tests\nflash_test, data, fat,      ,        220K\nnvs_key,    data, nvs_keys, ,        0x1000, encrypted\n\n# Note: occupied 1.85MB in the 2MB flash\n"
  },
  {
    "path": "unit-test-app/examples/unit-test-app/partition_table_unit_test_two_ota.csv",
    "content": "# Special partition table for unit test app_update\n# Name,     Type, SubType, Offset,   Size, Flags\nnvs,        data, nvs,     ,        0x4000\notadata,    data, ota,     ,        0x2000\nphy_init,   data, phy,     ,        0x1000\nfactory,    0,    0,       ,        0xB0000\nota_0,      0,    ota_0,   ,        0xB0000\nota_1,      0,    ota_1,   ,        0xB0000\ntest,       0,    test,    ,        0xB0000\n# flash_test partition used for SPI flash tests, WL FAT tests, and SPIFFS tests\nflash_test, data, fat,     ,        528K\n"
  },
  {
    "path": "unit-test-app/examples/unit-test-app/partition_table_unit_test_two_ota_2m.csv",
    "content": "# Special partition table for unit test app_update\n# Name,     Type, SubType, Offset,   Size, Flags\nnvs,        data, nvs,     ,        0x4000\notadata,    data, ota,     ,        0x2000\nphy_init,   data, phy,     ,        0x1000\nfactory,    0,    0,       ,        0x70000\nota_0,      0,    ota_0,   ,        0x70000\nota_1,      0,    ota_1,   ,        0x70000\ntest,       0,    test,    ,        0x70000\n# flash_test partition used for SPI flash tests, WL FAT tests, and SPIFFS tests\nflash_test, data, fat,     ,        128K\n"
  },
  {
    "path": "unit-test-app/examples/unit-test-app/sdkconfig.defaults",
    "content": "CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y\nCONFIG_ESPTOOLPY_FLASHSIZE_4MB=y\nCONFIG_PARTITION_TABLE_CUSTOM=y\nCONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partition_table_unit_test_app.csv\"\nCONFIG_PARTITION_TABLE_FILENAME=\"partition_table_unit_test_app.csv\"\nCONFIG_PARTITION_TABLE_OFFSET=0x8000\nCONFIG_FREERTOS_HZ=1000\nCONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y\nCONFIG_HEAP_POISONING_COMPREHENSIVE=y\nCONFIG_SPI_FLASH_ENABLE_COUNTERS=y\nCONFIG_ESP_TASK_WDT_INIT=n\nCONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS=y\nCONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y\nCONFIG_COMPILER_STACK_CHECK=y\nCONFIG_ADC_DISABLE_DAC=n\nCONFIG_COMPILER_WARN_WRITE_STRINGS=y\nCONFIG_SPI_MASTER_IN_IRAM=y\nCONFIG_EFUSE_VIRTUAL=y\nCONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y\n"
  },
  {
    "path": "unit-test-app/examples/unit-test-app/sdkconfig.defaults.esp32",
    "content": "CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y\nCONFIG_XTAL_FREQ_AUTO=y\nCONFIG_SPI_FLASH_SHARE_SPI1_BUS=y\nCONFIG_SPIRAM_BANKSWITCH_ENABLE=n\n"
  },
  {
    "path": "unit-test-app/examples/unit-test-app/sdkconfig.defaults.esp32c2",
    "content": "CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n\nCONFIG_ESPTOOLPY_FLASHSIZE_2MB=y\nCONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partition_table_unit_test_app_2m.csv\"\nCONFIG_PARTITION_TABLE_FILENAME=\"partition_table_unit_test_app_2m.csv\"\n\n# 2MB partition table has a FAT partition too small for 4k sectors\nCONFIG_WL_SECTOR_SIZE_512=y\n"
  },
  {
    "path": "unit-test-app/examples/unit-test-app/sdkconfig.defaults.esp32c3",
    "content": "CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n\n"
  },
  {
    "path": "unit-test-app/examples/unit-test-app/sdkconfig.defaults.esp32s2",
    "content": "CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y\nCONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n\n"
  },
  {
    "path": "unit-test-app/examples/unit-test-app/sdkconfig.defaults.esp32s3",
    "content": "CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y\nCONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n\n"
  },
  {
    "path": "unit-test-app/examples/unit-test-app/tools/CreateSectionTable.py",
    "content": "# This file is used to process section data generated by `objdump -s`\nimport re\n\n\nclass Section(object):\n    \"\"\"\n    One Section of section table. contains info about section name, address and raw data\n    \"\"\"\n    SECTION_START_PATTERN = re.compile(b'Contents of section (.+?):')\n    DATA_PATTERN = re.compile(b'([0-9a-f]{4,8})')\n\n    def __init__(self, name, start_address, data):\n        self.name = name\n        self.start_address = start_address\n        self.data = data\n\n    def __contains__(self, item):\n        \"\"\" check if the section name and address match this section \"\"\"\n        if (item['section'] == self.name or item['section'] == 'any') \\\n                and (self.start_address <= item['address'] < (self.start_address + len(self.data))):\n            return True\n        else:\n            return False\n\n    def __getitem__(self, item):\n        \"\"\"\n        process slice.\n        convert absolute address to relative address in current section and return slice result\n        \"\"\"\n        if isinstance(item, int):\n            return self.data[item - self.start_address]\n        elif isinstance(item, slice):\n            start = item.start if item.start is None else item.start - self.start_address\n            stop = item.stop if item.stop is None else item.stop - self.start_address\n            return self.data[start:stop]\n        return self.data[item]\n\n    def __str__(self):\n        return '%s [%08x - %08x]' % (self.name, self.start_address, self.start_address + len(self.data))\n\n    __repr__ = __str__\n\n    @classmethod\n    def parse_raw_data(cls, raw_data):\n        \"\"\"\n        process raw data generated by `objdump -s`, create section and return un-processed lines\n        :param raw_data: lines of raw data generated by `objdump -s`\n        :return: one section, un-processed lines\n        \"\"\"\n        name = ''\n        data = ''\n        start_address = 0\n        # first find start line\n        for i, line in enumerate(raw_data):\n            if b'Contents of section ' in line:  # do strcmp first to speed up\n                match = cls.SECTION_START_PATTERN.search(line)\n                if match is not None:\n                    name = match.group(1)\n                    raw_data = raw_data[i + 1:]\n                    break\n        else:\n            # do some error handling\n            raw_data = [b'']  # add a dummy first data line\n\n        def process_data_line(line_to_process):\n            # first remove the ascii part\n            hex_part = line_to_process.split(b'  ')[0]\n            # process rest part\n            data_list = cls.DATA_PATTERN.findall(hex_part)\n            try:\n                _address = int(data_list[0], base=16)\n            except IndexError:\n                _address = -1\n\n            def hex_to_str(hex_data):\n                if len(hex_data) % 2 == 1:\n                    hex_data = b'0' + hex_data  # append zero at the beginning\n                _length = len(hex_data)\n                return ''.join([chr(int(hex_data[_i:_i + 2], base=16))\n                                for _i in range(0, _length, 2)])\n\n            return _address, ''.join([hex_to_str(x) for x in data_list[1:]])\n\n        # handle first line:\n        address, _data = process_data_line(raw_data[0])\n        if address != -1:\n            start_address = address\n            data += _data\n            raw_data = raw_data[1:]\n            for i, line in enumerate(raw_data):\n                address, _data = process_data_line(line)\n                if address == -1:\n                    raw_data = raw_data[i:]\n                    break\n                else:\n                    data += _data\n        else:\n            # do error handling\n            raw_data = []\n\n        section = cls(name, start_address, data) if start_address != -1 else None\n        unprocessed_data = None if len(raw_data) == 0 else raw_data\n        return section, unprocessed_data\n\n\nclass SectionTable(object):\n    \"\"\" elf section table \"\"\"\n\n    def __init__(self, file_name):\n        with open(file_name, 'rb') as f:\n            raw_data = f.readlines()\n        self.table = []\n        while raw_data:\n            section, raw_data = Section.parse_raw_data(raw_data)\n            self.table.append(section)\n\n    def get_unsigned_int(self, section, address, size=4, endian='LE'):\n        \"\"\"\n        get unsigned int from section table\n        :param section: section name; use \"any\" will only match with address\n        :param address: start address\n        :param size: size in bytes\n        :param endian: LE or BE\n        :return: int or None\n        \"\"\"\n        if address % 4 != 0 or size % 4 != 0:\n            print('warning: try to access without 4 bytes aligned')\n        key = {'address': address, 'section': section}\n        for section in self.table:\n            if key in section:\n                tmp = section[address:address + size]\n                value = 0\n                for i in range(size):\n                    if endian == 'LE':\n                        value += ord(tmp[i]) << (i * 8)\n                    elif endian == 'BE':\n                        value += ord(tmp[i]) << ((size - i - 1) * 8)\n                    else:\n                        print('only support LE or BE for parameter endian')\n                        assert False\n                break\n        else:\n            value = None\n        return value\n\n    def get_string(self, section, address):\n        \"\"\"\n        get string ('\\0' terminated) from section table\n        :param section: section name; use \"any\" will only match with address\n        :param address: start address\n        :return: string or None\n        \"\"\"\n        value = None\n        key = {'address': address, 'section': section}\n        for section in self.table:\n            if key in section:\n                value = section[address:]\n                for i, c in enumerate(value):\n                    if c == '\\0':\n                        value = value[:i]\n                        break\n                break\n        return value\n"
  },
  {
    "path": "unit-test-app/examples/unit-test-app/tools/ElfUnitTestParser.py",
    "content": "# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD\n# SPDX-License-Identifier: Apache-2.0\nimport argparse\nimport os\nimport subprocess\nimport sys\nfrom typing import Dict, List\n\nimport yaml\n\ntry:\n    import CreateSectionTable\nexcept ImportError:\n    sys.path.append(os.path.expandvars(os.path.join('$IDF_PATH', 'tools', 'unit-test-app', 'tools')))\n    import CreateSectionTable\n\n\ndef get_target_objdump(idf_target: str) -> str:\n    toolchain_for_target = {\n        'esp32': 'xtensa-esp32-elf-',\n        'esp32s2': 'xtensa-esp32s2-elf-',\n        'esp32s3': 'xtensa-esp32s3-elf-',\n        'esp32c2': 'riscv32-esp-elf-',\n        'esp32c3': 'riscv32-esp-elf-',\n    }\n    return toolchain_for_target.get(idf_target, 'riscv32-esp-elf-') + 'objdump'\n\n\ndef parse_elf_test_cases(elf_file: str, idf_target: str) -> List[Dict]:\n    objdump = get_target_objdump(idf_target)\n\n    try:\n        subprocess.check_output('{} -s {} > section_table.tmp'.format(objdump, elf_file), shell=True)\n        table = CreateSectionTable.SectionTable('section_table.tmp')\n    except subprocess.CalledProcessError:\n        raise Exception('Can\\'t resolve elf file. File not found.')\n    finally:\n        os.remove('section_table.tmp')\n\n    bin_test_cases = []\n    try:\n        subprocess.check_output('{} -t {} | grep test_desc > case_address.tmp'.format(objdump, elf_file),\n                                shell=True)\n\n        with open('case_address.tmp', 'rb') as input_f:\n            for line in input_f:\n                # process symbol table like: \"3ffb4310 l     O .dram0.data\t00000018 test_desc_33$5010\"\n                sections = line.split()\n                test_addr = int(sections[0], 16)\n                section = sections[3]\n\n                name_addr = table.get_unsigned_int(section, test_addr, 4)\n                desc_addr = table.get_unsigned_int(section, test_addr + 4, 4)\n                tc = {\n                    'name': table.get_string('any', name_addr),\n                    'desc': table.get_string('any', desc_addr),\n                    'function_count': table.get_unsigned_int(section, test_addr + 20, 4),\n                }\n                bin_test_cases.append(tc)\n    except subprocess.CalledProcessError:\n        raise Exception('Test cases not found')\n    finally:\n        os.remove('case_address.tmp')\n\n    return bin_test_cases\n\n\nif __name__ == '__main__':\n    parser = argparse.ArgumentParser()\n    parser.add_argument('elf_file', help='Elf file to parse')\n    parser.add_argument('-t', '--idf_target',\n                        type=str, default=os.environ.get('IDF_TARGET', ''),\n                        help='Target of the elf, e.g. esp32s2')\n    parser.add_argument('-o', '--output_file',\n                        type=str, default='elf_test_cases.yml',\n                        help='Target of the elf, e.g. esp32s2')\n    args = parser.parse_args()\n\n    assert args.idf_target\n\n    test_cases = parse_elf_test_cases(args.elf_file, args.idf_target)\n    with open(args.output_file, 'w') as out_file:\n        yaml.dump(test_cases, out_file, default_flow_style=False)\n"
  },
  {
    "path": "unit-test-app/idf_component.yml",
    "content": "version: \"1.0.0\"\ndescription: \"Legacy ESP-IDF unit test app\"\nurl: https://github.com/espressif/idf-extra-components/tree/master/unit-test-app\n"
  },
  {
    "path": "zlib/.build-test-rules.yml",
    "content": ""
  },
  {
    "path": "zlib/CMakeLists.txt",
    "content": "idf_component_register(INCLUDE_DIRS zlib SRC_DIRS zlib)\n\ntarget_compile_options(${COMPONENT_LIB} PRIVATE  -Wno-unused-function)\ntarget_compile_options(${COMPONENT_LIB} PRIVATE  -Wno-implicit-int)\ntarget_compile_options(${COMPONENT_LIB} PRIVATE  -Wno-return-type)\ntarget_compile_options(${COMPONENT_LIB} PRIVATE  -Wno-format-extra-args)\ntarget_compile_options(${COMPONENT_LIB} PRIVATE  -Wno-unused-parameter)\ntarget_compile_options(${COMPONENT_LIB} PRIVATE  -Wno-unused-const-variable)\ntarget_compile_options(${COMPONENT_LIB} PRIVATE  -Wno-implicit-fallthrough)\n\ntarget_compile_definitions(${COMPONENT_LIB} PRIVATE PPM_SUPPORTED)\ntarget_compile_definitions(${COMPONENT_LIB} PRIVATE HAVE_MATH_H)\ntarget_compile_definitions(${COMPONENT_LIB} PRIVATE HAVE_CTYPE_H)\ntarget_compile_definitions(${COMPONENT_LIB} PRIVATE HAVE_UNISTD_H)\ntarget_compile_definitions(${COMPONENT_LIB} PRIVATE HAVE_ERRNO_H)\n\n"
  },
  {
    "path": "zlib/LICENSE",
    "content": "Copyright notice:\n\n (C) 1995-2022 Jean-loup Gailly and Mark Adler\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  Jean-loup Gailly        Mark Adler\n  jloup@gzip.org          madler@alumni.caltech.edu\n"
  },
  {
    "path": "zlib/README.md",
    "content": "# Zlib compression and decompression Library\n\n[![Component Registry](https://components.espressif.com/components/espressif/zlib/badge.svg)](https://components.espressif.com/components/espressif/zlib)\n\nThis is an IDF component for zlib library.\n\nFor usage instructions, please refer to the official documentation: https://www.zlib.net/manual.html\n"
  },
  {
    "path": "zlib/idf_component.yml",
    "content": "version: \"1.3.2\"\ndescription: zlib C library\nurl: https://github.com/espressif/idf-extra-components/tree/master/zlib\nrepository: \"https://github.com/espressif/idf-extra-components.git\"\ndocumentation: \"https://www.zlib.net/manual.html\"\nissues: \"https://github.com/espressif/idf-extra-components/issues\" # URL of the issue tracker\ndependencies:\n  idf: \">=4.4\"\nsbom:\n  manifests:\n    - path: sbom_zlib.yml\n      dest: zlib\n"
  },
  {
    "path": "zlib/sbom_zlib.yml",
    "content": "name: zlib\nversion: 1.3.2\ncpe: cpe:2.3:a:zlib:zlib:{}:*:*:*:*:*:*:*\nsupplier: 'Organization: zlib <http://www.zlib.net/>'\ndescription: A massively spiffy yet delicately unobtrusive compression library\nurl: https://github.com/madler/zlib\nhash: da607da739fa6047df13e66a2af6b8bec7c2a498\n"
  },
  {
    "path": "zlib/test_apps/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\n\ninclude($ENV{IDF_PATH}/tools/cmake/project.cmake)\nset(COMPONENTS main)\nproject(zlib_test)\n"
  },
  {
    "path": "zlib/test_apps/main/CMakeLists.txt",
    "content": "idf_component_register(SRCS \"zlib_test.c\"\n                    INCLUDE_DIRS \".\"\n                    PRIV_REQUIRES unity)\n"
  },
  {
    "path": "zlib/test_apps/main/idf_component.yml",
    "content": "dependencies:\n  espressif/zlib:\n    version: \"*\"\n    override_path: \"../..\"\n"
  },
  {
    "path": "zlib/test_apps/main/zlib_test.c",
    "content": "#include <stdio.h>\n\nvoid app_main(void)\n{\n\n}\n"
  }
]