├── .clang-format ├── .github └── workflows │ ├── github_workflows_issue_comment.yml │ ├── github_workflows_new_issues.yml │ └── github_workflows_new_prs.yml ├── .gitignore ├── .gitlab-ci.yml ├── .gitlab └── ci │ ├── build.yml │ ├── pre_check.yml │ └── rules.yml ├── .pre-commit-config.yaml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── README_CN.md ├── components ├── who_app │ ├── who_detect_app │ │ ├── CMakeLists.txt │ │ ├── who_detect_app.cpp │ │ └── who_detect_app.hpp │ ├── who_qrcode_app │ │ ├── CMakeLists.txt │ │ ├── who_qrcode_app.cpp │ │ └── who_qrcode_app.hpp │ └── who_recognition_app │ │ ├── CMakeLists.txt │ │ ├── Kconfig │ │ ├── who_recognition_app.cpp │ │ └── who_recognition_app.hpp ├── who_detect │ ├── CMakeLists.txt │ ├── who_detect_base.cpp │ ├── who_detect_base.hpp │ ├── who_detect_lcd.cpp │ ├── who_detect_lcd.hpp │ ├── who_detect_term.cpp │ ├── who_detect_term.hpp │ ├── who_detect_utils.cpp │ └── who_detect_utils.hpp ├── who_frame_cap │ ├── CMakeLists.txt │ ├── who_frame_cap.cpp │ ├── who_frame_cap.hpp │ ├── who_publisher.hpp │ └── who_subscriber.hpp ├── who_peripherals │ ├── who_cam │ │ ├── CMakeLists.txt │ │ ├── idf_component.yml │ │ ├── who_cam.hpp │ │ ├── who_cam_base.hpp │ │ ├── who_cam_p4 │ │ │ ├── who_cam_define.hpp │ │ │ ├── who_esp_video.cpp │ │ │ ├── who_esp_video.hpp │ │ │ ├── who_p4_cam.cpp │ │ │ ├── who_p4_cam.hpp │ │ │ ├── who_p4_ppa_cam.cpp │ │ │ └── who_p4_ppa_cam.hpp │ │ └── who_cam_s3 │ │ │ ├── who_cam_define.hpp │ │ │ ├── who_s3_cam.cpp │ │ │ └── who_s3_cam.hpp │ ├── who_lcd │ │ ├── CMakeLists.txt │ │ ├── idf_component.yml │ │ ├── who_lcd.cpp │ │ ├── who_lcd.hpp │ │ ├── who_lvgl_lcd.cpp │ │ ├── who_lvgl_lcd.hpp │ │ └── who_lvgl_utils │ │ │ ├── montserrat_bold_20.c │ │ │ ├── montserrat_bold_26.c │ │ │ ├── who_lvgl_utils.cpp │ │ │ └── who_lvgl_utils.hpp │ └── who_spiflash_fatfs │ │ ├── CMakeLists.txt │ │ ├── Kconfig │ │ ├── who_spiflash_fatfs.cpp │ │ └── who_spiflash_fatfs.hpp ├── who_qrcode │ ├── CMakeLists.txt │ ├── idf_component.yml │ ├── who_qrcode_base.cpp │ ├── who_qrcode_base.hpp │ ├── who_qrcode_lcd.cpp │ ├── who_qrcode_lcd.hpp │ ├── who_qrcode_term.cpp │ └── who_qrcode_term.hpp ├── who_recognition │ ├── CMakeLists.txt │ ├── idf_component.yml │ ├── who_recognition.cpp │ └── who_recognition.hpp └── who_task │ ├── CMakeLists.txt │ ├── who_container.hpp │ ├── who_task.cpp │ ├── who_task.hpp │ ├── who_task_state.cpp │ ├── who_task_state.hpp │ ├── who_yield2idle.cpp │ └── who_yield2idle.hpp ├── default_bin ├── esp-eye │ └── esp-eye-bin-v1.0.0.bin └── esp32-s3-eye │ ├── v2.1 │ ├── esp32-s3-eye-v2.1-firmware-v0.2.0-cn.bin │ └── esp32-s3-eye-v2.1-firmware-v0.2.0-en.bin │ └── v2.2 │ ├── esp32-s3-eye-v2.2-firmware-v0.2.0-cn.bin │ └── esp32-s3-eye-v2.2-firmware-v0.2.0-en.bin ├── docs ├── _static │ ├── get-started │ │ ├── ESP32-S3-EYE-isometric.png │ │ ├── ESP32-S3-EYE-v2-1-camera-ps.png │ │ ├── ESP32-S3-EYE-v2-1-module-ps.png │ │ ├── ESP32-S3-EYE_20210913_V03_SystemBlock.png │ │ ├── ESP32-S3-EYE_3dpcase_btm.STL │ │ ├── ESP32-S3-EYE_3dpcase_top.STL │ │ ├── ESP32-S3-EYE_MB-annotated-photo.png │ │ ├── ESP32-S3-EYE_SUB-annotated-photo.png │ │ ├── S3-eye_banner_photo.png │ │ ├── esp-eye_callout.png │ │ ├── esp32-s3-eye-v2_1-marking.png │ │ ├── esp32-s3-eye-v2_1-resistor.png │ │ ├── esp32-s3-eye-v2_2-marking.png │ │ ├── esp32-s3-eye-v2_2-resistor.png │ │ ├── face_id_enrollment_cn.jpg │ │ ├── face_id_enrollment_en.png │ │ ├── wifi_connection.jpeg │ │ ├── work_flow_cn.jpg │ │ └── work_flow_en.png │ └── source-graphics │ │ ├── ESP32-S3-EYE_20210913_V03_SystemBlock.odg │ │ ├── ESP32-S3-EYE_MB_V2.2 callouts.odg │ │ └── ESP32-S3-EYE_SUB_V1.1_callouts.odg ├── docs.png ├── en │ ├── Camera_connections.md │ └── get-started │ │ ├── ESP-EYE_Getting_Started_Guide.md │ │ └── ESP32-S3-EYE_Getting_Started_Guide.md └── zh_CN │ └── get-started │ ├── ESP-EYE_Getting_Started_Guide.md │ └── ESP32-S3-EYE_Getting_Started_Guide.md ├── examples ├── human_face_detect │ ├── CMakeLists.txt │ ├── dependencies.lock.esp32p4 │ ├── dependencies.lock.esp32s3 │ ├── main │ │ ├── CMakeLists.txt │ │ ├── app_main.cpp │ │ └── idf_component.yml │ ├── partitions.csv │ ├── partitions2.csv │ ├── sdkconfig.defaults │ ├── sdkconfig.defaults.esp32p4 │ └── sdkconfig.defaults.esp32s3 ├── human_face_recognition │ ├── CMakeLists.txt │ ├── README.md │ ├── dependencies.lock.esp32p4 │ ├── dependencies.lock.esp32s3 │ ├── main │ │ ├── CMakeLists.txt │ │ ├── app_main.cpp │ │ └── idf_component.yml │ ├── partitions.csv │ ├── partitions2.csv │ ├── sdkconfig.defaults │ ├── sdkconfig.defaults.esp32p4 │ └── sdkconfig.defaults.esp32s3 ├── pedestrian_detect │ ├── CMakeLists.txt │ ├── dependencies.lock.esp32p4 │ ├── dependencies.lock.esp32s3 │ ├── main │ │ ├── CMakeLists.txt │ │ ├── app_main.cpp │ │ └── idf_component.yml │ ├── partitions.csv │ ├── partitions2.csv │ ├── sdkconfig.defaults │ ├── sdkconfig.defaults.esp32p4 │ └── sdkconfig.defaults.esp32s3 └── qrcode_recognition │ ├── CMakeLists.txt │ ├── dependencies.lock.esp32p4 │ ├── dependencies.lock.esp32s3 │ ├── main │ ├── CMakeLists.txt │ ├── app_main.cpp │ └── idf_component.yml │ ├── partitions.csv │ ├── sdkconfig.defaults │ ├── sdkconfig.defaults.esp32p4 │ └── sdkconfig.defaults.esp32s3 ├── img ├── architecture_cn.drawio.svg ├── architecture_en.drawio.svg ├── esp-who_config.png ├── esp-who_config_camera_config.png ├── esp-who_config_camera_config_custom.png ├── esp-who_config_camera_config_select_pinout.png ├── esp-who_config_wifi_config.png ├── esp_eye_Wechat_cross.jpeg ├── esp_eye_Wechat_list.jpg ├── esp_eye_Wechat_network_configuration.jpg ├── esp_eye_wechat.jpg ├── esp_eye_wechat_qr.jpg └── face_recognition_model_config.png └── tools └── ci ├── build_apps.py ├── check_readme_links.py └── push_to_github.sh /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | BasedOnStyle: LLVM 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlines: Left 9 | AlignOperands: false 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: false 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: InlineOnly 15 | AllowShortIfStatementsOnASingleLine: false 16 | AllowShortLoopsOnASingleLine: true 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: false 20 | AlwaysBreakTemplateDeclarations: true 21 | BinPackArguments: false 22 | BinPackParameters: false 23 | BraceWrapping: 24 | AfterCaseLabel: false 25 | AfterClass: false 26 | AfterControlStatement: false 27 | AfterEnum: false 28 | AfterFunction: true 29 | AfterNamespace: false 30 | AfterObjCDeclaration: false 31 | AfterStruct: false 32 | AfterUnion: false 33 | BeforeCatch: false 34 | BeforeElse: false 35 | IndentBraces: false 36 | SplitEmptyFunction: true 37 | SplitEmptyRecord: true 38 | SplitEmptyNamespace: true 39 | BreakBeforeBinaryOperators: None 40 | BreakBeforeBraces: Custom 41 | BreakBeforeInheritanceComma: false 42 | BreakBeforeTernaryOperators: true 43 | BreakConstructorInitializersBeforeComma: false 44 | BreakConstructorInitializers: AfterColon 45 | BreakAfterJavaFieldAnnotations: false 46 | BreakStringLiterals: true 47 | ColumnLimit: 120 48 | CommentPragmas: '^ IWYU pragma:' 49 | CompactNamespaces: false 50 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 51 | ConstructorInitializerIndentWidth: 4 52 | ContinuationIndentWidth: 4 53 | Cpp11BracedListStyle: true 54 | DerivePointerAlignment: false 55 | DisableFormat: false 56 | ExperimentalAutoDetectBinPacking: false 57 | FixNamespaceComments: true 58 | ForEachMacros: 59 | - foreach 60 | - Q_FOREACH 61 | - BOOST_FOREACH 62 | IncludeCategories: 63 | - Regex: '^<' 64 | Priority: 2 65 | - Regex: '^".*/' 66 | Priority: 5 67 | - Regex: '^"' 68 | Priority: 1 69 | IncludeIsMainRegex: '(Test)?$' 70 | IndentCaseLabels: false 71 | IndentWidth: 4 72 | IndentWrappedFunctionNames: false 73 | JavaScriptQuotes: Leave 74 | JavaScriptWrapImports: true 75 | KeepEmptyLinesAtTheStartOfBlocks: false 76 | MacroBlockBegin: '' 77 | MacroBlockEnd: '' 78 | MaxEmptyLinesToKeep: 1 79 | NamespaceIndentation: None 80 | ObjCBlockIndentWidth: 2 81 | ObjCSpaceAfterProperty: false 82 | ObjCSpaceBeforeProtocolList: true 83 | PenaltyBreakAssignment: 2 84 | PenaltyBreakBeforeFirstCallParameter: 19 85 | PenaltyBreakComment: 300 86 | PenaltyBreakFirstLessLess: 120 87 | PenaltyBreakString: 1000 88 | PenaltyExcessCharacter: 1000000 89 | PenaltyReturnTypeOnItsOwnLine: 1000 90 | PointerAlignment: Right 91 | ReflowComments: true 92 | SortIncludes: true 93 | SortUsingDeclarations: true 94 | SpaceAfterCStyleCast: false 95 | SpaceAfterTemplateKeyword: true 96 | SpaceBeforeAssignmentOperators: true 97 | SpaceBeforeParens: ControlStatements 98 | SpaceInEmptyParentheses: false 99 | SpacesBeforeTrailingComments: 1 100 | SpacesInAngles: false 101 | SpacesInContainerLiterals: true 102 | SpacesInCStyleCastParentheses: false 103 | SpacesInParentheses: false 104 | SpacesInSquareBrackets: false 105 | Standard: Cpp11 106 | TabWidth: 4 107 | UseTab: Never -------------------------------------------------------------------------------- /.github/workflows/github_workflows_issue_comment.yml: -------------------------------------------------------------------------------- 1 | name: Sync issue comments to JIRA 2 | 3 | # This workflow will be triggered when new issue comment is created (including PR comments) 4 | on: issue_comment 5 | 6 | jobs: 7 | sync_issue_comments_to_jira: 8 | name: Sync Issue Comments to Jira 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@master 12 | - name: Sync issue comments to JIRA 13 | uses: espressif/github-actions/sync_issues_to_jira@master 14 | env: 15 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 16 | JIRA_PASS: ${{ secrets.JIRA_PASS }} 17 | JIRA_PROJECT: AIS 18 | JIRA_URL: ${{ secrets.JIRA_URL }} 19 | JIRA_USER: ${{ secrets.JIRA_USER }} 20 | -------------------------------------------------------------------------------- /.github/workflows/github_workflows_new_issues.yml: -------------------------------------------------------------------------------- 1 | name: Sync issues to Jira 2 | 3 | # This workflow will be triggered when a new issue is opened 4 | on: issues 5 | 6 | jobs: 7 | sync_issues_to_jira: 8 | name: Sync issues to Jira 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@master 12 | - name: Sync GitHub issues to Jira project 13 | uses: espressif/github-actions/sync_issues_to_jira@master 14 | env: 15 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 16 | JIRA_PASS: ${{ secrets.JIRA_PASS }} 17 | JIRA_PROJECT: AIS 18 | JIRA_URL: ${{ secrets.JIRA_URL }} 19 | JIRA_USER: ${{ secrets.JIRA_USER }} 20 | -------------------------------------------------------------------------------- /.github/workflows/github_workflows_new_prs.yml: -------------------------------------------------------------------------------- 1 | name: Sync remain PRs to Jira 2 | 3 | # This workflow will be triggered every hour, to sync remaining PRs (i.e. PRs with zero comment) to Jira project 4 | # Note that, PRs can also get synced when new PR comment is created 5 | on: 6 | schedule: 7 | - cron: "0 * * * *" 8 | 9 | jobs: 10 | sync_prs_to_jira: 11 | name: Sync PRs to Jira 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@master 15 | - name: Sync PRs to Jira project 16 | uses: espressif/github-actions/sync_issues_to_jira@master 17 | with: 18 | cron_job: true 19 | env: 20 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 21 | JIRA_PASS: ${{ secrets.JIRA_PASS }} 22 | JIRA_PROJECT: AIS 23 | JIRA_URL: ${{ secrets.JIRA_URL }} 24 | JIRA_USER: ${{ secrets.JIRA_USER }} 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | 3 | sdkconfig 4 | sdkconfig.old 5 | 6 | .vscode/ 7 | 8 | managed_components/ 9 | dependencies.lock 10 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | stages: 2 | - pre_check 3 | - build 4 | 5 | workflow: 6 | rules: 7 | # Disable those non-protected push triggered pipelines 8 | - if: '$CI_COMMIT_REF_NAME != "master" && $CI_COMMIT_BRANCH !~ /^release\/v/ && $CI_COMMIT_TAG !~ /^v\d+\.\d+(\.\d+)?($|-)/ && $CI_PIPELINE_SOURCE == "push"' 9 | when: never 10 | # when running merged result pipelines, it would create a temp commit id. use $CI_MERGE_REQUEST_SOURCE_BRANCH_SHA instead of $CI_COMMIT_SHA. 11 | # Please use PIPELINE_COMMIT_SHA at all places that require a commit sha 12 | - if: $CI_OPEN_MERGE_REQUESTS != null 13 | variables: 14 | PIPELINE_COMMIT_SHA: $CI_MERGE_REQUEST_SOURCE_BRANCH_SHA 15 | - if: $CI_OPEN_MERGE_REQUESTS == null 16 | variables: 17 | PIPELINE_COMMIT_SHA: $CI_COMMIT_SHA 18 | - when: always 19 | 20 | variables: 21 | BATCH_BUILD: "1" 22 | V: "0" 23 | IDF_CI_BUILD: "1" 24 | 25 | include: 26 | - '.gitlab/ci/rules.yml' 27 | - '.gitlab/ci/pre_check.yml' 28 | - '.gitlab/ci/build.yml' 29 | 30 | -------------------------------------------------------------------------------- /.gitlab/ci/build.yml: -------------------------------------------------------------------------------- 1 | .build_template: &build_template 2 | stage: build 3 | tags: ["build", "amd64", "internet"] 4 | image: ${IMAGE} 5 | variables: 6 | # Enable ccache for all build jobs. See configure_ci_environment.sh for more ccache related settings. 7 | IDF_CCACHE_ENABLE: "1" 8 | BATCH_BUILD: "1" 9 | V: "0" 10 | WARNING_STR: "" 11 | artifacts: 12 | when: always 13 | paths: 14 | - "**/build*/*.bin" 15 | # upload to s3 server to save the artifacts size 16 | - "**/build*/*.map" 17 | - "**/build*/*.elf" 18 | - "**/build*/flasher_args.json" 19 | - "**/build*/flash_project_args" 20 | - "**/build*/sdkconfig" 21 | - "**/build*/bootloader/*.bin" 22 | - "**/build*/bootloader/*.elf" 23 | - "**/build*/partition_table/*.bin" 24 | - "**/build*/size.json" 25 | expire_in: 1 week 26 | variables: 27 | IDF_CI_BUILD: "1" 28 | script: 29 | - pip install --upgrade idf-component-manager 30 | - pip install idf_build_apps==2.10.1 31 | - python tools/ci/build_apps.py ${EXAMPLE_DIR} 32 | 33 | build_example_human_face_detect: 34 | extends: 35 | - .build_template 36 | - .rules:build:example_detect 37 | parallel: 38 | matrix: 39 | - IMAGE: [espressif/idf:release-v5.4, espressif/idf:latest] 40 | variables: 41 | EXAMPLE_DIR: examples/human_face_detect 42 | 43 | build_example_human_face_recognition: 44 | extends: 45 | - .build_template 46 | - .rules:build:example_human_face_recognition 47 | parallel: 48 | matrix: 49 | - IMAGE: [espressif/idf:release-v5.4, espressif/idf:latest] 50 | variables: 51 | EXAMPLE_DIR: examples/human_face_recognition 52 | 53 | build_example_pedestrian_detect: 54 | extends: 55 | - .build_template 56 | - .rules:build:example_detect 57 | parallel: 58 | matrix: 59 | - IMAGE: [espressif/idf:release-v5.4, espressif/idf:latest] 60 | variables: 61 | EXAMPLE_DIR: examples/pedestrian_detect 62 | 63 | build_example_qrcode_recognition: 64 | extends: 65 | - .build_template 66 | - .rules:build:example_qrcode_recognition 67 | parallel: 68 | matrix: 69 | - IMAGE: [espressif/idf:release-v5.4, espressif/idf:latest] 70 | variables: 71 | EXAMPLE_DIR: examples/qrcode_recognition -------------------------------------------------------------------------------- /.gitlab/ci/pre_check.yml: -------------------------------------------------------------------------------- 1 | .pre_check_template: 2 | stage: pre_check 3 | image: python:3.9 4 | tags: ["build", "amd64", "internet"] 5 | dependencies: [] 6 | 7 | check_pre_commit: 8 | extends: 9 | - .pre_check_template 10 | before_script: 11 | - pip install pre-commit 12 | script: 13 | - | 14 | # merged results pipelines, by default 15 | if [[ -n $CI_MERGE_REQUEST_SOURCE_BRANCH_SHA ]]; then 16 | MODIFIED_FILES=$(git diff --name-only $CI_MERGE_REQUEST_DIFF_BASE_SHA $CI_MERGE_REQUEST_SOURCE_BRANCH_SHA) 17 | # merge request pipelines, when the mr got conflicts 18 | elif [[ -n $CI_MERGE_REQUEST_DIFF_BASE_SHA ]]; then 19 | MODIFIED_FILES=$(git diff --name-only $CI_MERGE_REQUEST_DIFF_BASE_SHA $CI_COMMIT_SHA) 20 | # other pipelines, like the protected branches pipelines 21 | else 22 | MODIFIED_FILES=$(git diff --name-only $CI_COMMIT_BEFORE_SHA $CI_COMMIT_SHA) 23 | fi 24 | # print the MODIFIED_FILES 25 | echo "MODIFIED_FILES: $MODIFIED_FILES" 26 | - pre-commit install --allow-missing-config -t pre-commit -t commit-msg 27 | - export SKIP=check-copyright # copyrights has been checked in separate job 28 | - pre-commit run --files $MODIFIED_FILES 29 | 30 | check_readme_links: 31 | extends: 32 | - .pre_check_template 33 | - .rules:pre_check:readme 34 | allow_failure: true 35 | script: 36 | - python ${CI_PROJECT_DIR}/tools/ci/check_readme_links.py ${CI_PROJECT_DIR} 37 | -------------------------------------------------------------------------------- /.gitlab/ci/rules.yml: -------------------------------------------------------------------------------- 1 | ############ 2 | # Patterns # 3 | ############ 4 | 5 | .patterns-gitlab-ci: &patterns-gitlab-ci 6 | - ".gitlab/ci/*" 7 | 8 | # components folder 9 | .patterns-components_who_detect_app: &patterns-components_who_detect_app 10 | - "components/who_app/who_detect_app/**/*" 11 | 12 | .patterns-components_who_qrcode_app: &patterns-components_who_qrcode_app 13 | - "components/who_app/who_qrcode_app/**/*" 14 | 15 | .patterns-components_who_recognition_app: &patterns-components_who_recognition_app 16 | - "components/who_app/who_recognition_app/**/*" 17 | 18 | .patterns-components_who_detect: &patterns-components_who_detect 19 | - "components/who_detect/**/*" 20 | 21 | .patterns-components_who_frame_cap: &patterns-components_who_frame_cap 22 | - "components/who_frame_cap/**/*" 23 | 24 | .patterns-components_who_cam: &patterns-components_who_cam 25 | - "components/who_peripherals/who_cam/**/*" 26 | 27 | .patterns-components_who_lcd: &patterns-components_who_lcd 28 | - "components/who_peripherals/who_lcd/**/*" 29 | 30 | .patterns-components_who_spiflash_fatfs: &patterns-components_who_spiflash_fatfs 31 | - "components/who_peripherals/who_spiflash_fatfs/**/*" 32 | 33 | .patterns-components_who_qrcode: &patterns-components_who_qrcode 34 | - "components/who_qrcode/**/*" 35 | 36 | .patterns-components_who_recognition: &patterns-components_who_recognition 37 | - "components/who_recognition/**/*" 38 | 39 | .patterns-components_who_task: &patterns-components_who_task 40 | - "components/who_task/**/*" 41 | 42 | # examples folder 43 | .patterns-example_human_face_detect: &patterns-example_human_face_detect 44 | - "examples/human_face_detect/**/*" 45 | 46 | .patterns-example_human_face_recognition: &patterns-example_human_face_recognition 47 | - "examples/human_face_recognition/**/*" 48 | 49 | .patterns-example_pedestrian_detect: &patterns-example_pedestrian_detect 50 | - "examples/pedestrian_detect/**/*" 51 | 52 | .patterns-example_qrcode_recognition: &patterns-example_qrcode_recognition 53 | - "examples/qrcode_recognition/**/*" 54 | 55 | ############## 56 | # if anchors # 57 | ############## 58 | .if-protected: &if-protected 59 | if: '($CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_BRANCH =~ /^release\/v/ || $CI_COMMIT_TAG =~ /^v\d+\.\d+(\.\d+)?($|-)/)' 60 | 61 | .if-dev-push: &if-dev-push 62 | if: '$CI_COMMIT_REF_NAME != "master" && $CI_COMMIT_BRANCH !~ /^release\/v/ && $CI_COMMIT_TAG !~ /^v\d+\.\d+(\.\d+)?($|-)/ && ($CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "merge_request_event")' 63 | 64 | ################## 65 | # Auto Generated # 66 | ################## 67 | .if-label-build: &if-label-build 68 | if: '$CI_MERGE_REQUEST_LABELS =~ /^(?:[^,\n\r]+,)*build(?:,[^,\n\r]+)*$/i' 69 | 70 | .if-label-pre_check: &if-label-pre_check 71 | if: '$BOT_LABEL_PRE_CHECK || $CI_MERGE_REQUEST_LABELS =~ /^(?:[^,\n\r]+,)*pre_check(?:,[^,\n\r]+)*$/i' 72 | 73 | .patterns-docs_md: &patterns-docs_md 74 | - "**/*.md" 75 | 76 | # rules for examples 77 | .rules:build:example_detect: 78 | rules: 79 | - <<: *if-protected 80 | - <<: *if-label-build 81 | - <<: *if-dev-push 82 | changes: *patterns-components_who_detect_app 83 | - <<: *if-dev-push 84 | changes: *patterns-components_who_detect 85 | - <<: *if-dev-push 86 | changes: *patterns-components_who_frame_cap 87 | - <<: *if-dev-push 88 | changes: *patterns-components_who_cam 89 | - <<: *if-dev-push 90 | changes: *patterns-components_who_lcd 91 | - <<: *if-dev-push 92 | changes: *patterns-components_who_task 93 | - <<: *if-dev-push 94 | changes: *patterns-gitlab-ci 95 | 96 | .rules:build:example_human_face_recognition: 97 | rules: 98 | - <<: *if-protected 99 | - <<: *if-label-build 100 | - <<: *if-dev-push 101 | changes: *patterns-components_who_recognition_app 102 | - <<: *if-dev-push 103 | changes: *patterns-components_who_detect 104 | - <<: *if-dev-push 105 | changes: *patterns-components_who_frame_cap 106 | - <<: *if-dev-push 107 | changes: *patterns-components_who_cam 108 | - <<: *if-dev-push 109 | changes: *patterns-components_who_lcd 110 | - <<: *if-dev-push 111 | changes: *patterns-components_who_spiflash_fatfs 112 | - <<: *if-dev-push 113 | changes: *patterns-components_who_recognition 114 | - <<: *if-dev-push 115 | changes: *patterns-components_who_task 116 | - <<: *if-dev-push 117 | changes: *patterns-gitlab-ci 118 | 119 | .rules:build:example_qrcode_recognition: 120 | rules: 121 | - <<: *if-protected 122 | - <<: *if-label-build 123 | - <<: *if-dev-push 124 | changes: *patterns-components_who_qrcode_app 125 | - <<: *if-dev-push 126 | changes: *patterns-components_who_frame_cap 127 | - <<: *if-dev-push 128 | changes: *patterns-components_who_cam 129 | - <<: *if-dev-push 130 | changes: *patterns-components_who_lcd 131 | - <<: *if-dev-push 132 | changes: *patterns-components_who_qrcode 133 | - <<: *if-dev-push 134 | changes: *patterns-components_who_task 135 | - <<: *if-dev-push 136 | changes: *patterns-gitlab-ci 137 | 138 | .rules:pre_check:readme: 139 | rules: 140 | - <<: *if-protected 141 | - <<: *if-label-pre_check 142 | - <<: *if-dev-push 143 | changes: *patterns-docs_md -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # See https://pre-commit.com for more information 2 | # See https://pre-commit.com/hooks.html for more hooks 3 | 4 | default_stages: [commit] 5 | 6 | repos: 7 | - repo: https://github.com/pre-commit/pre-commit-hooks 8 | rev: v4.6.0 9 | hooks: 10 | - id: trailing-whitespace 11 | types_or: [c, c++] 12 | - id: end-of-file-fixer 13 | types_or: [c, c++] 14 | - id: check-merge-conflict 15 | - id: mixed-line-ending 16 | types_or: [c, c++, text] 17 | args: ['--fix=lf'] 18 | description: Forces to replace line ending by the UNIX 'lf' character 19 | 20 | - repo: https://github.com/psf/black 21 | rev: 24.8.0 22 | hooks: 23 | - id: black 24 | 25 | - repo: https://github.com/pre-commit/mirrors-clang-format 26 | rev: v18.1.8 27 | hooks: 28 | - id: clang-format 29 | types_or: [c++, c, cuda] 30 | args: ['--style=file'] 31 | 32 | 33 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change log for esp-who 2 | 3 | ## 1.0.0 4 | - Feature of deep learning and image 5 | - Basic CNN 6 | - PRELU 7 | - Softmax 8 | - Global pool 9 | - Batch normalization 10 | - Depthwise convolution 11 | - Mobilenet 12 | - Quantization 13 | - Resize 14 | - Crop 15 | - NMS 16 | - Known issues 17 | - Recognition the same person while in different background 18 | 19 | 20 | ## 0.9.1 21 | - Add ip configuration 22 | - Minor bugfix 23 | 24 | ## 0.9.0 25 | Recognition solution for ESP-EYE 26 | - Support speech wake up 27 | - Support enrollment face id in flash 28 | - Bugfix: adjust for AI-Thinker 29 | 30 | ## 0.6.1 31 | Open source face detection and recognition forward process 32 | - Move forward process in the esp-face repository 33 | - Update readme 34 | 35 | ## 0.6.0 36 | Display images via Http 37 | - Add web server for camera and facial recognition 38 | - Add some documents for API reference and guide 39 | 40 | ## 0.5.0 41 | Initial commit, esp-who appear in the world. 42 | - Elementry functions such as image processing and matrix computing 43 | - Face detection 44 | - Face recognition 45 | - Components such as camera 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ESPRESSIF MIT License 2 | 3 | Copyright (c) 2018 4 | 5 | Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case, 6 | it is free of charge, to any person obtaining a copy of this software and associated 7 | documentation files (the "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished 10 | to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or 13 | substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP-WHO [[中文]](./README_CN.md) 2 | 3 | ESP-WHO is an image processing development platform based on Espressif chips. It contains development examples that may be applied in practical applications. 4 | 5 | ## Overview 6 | 7 | ESP-WHO provides examples such as Human Face Detection, Human Face Recognition, Pedestrian Detection etc. You can develop a variety of practical applications based on these examples. ESP-WHO runs on ESP-IDF. [ESP-DL](https://github.com/espressif/esp-dl) provides rich deep learning related interfaces for ESP-WHO, which can be implemented with various peripherals to realize many interesting applications. 8 | 9 | ## What's new 10 | 1. The repository has been fully refactored. It adapts to the new [ESP-DL](https://github.com/espressif/esp-dl) 11 | 2. New chip [ESP32-P4](https://www.espressif.com/en/products/socs/esp32-p4) is now supported. 12 | 3. Camera and the deep learning model now runs asynchronously, which achieves higher fps. 13 | 4. Add [lvgl](https://lvgl.io/)(Light and Versatile Graphics Library) support, feel free to develop your own graphical applications. 14 | 5. New pedestrian detect model is added. 15 | 16 | Some chip such as esp32 and esp32-s2, and examples such as cat face detection, color detection, code recognition is not available in this branch currently, we're still working on them. Old branch can be found here. 17 | [old ESP-WHO branch](https://github.com/espressif/esp-who/tree/release/v1.1.0) 18 | 19 | ## What You Need 20 | 21 | ### Hardware 22 | 23 | We recommend novice developers to use the development boards designed by Espressif. The examples provided by ESP-WHO are developed based on the following Espressif development board, and the corresponding relationships between the development boards and SoC are shown in the table below. 24 | 25 | | Soc | [ESP32-S3](https://www.espressif.com/en/products/socs/esp32-s3) | [ESP32-P4](https://www.espressif.com/en/products/socs/esp32-p4) | 26 | |-------------------|-----------------------------------------------------------------|-----------------------------------------------------------------------------| 27 | | Development Board | [ESP-S3-EYE](https://www.espressif.com/en/products/devkits) | [ESP32-P4-Function-EV-Board](https://www.espressif.com/en/products/devkits) | 28 | 29 | > Using a development board not mentioned in the table above, configure pins assigned to peripherals manually, such as camera, LCD, and buttons. 30 | 31 | ### Software 32 | 33 | #### Get ESP-IDF 34 | 35 | 36 | ESP-WHO runs on [ESP-IDF release/v5.4](https://github.com/espressif/esp-idf/tree/release/v5.4) branch . For details on getting ESP-IDF, please refer to [ESP-IDF Programming Guide](https://idf.espressif.com/). 37 | 38 | #### Get ESP-WHO 39 | 40 | Run the following commands in your terminal to download ESP-WHO: 41 | 42 | ```bash 43 | git clone https://github.com/espressif/esp-who.git 44 | ``` 45 | 46 | ## Run Examples 47 | 48 | All examples of ESP-WHO are stored in [examples](./examples) folder. Structure of this folder is shown below: 49 | 50 | ```bash 51 | ├── examples 52 | │   ├── human_face_detect 53 | │   │   ├── human_face_detect_lcd // high fps diaplay with esp_lcd 54 | │   │   └── human_face_detect_terminal // output in terminal witout lcd 55 | │   ├── human_face_recognition // human face recognition demo with lvgl 56 | │   ├── multiple_detect // run mutiple detect models in the same time. 57 | │   └── pedestrian_detect 58 | │   ├── pedestrian_detect_lcd 59 | │   └── pedestrian_detect_terminal 60 | ``` 61 | 62 | For the development boards mentioned in [Hardware](#Hardware), all examples are available out of the box. To run the examples, you only need to perform [Step 1: Hardware connection](#step-1-hardware-connection), [Step 2: Set the target chip](#step-2-set-the-target-chip) and [Step 4: Launch and monitor](#step-4-launch-and-monitor). 63 | 64 | 65 | ### Step 1: Hardware connection 66 | 67 | If you are using ESP32-P4-Function-EV-Board, please following the user guide [ESP32-P4 user guide](https://docs.espressif.com/projects/esp-dev-kits/zh_CN/latest/esp32p4/esp32-p4-function-ev-board/user_guide.html) to connect the camera and lcd to the development board. 68 | 69 | ### Step 2: Set the target chip 70 | 71 | Open the terminal and go to any folder that stores examples (e.g. examples/human_face_detection). Run the following command to set the target chip: 72 | 73 | ```bash 74 | idf.py set-target [SoC] 75 | ``` 76 | 77 | Replace [SoC] with your target chip, e.g. esp32s3, esp32p4 78 | 79 | 80 | ### Step 3: (Optional) change options in menuconfig 81 | 82 | In addtion to the default configuration, there may be some options in the example that you can modify freely. For more details, read the README.md under the examples. 83 | 84 | ```bash 85 | idf.py menuconfig 86 | ``` 87 | 88 | ### Step 4: Launch and monitor 89 | 90 | Flash the program and launch IDF Monitor: 91 | 92 | ```bash 93 | idf.py flash monitor 94 | ``` 95 | 96 | ## Feedback 97 | 98 | Please submit an [issue](https://github.com/espressif/esp-who/issues) if you find any problems using our products, and we will reply as soon as possible. 99 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # ESP-WHO [[English]](./README.md) 2 | 3 | ESP-WHO 是基于乐鑫芯片的图像处理开发平台,其中包含了实际应用中可能出现的开发示例。 4 | 5 | ## 概述 6 | 7 | ESP-WHO 提供了人脸检测、人脸识别、行人检测等示例。您可以基于这些示例,衍生出丰富的实际应用。ESP-WHO 的运行基于 ESP-IDF。[ESP-DL](https://github.com/espressif/esp-dl) 为 ESP-WHO 提供了丰富的深度学习相关接口,配合各种外设可以实现许多有趣的应用。 8 | 9 | ## 新功能 10 | 1. 该仓库已完全重构。适配新版 [ESP-DL](https://github.com/espressif/esp-dl) 11 | 2. 支持新芯片 [ESP32-P4](https://www.espressif.com/en/products/socs/esp32-p4)。 12 | 3. 摄像头和深度学习模型现在异步执行,可实现更高的帧率。 13 | 4. 添加 [lvgl](https://lvgl.io/)(轻量级多功能图形库) 支持,您可以自由开发自己的图形应用程序。 14 | 5. 添加了新的行人检测模型。 15 | 16 | 某些芯片(如 esp32 和 esp32-s2)以及示例(如猫脸检测、颜色检测、二维码识别)目前不在此分支中,还未适配完成。旧分支可在此处找到。 17 | [老 ESP-WHO 分支](https://github.com/espressif/esp-who/tree/release/v1.1.0) 18 | 19 | ## 准备工作 20 | 21 | ### 硬件准备 22 | 23 | 我们推荐新手开发者使用乐鑫设计的开发板。ESP-WHO 提供的示例基于以下乐鑫开发板开发,开发板与芯片的对应关系如下表所示。 24 | 25 | | 芯片 | [ESP32-S3](https://www.espressif.com/en/products/socs/esp32-s3) | [ESP32-P4](https://www.espressif.com/en/products/socs/esp32-p4) | 26 | |-------------------|---------------------------------------------------|-----------------------------------------------------------------------------------| 27 | | 开发板 | [ESP-S3-EYE](https://www.espressif.com/en/products/devkits) | [ESP32-P4-Function-EV-Board](https://www.espressif.com/en/products/devkits) | 28 | 29 | > 使用上表中未提及的开发板,需要手动修改外设的管脚配置,例如摄像头、LCD 和按键等。 30 | 31 | ### 软件准备 32 | 33 | #### 获取 ESP-IDF 34 | 35 | ESP-WHO 在 [ESP-IDF release/v5.4](https://github.com/espressif/esp-idf/tree/release/v5.4) 分支上运行。有关获取 ESP-IDF 的详细信息,请参阅 [ESP-IDF 编程指南](https://idf.espressif.com/)。 36 | 37 | #### 获取 ESP-WHO 38 | 39 | 在终端中运行以下命令下载 ESP-WHO: 40 | 41 | ```bash 42 | git clone https://github.com/espressif/esp-who.git 43 | ``` 44 | 45 | ## 运行示例 46 | 47 | ESP-WHO 的所有示例都存放在 [examples](./examples) 中。该文件夹架构如下所示: 48 | 49 | ```bash 50 | ├── examples 51 | │   ├── human_face_detect 52 | │   │   ├── human_face_detect_lcd // 使用esp_lcd的高帧率示例 53 | │   │   └── human_face_detect_terminal // 没有lcd的情况下在terminal显示结果 54 | │   ├── human_face_recognition // 使用lvgl的人脸识别示例 55 | │   ├── multiple_detect // 多个检测模型同时运行的示例 56 | │   └── pedestrian_detect 57 | │   ├── pedestrian_detect_lcd 58 | │   └── pedestrian_detect_terminal 59 | ``` 60 | 61 | 对于[硬件准备](#硬件准备)中所提到的开发板,所有示例都是开箱即用的,要运行示例仅需执行[步骤 1:硬件连接](#步骤-1硬件连接), [步骤 2:设置目标芯片](#步骤-2设置目标芯片)和[步骤 4:运行和监视](#步骤-4运行和监视)。 62 | 63 | ### 步骤 1:硬件连接 64 | 65 | 如果您使用的是 ESP32-P4-Function-EV-Board,请按照用户指南[ESP32-P4 用户指南](https://docs.espressif.com/projects/esp-dev-kits/zh_CN/latest/esp32p4/esp32-p4-function-ev-board/user_guide.html)将摄像头和液晶显示屏连接到开发板。 66 | 67 | ### 步骤 2:设置目标芯片 68 | 69 | 打开终端并转到存储示例的任何文件夹(例如 examples/human_face_detection)。运行以下命令设置目标芯片: 70 | 71 | ```bash 72 | idf.py set-target [SoC] 73 | ``` 74 | 75 | 将 [SoC] 替换为您的目标芯片,例如 esp32s3、esp32p4 76 | 77 | ### 步骤 3:(可选)更改 menuconfig 中的选项 78 | 79 | 除了默认配置外,示例中可能还有一些您可以自由修改的选项。有关更多详细信息,请阅读示例下的 README.md。 80 | 81 | ```bash 82 | idf.py menuconfig 83 | ``` 84 | 85 | ### 步骤 4:运行和监视 86 | 87 | 烧录程序,运行 IDF 监视器: 88 | 89 | ```bash 90 | idf.py flash monitor 91 | ``` 92 | 93 | ## 反馈 94 | 95 | 如果在使用中发现任何问题,请提交相关 [issue](https://github.com/espressif/esp-who/issues),我们将尽快予以答复。 96 | -------------------------------------------------------------------------------- /components/who_app/who_detect_app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(src_dirs .) 2 | 3 | set(include_dirs .) 4 | 5 | set(requires who_detect) 6 | 7 | idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires}) -------------------------------------------------------------------------------- /components/who_app/who_detect_app/who_detect_app.cpp: -------------------------------------------------------------------------------- 1 | #include "who_detect_app.hpp" 2 | #include "who_yield2idle.hpp" 3 | 4 | namespace who { 5 | namespace app { 6 | bool WhoDetectAppBase::run() 7 | { 8 | who::WhoYield2Idle::run(); 9 | bool ret = m_frame_cap->run(4096, 2, 0); 10 | return ret & m_detect->run(2560, 2, 1); 11 | } 12 | 13 | WhoDetectAppLCD::WhoDetectAppLCD(const std::vector> &palette) 14 | { 15 | m_frame_cap = new frame_cap::WhoFrameCapLCD("FrameCapLCD"); 16 | m_detect = new detect::WhoDetectLCD(m_frame_cap, "DetectLCD", palette); 17 | add_element(m_frame_cap); 18 | add_element(m_detect); 19 | } 20 | 21 | WhoDetectAppTerm::WhoDetectAppTerm() 22 | { 23 | m_frame_cap = new frame_cap::WhoFrameCap("FrameCap"); 24 | m_detect = new detect::WhoDetectTerm(m_frame_cap, "DetectTerm"); 25 | add_element(m_frame_cap); 26 | add_element(m_detect); 27 | } 28 | 29 | } // namespace app 30 | } // namespace who 31 | -------------------------------------------------------------------------------- /components/who_app/who_detect_app/who_detect_app.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "who_detect_lcd.hpp" 3 | #include "who_detect_term.hpp" 4 | #include "who_frame_cap.hpp" 5 | 6 | namespace who { 7 | namespace app { 8 | class WhoDetectAppBase : public WhoTasks { 9 | public: 10 | void set_cam(cam::WhoCam *cam) { m_frame_cap->set_cam(cam); } 11 | void set_model(dl::detect::Detect *model) { m_detect->set_model(model); } 12 | void set_fps(float fps) { m_detect->set_fps(fps); } 13 | bool run() override; 14 | 15 | protected: 16 | frame_cap::WhoFrameCap *m_frame_cap; 17 | detect::WhoDetectBase *m_detect; 18 | }; 19 | 20 | class WhoDetectAppLCD : public WhoDetectAppBase { 21 | public: 22 | WhoDetectAppLCD(const std::vector> &palette); 23 | void set_lcd(lcd::WhoLCD *lcd) { static_cast(m_frame_cap)->set_lcd(lcd); } 24 | }; 25 | 26 | class WhoDetectAppTerm : public WhoDetectAppBase { 27 | public: 28 | WhoDetectAppTerm(); 29 | }; 30 | } // namespace app 31 | } // namespace who 32 | -------------------------------------------------------------------------------- /components/who_app/who_qrcode_app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(src_dirs .) 2 | 3 | set(include_dirs .) 4 | 5 | set(requires who_qrcode) 6 | 7 | idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires}) -------------------------------------------------------------------------------- /components/who_app/who_qrcode_app/who_qrcode_app.cpp: -------------------------------------------------------------------------------- 1 | #include "who_qrcode_app.hpp" 2 | #include "who_yield2idle.hpp" 3 | 4 | namespace who { 5 | namespace app { 6 | bool WhoQRCodeAppBase::run() 7 | { 8 | who::WhoYield2Idle::run(); 9 | bool ret = m_frame_cap->run(4096, 2, 0); 10 | return ret & m_qrcode->run(25600, 2, 1); 11 | } 12 | 13 | WhoQRCodeAppLCD::WhoQRCodeAppLCD() 14 | { 15 | m_frame_cap = new frame_cap::WhoFrameCapLCD("FrameCapLCD"); 16 | m_qrcode = new qrcode::WhoQRCodeLCD(m_frame_cap, "QRCodeLCD"); 17 | add_element(m_frame_cap); 18 | add_element(m_qrcode); 19 | } 20 | 21 | WhoQRCodeAppTerm::WhoQRCodeAppTerm() 22 | { 23 | m_frame_cap = new frame_cap::WhoFrameCap("FrameCap"); 24 | m_qrcode = new qrcode::WhoQRCodeTerm(m_frame_cap, "QRCodeTerm"); 25 | add_element(m_frame_cap); 26 | add_element(m_qrcode); 27 | } 28 | } // namespace app 29 | } // namespace who 30 | -------------------------------------------------------------------------------- /components/who_app/who_qrcode_app/who_qrcode_app.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "who_frame_cap.hpp" 3 | #include "who_qrcode_lcd.hpp" 4 | #include "who_qrcode_term.hpp" 5 | 6 | namespace who { 7 | namespace app { 8 | class WhoQRCodeAppBase : public WhoTasks { 9 | public: 10 | void set_cam(cam::WhoCam *cam) { m_frame_cap->set_cam(cam); } 11 | bool run() override; 12 | 13 | protected: 14 | frame_cap::WhoFrameCap *m_frame_cap; 15 | qrcode::WhoQRCodeBase *m_qrcode; 16 | }; 17 | 18 | class WhoQRCodeAppLCD : public WhoQRCodeAppBase { 19 | public: 20 | WhoQRCodeAppLCD(); 21 | void set_lcd(lcd::WhoLCD *lcd) { static_cast(m_frame_cap)->set_lcd(lcd); } 22 | }; 23 | 24 | class WhoQRCodeAppTerm : public WhoQRCodeAppBase { 25 | public: 26 | WhoQRCodeAppTerm(); 27 | }; 28 | 29 | } // namespace app 30 | } // namespace who 31 | -------------------------------------------------------------------------------- /components/who_app/who_recognition_app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(src_dirs .) 2 | 3 | set(include_dirs .) 4 | 5 | set(requires who_recognition) 6 | 7 | idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires}) -------------------------------------------------------------------------------- /components/who_app/who_recognition_app/Kconfig: -------------------------------------------------------------------------------- 1 | menu "esp-who: human_face_recognition" 2 | choice DB_FILE_SYSTEM 3 | prompt "database file system" 4 | default DB_FATFS_FLASH 5 | help 6 | fatfs support flash/sdcard. spiffs only support flash. 7 | config DB_FATFS_FLASH 8 | bool "fatfs_flash" 9 | config DB_FATFS_SDCARD 10 | bool "fatfs_sdcard" 11 | config DB_SPIFFS 12 | bool "spiffs" 13 | endchoice 14 | endmenu -------------------------------------------------------------------------------- /components/who_app/who_recognition_app/who_recognition_app.cpp: -------------------------------------------------------------------------------- 1 | #include "who_recognition_app.hpp" 2 | #include "who_yield2idle.hpp" 3 | 4 | namespace who { 5 | namespace app { 6 | WhoRecognitionApp::WhoRecognitionApp() 7 | { 8 | auto detect_model = new HumanFaceDetect(); 9 | auto feat_model = new HumanFaceFeat(); 10 | char db_path[64]; 11 | #if CONFIG_DB_FATFS_FLASH 12 | snprintf(db_path, sizeof(db_path), "%s/face.db", CONFIG_SPIFLASH_MOUNT_POINT); 13 | #elif CONFIG_DB_SPIFFS 14 | snprintf(db_path, sizeof(db_path), "%s/face.db", CONFIG_BSP_SPIFFS_MOUNT_POINT); 15 | #else 16 | snprintf(db_path, sizeof(db_path), "%s/face.db", CONFIG_BSP_SD_MOUNT_POINT); 17 | #endif 18 | auto recognizer = new HumanFaceRecognizer(feat_model, db_path); 19 | m_frame_cap = new frame_cap::WhoFrameCapLCD("FrameCapLCD"); 20 | m_detect = new recognition::WhoDetectLCD(m_frame_cap, detect_model, "DetectLCD", {{255, 0, 0}}); 21 | m_recognition = new recognition::WhoRecognition(m_detect, recognizer, "Recognition"); 22 | add_element(m_frame_cap); 23 | add_element(m_detect); 24 | add_element(m_recognition); 25 | } 26 | 27 | bool WhoRecognitionApp::run() 28 | { 29 | who::WhoYield2Idle::run(); 30 | bool ret = m_frame_cap->run(4096, 2, 0); 31 | ret &= m_detect->run(2560, 2, 1); 32 | ret &= m_recognition->run(3584, 2, 0); 33 | return ret; 34 | } 35 | } // namespace app 36 | } // namespace who 37 | -------------------------------------------------------------------------------- /components/who_app/who_recognition_app/who_recognition_app.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "who_frame_cap.hpp" 3 | #include "who_recognition.hpp" 4 | 5 | namespace who { 6 | namespace app { 7 | class WhoRecognitionApp : public WhoTasks { 8 | public: 9 | WhoRecognitionApp(); 10 | void set_cam(cam::WhoCam *cam) { m_frame_cap->set_cam(cam); } 11 | void set_lcd(lcd::WhoLCD *lcd) { m_frame_cap->set_lcd(lcd); } 12 | bool run() override; 13 | 14 | protected: 15 | frame_cap::WhoFrameCapLCD *m_frame_cap; 16 | recognition::WhoDetectLCD *m_detect; 17 | recognition::WhoRecognition *m_recognition; 18 | }; 19 | } // namespace app 20 | } // namespace who 21 | -------------------------------------------------------------------------------- /components/who_detect/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(include_dirs ".") 2 | 3 | set(src_dirs ".") 4 | 5 | set(requires who_frame_cap) 6 | 7 | idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires}) -------------------------------------------------------------------------------- /components/who_detect/who_detect_base.cpp: -------------------------------------------------------------------------------- 1 | #include "who_detect_base.hpp" 2 | 3 | namespace who { 4 | namespace detect { 5 | void WhoDetectBase::set_fps(float fps) 6 | { 7 | if (fps > 0) { 8 | m_interval = pdMS_TO_TICKS((int)(1000.f / fps)); 9 | } 10 | } 11 | 12 | void WhoDetectBase::detect_loop() 13 | { 14 | TickType_t last_wake_time = xTaskGetTickCount(); 15 | set_and_clear_bits(BLOCKING, RUNNING); 16 | while (true) { 17 | EventBits_t event_bits = 18 | xEventGroupWaitBits(m_event_group, NEW_FRAME | PAUSE | STOP, pdTRUE, pdFALSE, portMAX_DELAY); 19 | if (event_bits & STOP) { 20 | set_and_clear_bits(TERMINATE, BLOCKING); 21 | break; 22 | } else if (event_bits & PAUSE) { 23 | EventBits_t pause_event_bits = 24 | xEventGroupWaitBits(m_event_group, RESUME | STOP, pdTRUE, pdFALSE, portMAX_DELAY); 25 | if (pause_event_bits & STOP) { 26 | set_and_clear_bits(TERMINATE, BLOCKING); 27 | break; 28 | } else { 29 | continue; 30 | } 31 | } 32 | set_and_clear_bits(RUNNING, BLOCKING); 33 | auto fb = m_frame_cap->get_cam()->cam_fb_peek(); 34 | struct timeval timestamp = fb->timestamp; 35 | auto &res = m_detect->run(who::cam::fb2img(fb)); 36 | on_new_detect_result({res, timestamp, fb}); 37 | set_and_clear_bits(BLOCKING, RUNNING); 38 | if (m_interval) { 39 | vTaskDelayUntil(&last_wake_time, m_interval); 40 | } 41 | } 42 | vTaskDelete(NULL); 43 | } 44 | 45 | #if CONFIG_IDF_TARGET_ESP32P4 46 | void WhoDetectBase::ppa_detect_loop() 47 | { 48 | auto ppa_cam = static_cast(m_frame_cap->get_cam()); 49 | float ppa_inv_scale_x = 1.f / ppa_cam->m_ppa_scale_x; 50 | float ppa_inv_scale_y = 1.f / ppa_cam->m_ppa_scale_y; 51 | auto fb = ppa_cam->cam_fb_peek(); 52 | int fb_width = fb->width; 53 | int fb_height = fb->height; 54 | TickType_t last_wake_time = xTaskGetTickCount(); 55 | set_and_clear_bits(BLOCKING, RUNNING); 56 | while (true) { 57 | EventBits_t event_bits = 58 | xEventGroupWaitBits(m_event_group, NEW_FRAME | PAUSE | STOP, pdTRUE, pdFALSE, portMAX_DELAY); 59 | if (event_bits & STOP) { 60 | set_and_clear_bits(TERMINATE, BLOCKING); 61 | break; 62 | } else if (event_bits & PAUSE) { 63 | EventBits_t pause_event_bits = 64 | xEventGroupWaitBits(m_event_group, RESUME | STOP, pdTRUE, pdFALSE, portMAX_DELAY); 65 | if (pause_event_bits & STOP) { 66 | set_and_clear_bits(TERMINATE, BLOCKING); 67 | break; 68 | } else { 69 | continue; 70 | } 71 | } 72 | set_and_clear_bits(RUNNING, BLOCKING); 73 | auto ppa_fb = ppa_cam->ppa_cam_fb_peek(); 74 | struct timeval timestamp = ppa_fb->timestamp; 75 | auto &res = m_detect->run(who::cam::fb2img(ppa_fb)); 76 | for (auto &r : res) { 77 | r.box[0] = r.box[0] * ppa_inv_scale_x; 78 | r.box[1] = r.box[1] * ppa_inv_scale_y; 79 | r.box[2] = r.box[2] * ppa_inv_scale_x; 80 | r.box[3] = r.box[3] * ppa_inv_scale_y; 81 | r.limit_box(fb_width, fb_height); 82 | if (!r.keypoint.empty()) { 83 | assert(r.keypoint.size() == 10); 84 | for (int i = 0; i < 5; i++) { 85 | r.keypoint[2 * i] *= ppa_inv_scale_x; 86 | r.keypoint[2 * i + 1] *= ppa_inv_scale_y; 87 | } 88 | r.limit_keypoint(fb_width, fb_height); 89 | } 90 | } 91 | on_new_detect_result({res, timestamp, ppa_fb}); 92 | set_and_clear_bits(BLOCKING, RUNNING); 93 | if (m_interval) { 94 | vTaskDelayUntil(&last_wake_time, m_interval); 95 | } 96 | } 97 | vTaskDelete(NULL); 98 | } 99 | #endif 100 | 101 | void WhoDetectBase::task() 102 | { 103 | #if CONFIG_IDF_TARGET_ESP32P4 104 | if (m_frame_cap->get_cam()->get_type() == "WhoP4PPACam") { 105 | ppa_detect_loop(); 106 | } else { 107 | detect_loop(); 108 | } 109 | #else 110 | detect_loop(); 111 | #endif 112 | } 113 | 114 | bool WhoDetectBase::run(const configSTACK_DEPTH_TYPE uxStackDepth, UBaseType_t uxPriority, const BaseType_t xCoreID) 115 | { 116 | if (!m_detect) { 117 | ESP_LOGE("WhoDetect", "detect model is nullptr, please call set_model() first."); 118 | return false; 119 | } 120 | return WhoSubscriber::run(uxStackDepth, uxPriority, xCoreID); 121 | } 122 | 123 | bool WhoDetectBase::stop() 124 | { 125 | if (xEventGroupGetBits(m_event_group) & TERMINATE) { 126 | return false; 127 | } 128 | xEventGroupSetBits(m_event_group, STOP); 129 | xTaskAbortDelay(m_task_handle); 130 | xEventGroupWaitBits(m_event_group, TERMINATE, pdFALSE, pdFALSE, portMAX_DELAY); 131 | return true; 132 | } 133 | } // namespace detect 134 | } // namespace who 135 | -------------------------------------------------------------------------------- /components/who_detect/who_detect_base.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "dl_detect_base.hpp" 3 | #include "who_cam_define.hpp" 4 | #include "who_frame_cap.hpp" 5 | #include "who_subscriber.hpp" 6 | #include 7 | 8 | namespace who { 9 | namespace detect { 10 | class WhoDetectBase : public WhoSubscriber { 11 | public: 12 | typedef struct { 13 | std::list det_res; 14 | struct timeval timestamp; 15 | who::cam::cam_fb_t *fb; 16 | } result_t; 17 | 18 | WhoDetectBase(frame_cap::WhoFrameCap *frame_cap, const std::string &name) : WhoDetectBase(frame_cap, nullptr, name) 19 | { 20 | } 21 | 22 | WhoDetectBase(frame_cap::WhoFrameCap *frame_cap, dl::detect::Detect *detect, const std::string &name) : 23 | WhoSubscriber(name), m_frame_cap(frame_cap), m_detect(detect), m_interval(0) 24 | { 25 | frame_cap->add_element(this); 26 | } 27 | void set_model(dl::detect::Detect *model) { m_detect = model; } 28 | void set_fps(float fps); 29 | bool run(const configSTACK_DEPTH_TYPE uxStackDepth, UBaseType_t uxPriority, const BaseType_t xCoreID) override; 30 | bool stop() override; 31 | 32 | protected: 33 | frame_cap::WhoFrameCap *m_frame_cap; 34 | 35 | private: 36 | void detect_loop(); 37 | #if CONFIG_IDF_TARGET_ESP32P4 38 | void ppa_detect_loop(); 39 | #endif 40 | void task() override; 41 | virtual void on_new_detect_result(const result_t &result) = 0; 42 | dl::detect::Detect *m_detect; 43 | TickType_t m_interval; 44 | }; 45 | } // namespace detect 46 | } // namespace who 47 | -------------------------------------------------------------------------------- /components/who_detect/who_detect_lcd.cpp: -------------------------------------------------------------------------------- 1 | #include "who_detect_lcd.hpp" 2 | #include "who_detect_utils.hpp" 3 | 4 | namespace who { 5 | namespace detect { 6 | WhoDetectLCD::WhoDetectLCD(frame_cap::WhoFrameCap *frame_cap, 7 | dl::detect::Detect *detect, 8 | const std::string &name, 9 | const std::vector> &palette) : 10 | WhoDetectBase(frame_cap, detect, name), m_res_mutex(xSemaphoreCreateMutex()) 11 | { 12 | #if BSP_CONFIG_NO_GRAPHIC_LIB 13 | m_palette = palette; 14 | #else 15 | m_palette = cvt_to_lv_palette(palette); 16 | #endif 17 | } 18 | 19 | WhoDetectLCD::~WhoDetectLCD() 20 | { 21 | vSemaphoreDelete(m_res_mutex); 22 | } 23 | 24 | void WhoDetectLCD::on_new_detect_result(const result_t &result) 25 | { 26 | xSemaphoreTake(m_res_mutex, portMAX_DELAY); 27 | m_results.push(result); 28 | xSemaphoreGive(m_res_mutex); 29 | } 30 | 31 | void WhoDetectLCD::lcd_display_cb(who::cam::cam_fb_t *fb) 32 | { 33 | xSemaphoreTake(m_res_mutex, portMAX_DELAY); 34 | // Try to sync camera frame and result, skip the future result. 35 | auto compare_timestamp = [](const struct timeval &t1, const struct timeval &t2) -> bool { 36 | if (t1.tv_sec == t2.tv_sec) { 37 | return t1.tv_usec < t2.tv_usec; 38 | } 39 | return t1.tv_sec < t2.tv_sec; 40 | }; 41 | struct timeval t1 = fb->timestamp; 42 | if (!m_results.empty()) { 43 | result_t result = m_results.front(); 44 | if (!compare_timestamp(t1, result.timestamp)) { 45 | m_result = result; 46 | m_results.pop(); 47 | } 48 | } 49 | xSemaphoreGive(m_res_mutex); 50 | 51 | #if BSP_CONFIG_NO_GRAPHIC_LIB 52 | draw_detect_results_on_fb(fb, m_result.det_res, m_palette); 53 | #else 54 | draw_detect_results_on_canvas( 55 | static_cast(m_frame_cap)->get_lcd()->get_canvas(), m_result.det_res, m_palette); 56 | #endif 57 | } 58 | } // namespace detect 59 | } // namespace who 60 | -------------------------------------------------------------------------------- /components/who_detect/who_detect_lcd.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "who_detect_base.hpp" 3 | #include "bsp/config.h" 4 | #if !BSP_CONFIG_NO_GRAPHIC_LIB 5 | #include "lvgl.h" 6 | #endif 7 | #include 8 | 9 | namespace who { 10 | namespace detect { 11 | class WhoDetectLCD : public WhoDetectBase { 12 | public: 13 | WhoDetectLCD(frame_cap::WhoFrameCap *frame_cap, 14 | dl::detect::Detect *detect, 15 | const std::string &name, 16 | const std::vector> &palette); 17 | WhoDetectLCD(frame_cap::WhoFrameCap *frame_cap, 18 | const std::string &name, 19 | const std::vector> &palette) : 20 | WhoDetectLCD(frame_cap, nullptr, name, palette) 21 | { 22 | } 23 | ~WhoDetectLCD(); 24 | void lcd_display_cb(who::cam::cam_fb_t *fb) override; 25 | 26 | protected: 27 | void on_new_detect_result(const result_t &result) override; 28 | 29 | private: 30 | #if BSP_CONFIG_NO_GRAPHIC_LIB 31 | std::vector> m_palette; 32 | #else 33 | std::vector m_palette; 34 | #endif 35 | SemaphoreHandle_t m_res_mutex; 36 | 37 | std::queue m_results; 38 | result_t m_result; 39 | }; 40 | 41 | } // namespace detect 42 | } // namespace who 43 | -------------------------------------------------------------------------------- /components/who_detect/who_detect_term.cpp: -------------------------------------------------------------------------------- 1 | #include "who_detect_term.hpp" 2 | #include "who_detect_utils.hpp" 3 | 4 | namespace who { 5 | namespace detect { 6 | void WhoDetectTerm::on_new_detect_result(const result_t &result) 7 | { 8 | print_detect_results(result.det_res); 9 | } 10 | } // namespace detect 11 | } // namespace who 12 | -------------------------------------------------------------------------------- /components/who_detect/who_detect_term.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "who_detect_base.hpp" 3 | 4 | namespace who { 5 | namespace detect { 6 | class WhoDetectTerm : public WhoDetectBase { 7 | public: 8 | using WhoDetectBase::WhoDetectBase; 9 | 10 | private: 11 | void on_new_detect_result(const result_t &result) override; 12 | }; 13 | } // namespace detect 14 | } // namespace who 15 | -------------------------------------------------------------------------------- /components/who_detect/who_detect_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "who_detect_utils.hpp" 2 | 3 | static const char *TAG = "WhoDetect"; 4 | 5 | namespace who { 6 | namespace detect { 7 | 8 | void draw_detect_results_on_fb(who::cam::cam_fb_t *fb, 9 | const std::list &detect_res, 10 | const std::vector> &palette) 11 | { 12 | #if CONFIG_IDF_TARGET_ESP32P4 13 | uint32_t caps = DL_IMAGE_CAP_RGB565_BIG_ENDIAN; 14 | #else 15 | uint32_t caps = 0; 16 | #endif 17 | dl::image::img_t img = who::cam::fb2img(fb); 18 | for (const auto &res : detect_res) { 19 | dl::image::draw_hollow_rectangle( 20 | img, res.box[0], res.box[1], res.box[2], res.box[3], palette[res.category], 2, caps); 21 | if (!res.keypoint.empty()) { 22 | assert(res.keypoint.size() == 10); 23 | for (int i = 0; i < 5; i++) { 24 | dl::image::draw_point( 25 | img, res.keypoint[2 * i], res.keypoint[2 * i + 1], palette[res.category], 5, caps); 26 | } 27 | } 28 | } 29 | } 30 | 31 | #if !BSP_CONFIG_NO_GRAPHIC_LIB 32 | void draw_detect_results_on_canvas(lv_obj_t *canvas, 33 | const std::list &detect_res, 34 | const std::vector &palette) 35 | { 36 | lv_draw_rect_dsc_t rect_dsc; 37 | lv_draw_rect_dsc_init(&rect_dsc); 38 | rect_dsc.bg_opa = LV_OPA_TRANSP; 39 | rect_dsc.border_width = 2; 40 | 41 | lv_draw_arc_dsc_t arc_dsc; 42 | lv_draw_arc_dsc_init(&arc_dsc); 43 | arc_dsc.width = 5; 44 | arc_dsc.radius = 5; 45 | arc_dsc.start_angle = 0; 46 | arc_dsc.end_angle = 360; 47 | 48 | lv_layer_t layer; 49 | lv_canvas_init_layer(canvas, &layer); 50 | lv_area_t coords_rect; 51 | for (const auto &res : detect_res) { 52 | coords_rect = {res.box[0], res.box[1], res.box[2], res.box[3]}; 53 | rect_dsc.border_color = palette[res.category]; 54 | lv_draw_rect(&layer, &rect_dsc, &coords_rect); 55 | if (!res.keypoint.empty()) { 56 | arc_dsc.color = palette[res.category]; 57 | assert(res.keypoint.size() == 10); 58 | for (int i = 0; i < 5; i++) { 59 | arc_dsc.center.x = res.keypoint[2 * i]; 60 | arc_dsc.center.y = res.keypoint[2 * i + 1]; 61 | lv_draw_arc(&layer, &arc_dsc); 62 | } 63 | } 64 | } 65 | lv_canvas_finish_layer(canvas, &layer); 66 | } 67 | #endif 68 | 69 | void print_detect_results(const std::list &detect_res) 70 | { 71 | int i = 0; 72 | if (!detect_res.empty()) { 73 | if (detect_res.begin()->keypoint.empty()) { 74 | ESP_LOGI(TAG, "----------------------------------------"); 75 | } else { 76 | ESP_LOGI( 77 | TAG, 78 | "---------------------------------------------------------------------------------------------------" 79 | "---------------------------------------------------"); 80 | } 81 | } 82 | for (const auto &r : detect_res) { 83 | if (r.keypoint.empty()) { 84 | ESP_LOGI(TAG, "%d, bbox: [%f, %d, %d, %d, %d]", i, r.score, r.box[0], r.box[1], r.box[2], r.box[3]); 85 | } else { 86 | assert(r.keypoint.size() == 10); 87 | ESP_LOGI(TAG, 88 | "%d, bbox: [%f, %d, %d, %d, %d], left_eye: [%d, %d], left_mouth: [%d, %d], nose: [%d, %d], " 89 | "right_eye: [%d, %d], right_mouth: [%d, %d]", 90 | i, 91 | r.score, 92 | r.box[0], 93 | r.box[1], 94 | r.box[2], 95 | r.box[3], 96 | r.keypoint[0], 97 | r.keypoint[1], 98 | r.keypoint[2], 99 | r.keypoint[3], 100 | r.keypoint[4], 101 | r.keypoint[5], 102 | r.keypoint[6], 103 | r.keypoint[7], 104 | r.keypoint[8], 105 | r.keypoint[9]); 106 | } 107 | i++; 108 | } 109 | } 110 | 111 | } // namespace detect 112 | } // namespace who 113 | -------------------------------------------------------------------------------- /components/who_detect/who_detect_utils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "dl_detect_define.hpp" 3 | #include "who_cam_define.hpp" 4 | #include 5 | #include "bsp/config.h" 6 | #if !BSP_CONFIG_NO_GRAPHIC_LIB 7 | #include "who_lvgl_utils.hpp" 8 | #endif 9 | 10 | namespace who { 11 | namespace detect { 12 | 13 | void draw_detect_results_on_fb(who::cam::cam_fb_t *fb, 14 | const std::list &detect_res, 15 | const std::vector> &palette); 16 | 17 | #if !BSP_CONFIG_NO_GRAPHIC_LIB 18 | void draw_detect_results_on_canvas(lv_obj_t *canvas, 19 | const std::list &detect_res, 20 | const std::vector &palette); 21 | #endif 22 | 23 | void print_detect_results(const std::list &detect_res); 24 | 25 | } // namespace detect 26 | } // namespace who 27 | -------------------------------------------------------------------------------- /components/who_frame_cap/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(src_dirs .) 2 | 3 | set(include_dirs .) 4 | 5 | set(requires who_task 6 | who_cam 7 | who_lcd) 8 | 9 | idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires}) -------------------------------------------------------------------------------- /components/who_frame_cap/who_frame_cap.cpp: -------------------------------------------------------------------------------- 1 | #include "who_frame_cap.hpp" 2 | #include "esp_lcd_panel_ops.h" 3 | #include "who_lcd.hpp" 4 | #include "who_subscriber.hpp" 5 | #include "bsp/config.h" 6 | 7 | static const char *TAG = "WhoFrameCap"; 8 | 9 | namespace who { 10 | namespace frame_cap { 11 | void WhoFrameCap::task() 12 | { 13 | while (true) { 14 | EventBits_t event_bits = xEventGroupGetBits(m_event_group); 15 | if (event_bits & STOP) { 16 | set_and_clear_bits(TERMINATE, RUNNING | STOP); 17 | break; 18 | } else if (event_bits & PAUSE) { 19 | set_and_clear_bits(BLOCKING, RUNNING | PAUSE); 20 | EventBits_t pause_event_bits = 21 | xEventGroupWaitBits(m_event_group, RESUME | STOP, pdTRUE, pdFALSE, portMAX_DELAY); 22 | if (pause_event_bits & STOP) { 23 | set_and_clear_bits(TERMINATE, BLOCKING); 24 | break; 25 | } else { 26 | set_and_clear_bits(RUNNING, BLOCKING); 27 | m_cam->cam_fb_get(); 28 | m_cam->cam_fb_return(); 29 | } 30 | } 31 | m_cam->cam_fb_get(); 32 | on_new_frame(); 33 | m_cam->cam_fb_return(); 34 | } 35 | vTaskDelete(NULL); 36 | } 37 | 38 | void WhoFrameCap::fill_cam_queue() 39 | { 40 | #if CONFIG_IDF_TARGET_ESP32P4 41 | int n = m_cam->m_fb_count - 2; 42 | #elif CONFIG_IDF_TARGET_ESP32S3 43 | int n = m_cam->m_fb_count - 1; 44 | #endif 45 | for (int i = 0; i < n; i++) { 46 | m_cam->cam_fb_get(); 47 | } 48 | } 49 | 50 | bool WhoFrameCap::run(const configSTACK_DEPTH_TYPE uxStackDepth, UBaseType_t uxPriority, const BaseType_t xCoreID) 51 | { 52 | if (!m_cam) { 53 | ESP_LOGE(TAG, "Cam is nullptr, please call set_cam() first."); 54 | return false; 55 | } 56 | return WhoPublisher::run(uxStackDepth, uxPriority, xCoreID); 57 | } 58 | 59 | void WhoFrameCap::set_new_frame_bits() 60 | { 61 | for (const auto &subscriber : m_elements) { 62 | EventGroupHandle_t event_group = subscriber->get_event_group(); 63 | EventBits_t event_bits = xEventGroupGetBits(event_group); 64 | if (!(event_bits & TERMINATE) && !(event_bits & PAUSE)) { 65 | xEventGroupSetBits(event_group, NEW_FRAME); 66 | } 67 | } 68 | } 69 | 70 | void WhoFrameCap::on_new_frame() 71 | { 72 | set_new_frame_bits(); 73 | } 74 | 75 | bool WhoFrameCapLCD::run(const configSTACK_DEPTH_TYPE uxStackDepth, UBaseType_t uxPriority, const BaseType_t xCoreID) 76 | { 77 | if (!m_lcd) { 78 | ESP_LOGE(TAG, "LCD is nullptr, please call set_lcd() first."); 79 | return false; 80 | } 81 | if (xEventGroupGetBits(m_event_group) & (RUNNING | BLOCKING)) { 82 | return false; 83 | } 84 | #if !BSP_CONFIG_NO_GRAPHIC_LIB 85 | m_lcd->create_canvas(); 86 | #endif 87 | return WhoFrameCap::run(uxStackDepth, uxPriority, xCoreID); 88 | } 89 | 90 | void WhoFrameCapLCD::run_lcd_display_cbs(who::cam::cam_fb_t *fb) 91 | { 92 | for (const auto &subscriber : m_elements) { 93 | EventBits_t event_bits = xEventGroupGetBits(subscriber->get_event_group()); 94 | if (!(event_bits & TERMINATE) && !(event_bits & PAUSE)) { 95 | subscriber->lcd_display_cb(fb); 96 | } 97 | } 98 | } 99 | 100 | void WhoFrameCapLCD::on_new_frame() 101 | { 102 | set_new_frame_bits(); 103 | auto fb = m_cam->cam_fb_peek(m_display_back_frame); 104 | #if BSP_CONFIG_NO_GRAPHIC_LIB 105 | run_lcd_display_cbs(fb); 106 | m_lcd->draw_full_lcd(fb->buf); 107 | #else 108 | bsp_display_lock(0); 109 | lv_canvas_set_buffer(m_lcd->get_canvas(), fb->buf, fb->width, fb->height, LV_COLOR_FORMAT_NATIVE); 110 | run_lcd_display_cbs(fb); 111 | bsp_display_unlock(); 112 | #endif 113 | } 114 | } // namespace frame_cap 115 | } // namespace who 116 | -------------------------------------------------------------------------------- /components/who_frame_cap/who_frame_cap.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "who_cam.hpp" 3 | #include "who_lcd.hpp" 4 | #include "who_publisher.hpp" 5 | 6 | namespace who { 7 | namespace frame_cap { 8 | class WhoFrameCap : public WhoPublisher { 9 | public: 10 | WhoFrameCap(const std::string &name) : WhoFrameCap(nullptr, name) {} 11 | WhoFrameCap(who::cam::WhoCam *cam, const std::string &name) : WhoPublisher(name), m_cam(cam) 12 | { 13 | if (cam) { 14 | fill_cam_queue(); 15 | } 16 | } 17 | void set_cam(who::cam::WhoCam *cam) 18 | { 19 | m_cam = cam; 20 | fill_cam_queue(); 21 | } 22 | who::cam::WhoCam *get_cam() { return m_cam; } 23 | bool run(const configSTACK_DEPTH_TYPE uxStackDepth, UBaseType_t uxPriority, const BaseType_t xCoreID) override; 24 | 25 | protected: 26 | void set_new_frame_bits(); 27 | who::cam::WhoCam *m_cam; 28 | 29 | private: 30 | void task() override; 31 | void fill_cam_queue(); 32 | virtual void on_new_frame(); 33 | }; 34 | 35 | class WhoFrameCapLCD : public WhoFrameCap { 36 | public: 37 | WhoFrameCapLCD(const std::string &name, bool display_back_frame = false) : 38 | WhoFrameCapLCD(nullptr, nullptr, name, display_back_frame) 39 | { 40 | } 41 | WhoFrameCapLCD(who::cam::WhoCam *cam, 42 | who::lcd::WhoLCD *lcd, 43 | const std::string &name, 44 | bool display_back_frame = false) : 45 | WhoFrameCap(cam, name), m_lcd(lcd), m_display_back_frame(display_back_frame) 46 | { 47 | } 48 | void set_lcd(who::lcd::WhoLCD *lcd) { m_lcd = lcd; } 49 | who::lcd::WhoLCD *get_lcd() { return m_lcd; } 50 | bool run(const configSTACK_DEPTH_TYPE uxStackDepth, UBaseType_t uxPriority, const BaseType_t xCoreID) override; 51 | 52 | private: 53 | void run_lcd_display_cbs(who::cam::cam_fb_t *fb); 54 | void on_new_frame() override; 55 | who::lcd::WhoLCD *m_lcd; 56 | bool m_display_back_frame; 57 | }; 58 | } // namespace frame_cap 59 | } // namespace who 60 | -------------------------------------------------------------------------------- /components/who_frame_cap/who_publisher.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "who_task.hpp" 3 | 4 | namespace who { 5 | class WhoSubscriber; 6 | class WhoPublisher : public WhoTask, public WhoContainer { 7 | public: 8 | using WhoTask::WhoTask; 9 | }; 10 | } // namespace who 11 | -------------------------------------------------------------------------------- /components/who_frame_cap/who_subscriber.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "who_cam_define.hpp" 3 | #include "who_task.hpp" 4 | 5 | namespace who { 6 | class WhoSubscriber : public WhoTask { 7 | public: 8 | using WhoTask::WhoTask; 9 | virtual void lcd_display_cb(who::cam::cam_fb_t *fb) {}; 10 | }; 11 | } // namespace who 12 | -------------------------------------------------------------------------------- /components/who_peripherals/who_cam/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(include_dirs .) 2 | 3 | set (requires esp_timer esp-dl esp_lcd) 4 | if (IDF_TARGET STREQUAL "esp32s3") 5 | set(src_dirs who_cam_s3) 6 | list(APPEND include_dirs who_cam_s3) 7 | list(APPEND requires esp32_s3_eye_noglib) 8 | elseif (IDF_TARGET STREQUAL "esp32p4") 9 | set(src_dirs who_cam_p4) 10 | list(APPEND include_dirs who_cam_p4) 11 | list(APPEND requires esp_video 12 | esp32_p4_function_ev_board_noglib) 13 | endif() 14 | 15 | idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires}) 16 | -------------------------------------------------------------------------------- /components/who_peripherals/who_cam/idf_component.yml: -------------------------------------------------------------------------------- 1 | ## IDF Component Manager Manifest File 2 | dependencies: 3 | idf: ">=5.4" 4 | espressif/esp32_p4_function_ev_board_noglib: 5 | version: "*" 6 | rules: 7 | - if: "target == esp32p4" 8 | espressif/esp_video: 9 | version: "^0.8.0~3" 10 | rules: 11 | - if: "target == esp32p4" 12 | espressif/esp_h264: 13 | version: "1.0.4" 14 | rules: 15 | - if: "target == esp32p4" 16 | espressif/esp32_s3_eye_noglib: 17 | version: "*" 18 | rules: 19 | - if: "target == esp32s3" 20 | espressif/esp-dl: 21 | version: "3.1.2" -------------------------------------------------------------------------------- /components/who_peripherals/who_cam/who_cam.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "sdkconfig.h" 3 | #if CONFIG_IDF_TARGET_ESP32S3 4 | #include "who_s3_cam.hpp" 5 | #elif CONFIG_IDF_TARGET_ESP32P4 6 | #include "who_p4_cam.hpp" 7 | #include "who_p4_ppa_cam.hpp" 8 | #endif 9 | -------------------------------------------------------------------------------- /components/who_peripherals/who_cam/who_cam_base.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "who_cam_define.hpp" 3 | 4 | namespace who { 5 | namespace cam { 6 | 7 | class WhoCam { 8 | public: 9 | WhoCam(uint8_t fb_count) : m_fb_count(fb_count) {}; 10 | virtual ~WhoCam() {}; 11 | virtual cam_fb_t *cam_fb_get() = 0; 12 | virtual cam_fb_t *cam_fb_peek(bool back = true) = 0; 13 | virtual std::vector cam_fb_peek(bool back, int num) = 0; 14 | virtual void cam_fb_return() = 0; 15 | virtual std::string get_type() = 0; 16 | uint8_t m_fb_count; 17 | 18 | private: 19 | virtual esp_err_t set_horizontal_flip() = 0; 20 | }; 21 | 22 | } // namespace cam 23 | } // namespace who 24 | -------------------------------------------------------------------------------- /components/who_peripherals/who_cam/who_cam_p4/who_cam_define.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "dl_image.hpp" 3 | #include "linux/videodev2.h" 4 | 5 | namespace who { 6 | namespace cam { 7 | 8 | typedef enum { 9 | VIDEO_PIX_FMT_RAW8_BGGR = V4L2_PIX_FMT_SBGGR8, 10 | VIDEO_PIX_FMT_RGB565 = V4L2_PIX_FMT_RGB565, 11 | VIDEO_PIX_FMT_RGB888 = V4L2_PIX_FMT_RGB24, 12 | VIDEO_PIX_FMT_YUV420 = V4L2_PIX_FMT_YUV420, 13 | VIDEO_PIX_FMT_YUV422P = V4L2_PIX_FMT_YUV422P, 14 | } video_pix_fmt_t; 15 | 16 | typedef struct { 17 | void *buf; 18 | size_t len; 19 | int width; 20 | int height; 21 | video_pix_fmt_t format; 22 | struct timeval timestamp; 23 | } video_fb_t; 24 | 25 | using cam_fb_t = video_fb_t; 26 | 27 | inline dl::image::img_t fb2img(const who::cam::cam_fb_t *fb) 28 | { 29 | assert(fb->format == who::cam::VIDEO_PIX_FMT_RGB565 || fb->format == who::cam::VIDEO_PIX_FMT_RGB888); 30 | return {.data = fb->buf, 31 | .width = fb->width, 32 | .height = fb->height, 33 | .pix_type = (fb->format == who::cam::VIDEO_PIX_FMT_RGB565) ? dl::image::DL_IMAGE_PIX_TYPE_RGB565 34 | : dl::image::DL_IMAGE_PIX_TYPE_RGB888}; 35 | } 36 | 37 | } // namespace cam 38 | } // namespace who 39 | -------------------------------------------------------------------------------- /components/who_peripherals/who_cam/who_cam_p4/who_esp_video.cpp: -------------------------------------------------------------------------------- 1 | #include "who_esp_video.hpp" 2 | #include "esp_err.h" 3 | #include "esp_log.h" 4 | #include "esp_video_device.h" 5 | #include "esp_video_init.h" 6 | #include 7 | #include "bsp/esp-bsp.h" 8 | 9 | static const char *TAG = "ESPVideo"; 10 | 11 | namespace who { 12 | namespace cam { 13 | 14 | ESPVideo::ESPVideo(const video_pix_fmt_t video_pix_fmt, 15 | const uint8_t fb_count, 16 | const v4l2_memory fb_mem_type, 17 | bool horizontal_flip) : 18 | WhoCam(fb_count), m_video_pix_fmt(video_pix_fmt), m_fb_mem_type(fb_mem_type), m_horizontal_flip(horizontal_flip) 19 | { 20 | if ((fb_mem_type != V4L2_MEMORY_MMAP) && (fb_mem_type != V4L2_MEMORY_USERPTR)) { 21 | ESP_LOGE(TAG, "unsupported buffer memory type."); 22 | } 23 | } 24 | 25 | esp_err_t ESPVideo::set_horizontal_flip() 26 | { 27 | struct v4l2_ext_controls controls; 28 | struct v4l2_ext_control control[1]; 29 | controls.ctrl_class = V4L2_CTRL_CLASS_USER; 30 | controls.count = 1; 31 | controls.controls = control; 32 | control[0].id = V4L2_CID_HFLIP; 33 | control[0].value = 1; 34 | if (ioctl(m_fd, VIDIOC_S_EXT_CTRLS, &controls) != 0) { 35 | ESP_LOGE(TAG, "failed to mirror the frame horizontally"); 36 | close(m_fd); 37 | return ESP_FAIL; 38 | } 39 | return ESP_OK; 40 | } 41 | 42 | void ESPVideo::video_init() 43 | { 44 | ESP_ERROR_CHECK(bsp_i2c_init()); 45 | 46 | static bool once = []() { 47 | esp_video_init_csi_config_t csi_config = { 48 | .sccb_config = 49 | { 50 | .init_sccb = false, 51 | .i2c_handle = bsp_i2c_get_handle(), 52 | .freq = 100000, 53 | }, 54 | .reset_pin = -1, 55 | .pwdn_pin = -1, 56 | }; 57 | esp_video_init_config_t cam_config{}; 58 | cam_config.csi = &csi_config; 59 | ESP_ERROR_CHECK(esp_video_init(&cam_config)); 60 | return true; 61 | }(); 62 | (void)once; 63 | 64 | ESP_ERROR_CHECK(open_video_device()); 65 | ESP_ERROR_CHECK(print_info()); 66 | if (m_horizontal_flip) { 67 | ESP_ERROR_CHECK(set_horizontal_flip()); 68 | } 69 | ESP_ERROR_CHECK(set_video_format()); 70 | ESP_ERROR_CHECK(init_fbs()); 71 | ESP_ERROR_CHECK(start_video_stream()); 72 | } 73 | 74 | void ESPVideo::video_deinit() 75 | { 76 | ESP_ERROR_CHECK(stop_video_stream()); 77 | ESP_ERROR_CHECK(close_video_device()); 78 | } 79 | 80 | esp_err_t ESPVideo::open_video_device() 81 | { 82 | m_fd = open(ESP_VIDEO_MIPI_CSI_DEVICE_NAME, O_RDONLY); 83 | if (m_fd < 0) { 84 | ESP_LOGE(TAG, "failed to open device"); 85 | return ESP_FAIL; 86 | } 87 | return ESP_OK; 88 | } 89 | 90 | esp_err_t ESPVideo::print_info() 91 | { 92 | struct v4l2_capability capability; 93 | if (ioctl(m_fd, VIDIOC_QUERYCAP, &capability)) { 94 | ESP_LOGE(TAG, "failed to get capability"); 95 | close(m_fd); 96 | return ESP_FAIL; 97 | } 98 | 99 | ESP_LOGI(TAG, 100 | "version: %d.%d.%d", 101 | (uint16_t)(capability.version >> 16), 102 | (uint8_t)(capability.version >> 8), 103 | (uint8_t)capability.version); 104 | ESP_LOGI(TAG, "driver: %s", capability.driver); 105 | ESP_LOGI(TAG, "card: %s", capability.card); 106 | ESP_LOGI(TAG, "bus: %s", capability.bus_info); 107 | ESP_LOGI(TAG, "capabilities:"); 108 | if (capability.capabilities & V4L2_CAP_VIDEO_CAPTURE) { 109 | ESP_LOGI(TAG, "\tVIDEO_CAPTURE"); 110 | } 111 | if (capability.capabilities & V4L2_CAP_READWRITE) { 112 | ESP_LOGI(TAG, "\tREADWRITE"); 113 | } 114 | if (capability.capabilities & V4L2_CAP_ASYNCIO) { 115 | ESP_LOGI(TAG, "\tASYNCIO"); 116 | } 117 | if (capability.capabilities & V4L2_CAP_STREAMING) { 118 | ESP_LOGI(TAG, "\tSTREAMING"); 119 | } 120 | if (capability.capabilities & V4L2_CAP_META_OUTPUT) { 121 | ESP_LOGI(TAG, "\tMETA_OUTPUT"); 122 | } 123 | if (capability.capabilities & V4L2_CAP_DEVICE_CAPS) { 124 | ESP_LOGI(TAG, "device capabilities:"); 125 | if (capability.device_caps & V4L2_CAP_VIDEO_CAPTURE) { 126 | ESP_LOGI(TAG, "\tVIDEO_CAPTURE"); 127 | } 128 | if (capability.device_caps & V4L2_CAP_READWRITE) { 129 | ESP_LOGI(TAG, "\tREADWRITE"); 130 | } 131 | if (capability.device_caps & V4L2_CAP_ASYNCIO) { 132 | ESP_LOGI(TAG, "\tASYNCIO"); 133 | } 134 | if (capability.device_caps & V4L2_CAP_STREAMING) { 135 | ESP_LOGI(TAG, "\tSTREAMING"); 136 | } 137 | if (capability.device_caps & V4L2_CAP_META_OUTPUT) { 138 | ESP_LOGI(TAG, "\tMETA_OUTPUT"); 139 | } 140 | } 141 | return ESP_OK; 142 | } 143 | 144 | esp_err_t ESPVideo::close_video_device() 145 | { 146 | close(m_fd); 147 | return ESP_OK; 148 | } 149 | 150 | esp_err_t ESPVideo::set_video_format() 151 | { 152 | if (CONFIG_CAMERA_SC2336_MIPI_IF_FORMAT_INDEX_DAFAULT < 8) { 153 | ESP_LOGE(TAG, "raw10 cam mode is not supported."); 154 | close(m_fd); 155 | return ESP_FAIL; 156 | } 157 | struct v4l2_format format; 158 | memset(&format, 0, sizeof(struct v4l2_format)); 159 | format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 160 | if (ioctl(m_fd, VIDIOC_G_FMT, &format) != 0) { 161 | ESP_LOGE(TAG, "failed to get format"); 162 | close(m_fd); 163 | return ESP_FAIL; 164 | } 165 | format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 166 | format.fmt.pix.pixelformat = m_video_pix_fmt; 167 | m_width = format.fmt.pix.width; 168 | m_height = format.fmt.pix.height; 169 | if (ioctl(m_fd, VIDIOC_S_FMT, &format) != 0) { 170 | ESP_LOGE(TAG, "failed to set format"); 171 | close(m_fd); 172 | return ESP_FAIL; 173 | } 174 | return ESP_OK; 175 | } 176 | 177 | esp_err_t ESPVideo::start_video_stream() 178 | { 179 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 180 | if (ioctl(m_fd, VIDIOC_STREAMON, &type) != 0) { 181 | ESP_LOGE(TAG, "failed to start stream"); 182 | close(m_fd); 183 | return ESP_FAIL; 184 | } 185 | return ESP_OK; 186 | } 187 | 188 | esp_err_t ESPVideo::stop_video_stream() 189 | { 190 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 191 | if (ioctl(m_fd, VIDIOC_STREAMOFF, &type) != 0) { 192 | ESP_LOGE(TAG, "failed to stop stream"); 193 | close(m_fd); 194 | return ESP_FAIL; 195 | } 196 | return ESP_OK; 197 | } 198 | 199 | } // namespace cam 200 | } // namespace who 201 | -------------------------------------------------------------------------------- /components/who_peripherals/who_cam/who_cam_p4/who_esp_video.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "who_cam_base.hpp" 3 | #include 4 | #include 5 | 6 | namespace who { 7 | namespace cam { 8 | 9 | class ESPVideo : public WhoCam { 10 | public: 11 | ESPVideo(const video_pix_fmt_t video_pix_fmt, 12 | const uint8_t fb_count, 13 | const v4l2_memory fb_mem_type, 14 | bool horizontal_flip); 15 | 16 | protected: 17 | video_pix_fmt_t m_video_pix_fmt; 18 | v4l2_memory m_fb_mem_type; 19 | bool m_horizontal_flip; 20 | int m_width; 21 | int m_height; 22 | int m_fd; 23 | void video_init(); 24 | void video_deinit(); 25 | 26 | private: 27 | esp_err_t set_horizontal_flip() override; 28 | esp_err_t open_video_device(); 29 | esp_err_t print_info(); 30 | esp_err_t close_video_device(); 31 | esp_err_t set_video_format(); 32 | virtual esp_err_t init_fbs() = 0; 33 | esp_err_t start_video_stream(); 34 | esp_err_t stop_video_stream(); 35 | }; 36 | 37 | } // namespace cam 38 | } // namespace who 39 | -------------------------------------------------------------------------------- /components/who_peripherals/who_cam/who_cam_p4/who_p4_cam.cpp: -------------------------------------------------------------------------------- 1 | #include "who_p4_cam.hpp" 2 | #include "esp_cache.h" 3 | #include "esp_timer.h" 4 | #include "esp_private/esp_cache_private.h" 5 | 6 | static const char *TAG = "WhoP4Cam"; 7 | 8 | namespace who { 9 | namespace cam { 10 | 11 | WhoP4Cam::WhoP4Cam(const video_pix_fmt_t video_pix_fmt, 12 | const uint8_t fb_count, 13 | const v4l2_memory fb_mem_type, 14 | bool horizontal_flip) : 15 | ESPVideo(video_pix_fmt, fb_count, fb_mem_type, horizontal_flip), 16 | m_mutex(xSemaphoreCreateMutex()), 17 | m_cam_fbs(new cam_fb_t[fb_count]) 18 | { 19 | if (fb_count < 3) { 20 | ESP_LOGE("WhoP4Cam", "fb_count is at least 3."); 21 | } 22 | video_init(); 23 | } 24 | 25 | WhoP4Cam::~WhoP4Cam() 26 | { 27 | video_deinit(); 28 | if (m_fb_mem_type == V4L2_MEMORY_USERPTR) { 29 | for (int i = 0; i < m_fb_count; i++) { 30 | heap_caps_free(m_cam_fbs[i].buf); 31 | } 32 | } 33 | delete[] m_cam_fbs; 34 | vSemaphoreDelete(m_mutex); 35 | } 36 | 37 | cam_fb_t *WhoP4Cam::cam_fb_get() 38 | { 39 | if (m_buf_queue.size() + 1 >= m_fb_count) { 40 | ESP_LOGW(TAG, "Can not get more frame buffer."); 41 | return nullptr; 42 | } 43 | struct v4l2_buffer buf; 44 | memset(&buf, 0, sizeof(buf)); 45 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 46 | buf.memory = m_fb_mem_type; 47 | if (ioctl(m_fd, VIDIOC_DQBUF, &buf) != 0) { 48 | ESP_LOGE(TAG, "failed to receive video frame"); 49 | return nullptr; 50 | } 51 | int64_t us = esp_timer_get_time(); 52 | cam_fb_t *fb = m_cam_fbs + buf.index; 53 | fb->timestamp.tv_sec = us / 1000000UL; 54 | fb->timestamp.tv_usec = us % 1000000UL; 55 | xSemaphoreTake(m_mutex, portMAX_DELAY); 56 | m_v4l2_buf_queue.push(buf); 57 | m_buf_queue.push_back(fb); 58 | xSemaphoreGive(m_mutex); 59 | return fb; 60 | } 61 | 62 | cam_fb_t *WhoP4Cam::cam_fb_peek(bool back) 63 | { 64 | return cam_fb_peek(back, 1)[0]; 65 | } 66 | 67 | std::vector WhoP4Cam::cam_fb_peek(bool back, int num) 68 | { 69 | if (m_buf_queue.size() < num) { 70 | ESP_LOGW(TAG, "Unable to peek %d frame buffer from a frame buffer queue of size %d .", num, m_buf_queue.size()); 71 | return {}; 72 | } 73 | std::vector fbs; 74 | if (back) { 75 | xSemaphoreTake(m_mutex, portMAX_DELAY); 76 | for (auto it = m_buf_queue.end() - num; it != m_buf_queue.end(); it++) { 77 | fbs.emplace_back(*it); 78 | } 79 | xSemaphoreGive(m_mutex); 80 | } else { 81 | xSemaphoreTake(m_mutex, portMAX_DELAY); 82 | for (auto it = m_buf_queue.begin(); it != m_buf_queue.begin() + num; it++) { 83 | fbs.emplace_back(*it); 84 | } 85 | xSemaphoreGive(m_mutex); 86 | } 87 | return fbs; 88 | } 89 | 90 | void WhoP4Cam::cam_fb_return() 91 | { 92 | if (m_buf_queue.empty()) { 93 | ESP_LOGW(TAG, "Can not return more frame buffer."); 94 | return; 95 | } 96 | struct v4l2_buffer buf = m_v4l2_buf_queue.front(); 97 | cam_fb_t *fb = m_cam_fbs + buf.index; 98 | if (m_fb_mem_type == V4L2_MEMORY_USERPTR) { 99 | buf.m.userptr = (unsigned long)fb->buf; 100 | buf.length = fb->len; 101 | } 102 | xSemaphoreTake(m_mutex, portMAX_DELAY); 103 | if (ioctl(m_fd, VIDIOC_QBUF, &buf) != 0) { 104 | ESP_LOGE(TAG, "failed to queue video frame"); 105 | return; 106 | } 107 | m_v4l2_buf_queue.pop(); 108 | m_buf_queue.pop_front(); 109 | xSemaphoreGive(m_mutex); 110 | } 111 | 112 | esp_err_t WhoP4Cam::init_fbs() 113 | { 114 | struct v4l2_requestbuffers req; 115 | memset(&req, 0, sizeof(req)); 116 | req.count = m_fb_count; 117 | req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 118 | req.memory = m_fb_mem_type; 119 | if (ioctl(m_fd, VIDIOC_REQBUFS, &req) != 0) { 120 | ESP_LOGE(TAG, "failed to require buffer"); 121 | close(m_fd); 122 | return ESP_FAIL; 123 | } 124 | 125 | struct v4l2_buffer buf; 126 | size_t cache_line_size; 127 | ESP_ERROR_CHECK(esp_cache_get_alignment(MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA, &cache_line_size)); 128 | for (size_t i = 0; i < m_fb_count; i++) { 129 | memset(&buf, 0, sizeof(buf)); 130 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 131 | buf.memory = m_fb_mem_type; 132 | buf.index = i; 133 | 134 | if (ioctl(m_fd, VIDIOC_QUERYBUF, &buf) != 0) { 135 | ESP_LOGE(TAG, "failed to query buffer"); 136 | close(m_fd); 137 | return ESP_FAIL; 138 | } 139 | 140 | cam_fb_t *fb = m_cam_fbs + buf.index; 141 | fb->len = buf.length; 142 | if (m_fb_mem_type == V4L2_MEMORY_MMAP) { 143 | fb->buf = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, buf.m.offset); 144 | } else { 145 | fb->buf = heap_caps_aligned_alloc(cache_line_size, buf.length, MALLOC_CAP_SPIRAM); 146 | buf.m.userptr = (unsigned long)fb->buf; 147 | } 148 | fb->width = m_width; 149 | fb->height = m_height; 150 | fb->format = m_video_pix_fmt; 151 | 152 | if (!fb->buf) { 153 | ESP_LOGE(TAG, "failed to map/alloc buffer"); 154 | close(m_fd); 155 | return ESP_FAIL; 156 | } 157 | 158 | if (ioctl(m_fd, VIDIOC_QBUF, &buf) != 0) { 159 | ESP_LOGE(TAG, "failed to queue video frame"); 160 | close(m_fd); 161 | return ESP_FAIL; 162 | } 163 | } 164 | 165 | return ESP_OK; 166 | } 167 | 168 | } // namespace cam 169 | } // namespace who 170 | -------------------------------------------------------------------------------- /components/who_peripherals/who_cam/who_cam_p4/who_p4_cam.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "who_esp_video.hpp" 3 | #include 4 | #include 5 | 6 | namespace who { 7 | namespace cam { 8 | 9 | class WhoP4Cam : public ESPVideo { 10 | public: 11 | WhoP4Cam(const video_pix_fmt_t video_pix_fmt, 12 | const uint8_t fb_count, 13 | const v4l2_memory fb_mem_type, 14 | bool horizontal_flip); 15 | ~WhoP4Cam(); 16 | cam_fb_t *cam_fb_get() override; 17 | cam_fb_t *cam_fb_peek(bool back = true) override; 18 | std::vector cam_fb_peek(bool back, int num) override; 19 | void cam_fb_return() override; 20 | std::string get_type() override { return "WhoP4Cam"; } 21 | 22 | private: 23 | SemaphoreHandle_t m_mutex; 24 | cam_fb_t *m_cam_fbs; 25 | std::queue m_v4l2_buf_queue; 26 | std::deque m_buf_queue; 27 | 28 | esp_err_t init_fbs() override; 29 | }; 30 | 31 | } // namespace cam 32 | } // namespace who 33 | -------------------------------------------------------------------------------- /components/who_peripherals/who_cam/who_cam_p4/who_p4_ppa_cam.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "who_esp_video.hpp" 3 | #include 4 | #include 5 | 6 | namespace who { 7 | namespace cam { 8 | 9 | class WhoP4PPACam : public ESPVideo { 10 | public: 11 | typedef struct { 12 | cam_fb_t *fb; 13 | cam_fb_t *ppa_fb; 14 | } ppa_cam_fb_t; 15 | WhoP4PPACam(const video_pix_fmt_t video_pix_fmt, 16 | const uint8_t fb_count, 17 | const v4l2_memory fb_mem_type, 18 | int ppa_resized_w, 19 | int ppa_resized_h, 20 | bool horizontal_flip); 21 | ~WhoP4PPACam(); 22 | cam_fb_t *cam_fb_get() override; 23 | cam_fb_t *cam_fb_peek(bool back = true) override; 24 | std::vector cam_fb_peek(bool back, int num) override; 25 | cam_fb_t *ppa_cam_fb_peek(bool back = true); 26 | std::vector ppa_cam_fb_peek(bool back, int num); 27 | void cam_fb_return() override; 28 | std::string get_type() override { return "WhoP4PPACam"; } 29 | float m_ppa_scale_x; 30 | float m_ppa_scale_y; 31 | 32 | private: 33 | esp_err_t init_fbs() override; 34 | static bool ppa_trans_done_cb(ppa_client_handle_t ppa_client, ppa_event_data_t *event_data, void *user_data); 35 | static void task(void *args); 36 | 37 | SemaphoreHandle_t m_mutex; 38 | SemaphoreHandle_t m_ppa_sem1; 39 | SemaphoreHandle_t m_ppa_sem2; 40 | SemaphoreHandle_t m_task_finish; 41 | volatile bool m_task_stop = false; 42 | TaskHandle_t m_task_handle; 43 | cam_fb_t *m_cam_fbs; 44 | cam_fb_t *m_ppa_cam_fbs; 45 | int m_ppa_resized_w; 46 | int m_ppa_resized_h; 47 | ppa_client_handle_t m_ppa_srm_handle; 48 | std::queue m_v4l2_buf_queue; 49 | std::deque m_buf_queue; 50 | }; 51 | 52 | } // namespace cam 53 | } // namespace who 54 | -------------------------------------------------------------------------------- /components/who_peripherals/who_cam/who_cam_s3/who_cam_define.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "dl_image.hpp" 3 | #include "esp_camera.h" 4 | 5 | namespace who { 6 | namespace cam { 7 | 8 | using cam_fb_t = camera_fb_t; 9 | 10 | inline dl::image::img_t fb2img(const who::cam::cam_fb_t *fb) 11 | { 12 | assert(fb->format == PIXFORMAT_RGB565 || fb->format == PIXFORMAT_RGB888); 13 | return {.data = fb->buf, 14 | .width = (int)fb->width, 15 | .height = (int)fb->height, 16 | .pix_type = (fb->format == PIXFORMAT_RGB565) ? dl::image::DL_IMAGE_PIX_TYPE_RGB565 17 | : dl::image::DL_IMAGE_PIX_TYPE_RGB888}; 18 | } 19 | 20 | } // namespace cam 21 | } // namespace who 22 | -------------------------------------------------------------------------------- /components/who_peripherals/who_cam/who_cam_s3/who_s3_cam.cpp: -------------------------------------------------------------------------------- 1 | #include "who_s3_cam.hpp" 2 | #include "esp_err.h" 3 | #include "esp_log.h" 4 | #include "bsp/esp-bsp.h" 5 | 6 | static const char *TAG = "WhoS3Cam"; 7 | 8 | namespace who { 9 | namespace cam { 10 | 11 | WhoS3Cam::WhoS3Cam(const pixformat_t pixel_format, 12 | const framesize_t frame_size, 13 | const uint8_t fb_count, 14 | bool horizontal_flip) : 15 | WhoCam(fb_count), m_mutex(xSemaphoreCreateMutex()) 16 | { 17 | if (fb_count < 2) { 18 | ESP_LOGE("WhoS3Cam", "fb_count is at least 2."); 19 | } 20 | ESP_ERROR_CHECK(bsp_i2c_init()); 21 | camera_config_t camera_config = BSP_CAMERA_DEFAULT_CONFIG; 22 | camera_config.pixel_format = pixel_format; 23 | camera_config.frame_size = frame_size; 24 | camera_config.fb_count = fb_count; 25 | if (pixel_format == PIXFORMAT_JPEG) { 26 | camera_config.xclk_freq_hz = 20000000; 27 | } 28 | ESP_ERROR_CHECK(esp_camera_init(&camera_config)); 29 | sensor_t *s = esp_camera_sensor_get(); 30 | if (s->id.PID == OV3660_PID || s->id.PID == OV2640_PID || s->id.PID == GC032A_PID) { 31 | s->set_vflip(s, 1); 32 | } 33 | if (!horizontal_flip) { 34 | ESP_ERROR_CHECK(set_horizontal_flip()); 35 | } 36 | } 37 | 38 | WhoS3Cam::~WhoS3Cam() 39 | { 40 | xSemaphoreTake(m_mutex, portMAX_DELAY); 41 | while (!m_buf_queue.empty()) { 42 | esp_camera_fb_return(m_buf_queue.front()); 43 | m_buf_queue.pop_front(); 44 | } 45 | xSemaphoreGive(m_mutex); 46 | } 47 | 48 | cam_fb_t *WhoS3Cam::cam_fb_get() 49 | { 50 | if (m_buf_queue.size() >= m_fb_count) { 51 | ESP_LOGW(TAG, "Can not get more frame buffer."); 52 | return nullptr; 53 | } 54 | cam_fb_t *fb = esp_camera_fb_get(); 55 | xSemaphoreTake(m_mutex, portMAX_DELAY); 56 | m_buf_queue.push_back(fb); 57 | xSemaphoreGive(m_mutex); 58 | return fb; 59 | } 60 | 61 | cam_fb_t *WhoS3Cam::cam_fb_peek(bool back) 62 | { 63 | return cam_fb_peek(back, 1)[0]; 64 | } 65 | 66 | std::vector WhoS3Cam::cam_fb_peek(bool back, int num) 67 | { 68 | if (m_buf_queue.size() < num) { 69 | ESP_LOGW(TAG, "Unable to peek %d frame buffer from a frame buffer queue of size %d .", num, m_buf_queue.size()); 70 | return {}; 71 | } 72 | std::vector fbs; 73 | if (back) { 74 | xSemaphoreTake(m_mutex, portMAX_DELAY); 75 | for (auto it = m_buf_queue.end() - num; it != m_buf_queue.end(); it++) { 76 | fbs.emplace_back(*it); 77 | } 78 | xSemaphoreGive(m_mutex); 79 | } else { 80 | xSemaphoreTake(m_mutex, portMAX_DELAY); 81 | for (auto it = m_buf_queue.begin(); it != m_buf_queue.begin() + num; it++) { 82 | fbs.emplace_back(*it); 83 | } 84 | xSemaphoreGive(m_mutex); 85 | } 86 | return fbs; 87 | } 88 | 89 | void WhoS3Cam::cam_fb_return() 90 | { 91 | if (m_buf_queue.empty()) { 92 | ESP_LOGW(TAG, "Can not return more frame buffer."); 93 | return; 94 | } 95 | xSemaphoreTake(m_mutex, portMAX_DELAY); 96 | esp_camera_fb_return(m_buf_queue.front()); 97 | m_buf_queue.pop_front(); 98 | xSemaphoreGive(m_mutex); 99 | } 100 | 101 | esp_err_t WhoS3Cam::set_horizontal_flip() 102 | { 103 | sensor_t *s = esp_camera_sensor_get(); 104 | int ret = s->set_hmirror(s, 1); 105 | return (ret == 0) ? ESP_OK : ESP_FAIL; 106 | } 107 | 108 | } // namespace cam 109 | } // namespace who 110 | -------------------------------------------------------------------------------- /components/who_peripherals/who_cam/who_cam_s3/who_s3_cam.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "who_cam_base.hpp" 3 | #include 4 | 5 | namespace who { 6 | namespace cam { 7 | 8 | class WhoS3Cam : public WhoCam { 9 | public: 10 | WhoS3Cam(const pixformat_t pixel_format, 11 | const framesize_t frame_size, 12 | const uint8_t fb_count, 13 | bool horizontal_flip); 14 | ~WhoS3Cam(); 15 | cam_fb_t *cam_fb_get() override; 16 | cam_fb_t *cam_fb_peek(bool back = true) override; 17 | std::vector cam_fb_peek(bool back, int num) override; 18 | void cam_fb_return() override; 19 | std::string get_type() override { return "WhoS3Cam"; } 20 | 21 | private: 22 | SemaphoreHandle_t m_mutex; 23 | esp_err_t set_horizontal_flip() override; 24 | std::deque m_buf_queue; 25 | }; 26 | 27 | } // namespace cam 28 | } // namespace who 29 | -------------------------------------------------------------------------------- /components/who_peripherals/who_lcd/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(src_dirs .) 2 | 3 | set(include_dirs .) 4 | 5 | set (requires esp_lcd) 6 | if (IDF_TARGET STREQUAL "esp32s3") 7 | list(APPEND requires esp32_s3_eye_noglib) 8 | elseif (IDF_TARGET STREQUAL "esp32p4") 9 | list(APPEND requires esp32_p4_function_ev_board_noglib) 10 | endif() 11 | 12 | idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires}) 13 | 14 | idf_build_get_property(build_components BUILD_COMPONENTS) 15 | set(optional_reqs esp_lvgl_port espressif__esp_lvgl_port) 16 | foreach(req ${optional_reqs}) 17 | if(req IN_LIST build_components) 18 | idf_component_get_property(req_lib ${req} COMPONENT_LIB) 19 | add_library(who_lvgl_utils STATIC 20 | who_lvgl_utils/montserrat_bold_26.c 21 | who_lvgl_utils/montserrat_bold_20.c 22 | who_lvgl_utils/who_lvgl_utils.cpp 23 | ) 24 | target_include_directories(who_lvgl_utils PUBLIC who_lvgl_utils) 25 | target_link_libraries(who_lvgl_utils PUBLIC ${req_lib}) 26 | target_link_libraries(${COMPONENT_LIB} INTERFACE who_lvgl_utils) 27 | if (IDF_TARGET STREQUAL "esp32s3") 28 | if (esp32_s3_eye_noglib IN_LIST build_components) 29 | idf_component_get_property(bsp_lib esp32_s3_eye_noglib COMPONENT_LIB) 30 | elseif(espressif__esp32_s3_eye_noglib IN_LIST build_components) 31 | idf_component_get_property(bsp_lib espressif__esp32_s3_eye_noglib COMPONENT_LIB) 32 | endif() 33 | elseif (IDF_TARGET STREQUAL "esp32p4") 34 | if (esp32_p4_function_ev_board_noglib IN_LIST build_components) 35 | idf_component_get_property(bsp_lib esp32_p4_function_ev_board_noglib COMPONENT_LIB) 36 | elseif(espressif__esp32_p4_function_ev_board_noglib IN_LIST build_components) 37 | idf_component_get_property(bsp_lib espressif__esp32_p4_function_ev_board_noglib COMPONENT_LIB) 38 | endif() 39 | endif() 40 | target_compile_definitions(${bsp_lib} PUBLIC "BSP_CONFIG_NO_GRAPHIC_LIB=0") 41 | target_link_libraries(${bsp_lib} PUBLIC ${req_lib}) 42 | endif() 43 | endforeach() 44 | -------------------------------------------------------------------------------- /components/who_peripherals/who_lcd/idf_component.yml: -------------------------------------------------------------------------------- 1 | ## IDF Component Manager Manifest File 2 | dependencies: 3 | idf: ">=5.4" 4 | espressif/esp32_p4_function_ev_board_noglib: 5 | version: "*" 6 | rules: 7 | - if: "target == esp32p4" 8 | espressif/esp32_s3_eye_noglib: 9 | version: "*" 10 | rules: 11 | - if: "target == esp32s3" -------------------------------------------------------------------------------- /components/who_peripherals/who_lcd/who_lcd.cpp: -------------------------------------------------------------------------------- 1 | #include "who_lcd.hpp" 2 | #include "esp_lcd_panel_ops.h" 3 | #include 4 | #if BSP_CONFIG_NO_GRAPHIC_LIB 5 | namespace who { 6 | namespace lcd { 7 | esp_lcd_panel_handle_t WhoLCD::get_lcd_panel_handle() 8 | { 9 | #if CONFIG_IDF_TARGET_ESP32S3 10 | return m_panel_handle; 11 | #elif CONFIG_IDF_TARGET_ESP32P4 12 | return m_lcd_handles.panel; 13 | #endif 14 | } 15 | 16 | #if CONFIG_IDF_TARGET_ESP32S3 17 | void WhoLCD::init() 18 | { 19 | const bsp_display_config_t bsp_disp_cfg = { 20 | .max_transfer_sz = BSP_LCD_H_RES * BSP_LCD_V_RES * (BSP_LCD_BITS_PER_PIXEL / 8), 21 | }; 22 | ESP_ERROR_CHECK(bsp_display_new(&bsp_disp_cfg, &m_panel_handle, &m_io_handle)); 23 | esp_lcd_panel_disp_on_off(m_panel_handle, true); 24 | ESP_ERROR_CHECK(bsp_display_backlight_on()); 25 | m_lcd_buffer = heap_caps_malloc(BSP_LCD_H_RES * BSP_LCD_V_RES * (BSP_LCD_BITS_PER_PIXEL / 8), 26 | MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA); 27 | } 28 | 29 | void WhoLCD::draw_full_lcd(const void *data) 30 | { 31 | // Currently esp-idf doesn't support DMA for PSRAM in esp32s3. 32 | // Display the fb must copy it from PSRAM to internal RAM. 33 | // Use a static internal memory chunk to avoid alloc internal memory each time dynamically. 34 | memcpy(m_lcd_buffer, data, BSP_LCD_H_RES * BSP_LCD_V_RES * (BSP_LCD_BITS_PER_PIXEL / 8)); 35 | esp_lcd_panel_draw_bitmap(m_panel_handle, 0, 0, BSP_LCD_H_RES, BSP_LCD_V_RES, m_lcd_buffer); 36 | } 37 | #elif CONFIG_IDF_TARGET_ESP32P4 38 | void WhoLCD::init() 39 | { 40 | bsp_display_config_t bsp_disp_cfg = { 41 | #if CONFIG_BSP_LCD_TYPE_HDMI 42 | #if CONFIG_BSP_LCD_HDMI_800x600_60HZ 43 | .hdmi_resolution = BSP_HDMI_RES_800x600, 44 | #elif CONFIG_BSP_LCD_HDMI_1280x720_60HZ 45 | .hdmi_resolution = BSP_HDMI_RES_1280x720, 46 | #elif CONFIG_BSP_LCD_HDMI_1280x800_60HZ 47 | .hdmi_resolution = BSP_HDMI_RES_1280x800, 48 | #elif CONFIG_BSP_LCD_HDMI_1920x1080_30HZ 49 | .hdmi_resolution = BSP_HDMI_RES_1920x1080, 50 | #endif 51 | #else 52 | .hdmi_resolution = BSP_HDMI_RES_NONE, 53 | #endif 54 | .dsi_bus = { 55 | .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, 56 | .lane_bit_rate_mbps = BSP_LCD_MIPI_DSI_LANE_BITRATE_MBPS, 57 | }}; 58 | bsp_display_new_with_handles(&bsp_disp_cfg, &m_lcd_handles); 59 | ESP_ERROR_CHECK(bsp_display_brightness_init()); 60 | ESP_ERROR_CHECK(bsp_display_backlight_on()); 61 | } 62 | 63 | void WhoLCD::draw_full_lcd(const void *data) 64 | { 65 | esp_lcd_panel_draw_bitmap(m_lcd_handles.panel, 0, 0, BSP_LCD_H_RES, BSP_LCD_V_RES, data); 66 | } 67 | #endif 68 | } // namespace lcd 69 | } // namespace who 70 | #endif 71 | -------------------------------------------------------------------------------- /components/who_peripherals/who_lcd/who_lcd.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "esp_lcd_types.h" 3 | #include "bsp/esp-bsp.h" 4 | #if !BSP_CONFIG_NO_GRAPHIC_LIB 5 | #include "who_lvgl_lcd.hpp" 6 | #else 7 | 8 | namespace who { 9 | namespace lcd { 10 | class WhoLCD { 11 | public: 12 | WhoLCD() { init(); } 13 | void init(); 14 | esp_lcd_panel_handle_t get_lcd_panel_handle(); 15 | void draw_full_lcd(const void *data); 16 | 17 | private: 18 | #if CONFIG_IDF_TARGET_ESP32S3 19 | esp_lcd_panel_handle_t m_panel_handle; 20 | esp_lcd_panel_io_handle_t m_io_handle; 21 | void *m_lcd_buffer; 22 | #elif CONFIG_IDF_TARGET_ESP32P4 23 | bsp_lcd_handles_t m_lcd_handles; 24 | #endif 25 | }; 26 | } // namespace lcd 27 | } // namespace who 28 | #endif 29 | -------------------------------------------------------------------------------- /components/who_peripherals/who_lcd/who_lvgl_lcd.cpp: -------------------------------------------------------------------------------- 1 | #include "who_lvgl_lcd.hpp" 2 | #include "esp_lcd_panel_ops.h" 3 | #if !BSP_CONFIG_NO_GRAPHIC_LIB 4 | namespace who { 5 | namespace lcd { 6 | #if CONFIG_IDF_TARGET_ESP32S3 7 | void WhoLCD::init(const lvgl_port_cfg_t &lvgl_port_cfg) 8 | { 9 | lvgl_port_init(&lvgl_port_cfg); 10 | esp_lcd_panel_io_handle_t io_handle = NULL; 11 | esp_lcd_panel_handle_t panel_handle = NULL; 12 | const bsp_display_config_t bsp_disp_cfg = { 13 | .max_transfer_sz = BSP_LCD_H_RES * BSP_LCD_V_RES * sizeof(uint16_t), 14 | }; 15 | ESP_ERROR_CHECK(bsp_display_new(&bsp_disp_cfg, &panel_handle, &io_handle)); 16 | esp_lcd_panel_disp_on_off(panel_handle, true); 17 | const lvgl_port_display_cfg_t disp_cfg = { 18 | .io_handle = io_handle, 19 | .panel_handle = panel_handle, 20 | .buffer_size = BSP_LCD_DRAW_BUFF_SIZE, 21 | .double_buffer = BSP_LCD_DRAW_BUFF_DOUBLE, 22 | .hres = BSP_LCD_H_RES, 23 | .vres = BSP_LCD_V_RES, 24 | .monochrome = false, 25 | /* Rotation values must be same as used in esp_lcd for initial settings of the screen */ 26 | .rotation = 27 | { 28 | .swap_xy = false, 29 | .mirror_x = false, 30 | .mirror_y = false, 31 | }, 32 | .flags = { 33 | .buff_dma = true, 34 | .buff_spiram = false, 35 | #if LVGL_VERSION_MAJOR >= 9 36 | .swap_bytes = false, 37 | #endif 38 | }}; 39 | lvgl_port_add_disp(&disp_cfg); 40 | ESP_ERROR_CHECK(bsp_display_backlight_on()); 41 | } 42 | #elif CONFIG_IDF_TARGET_ESP32P4 43 | void WhoLCD::init(const lvgl_port_cfg_t &lvgl_port_cfg) 44 | { 45 | bsp_display_cfg_t cfg = {.lvgl_port_cfg = lvgl_port_cfg, 46 | .buffer_size = BSP_LCD_DRAW_BUFF_SIZE, 47 | .double_buffer = BSP_LCD_DRAW_BUFF_DOUBLE, 48 | .hw_cfg = 49 | { 50 | #if CONFIG_BSP_LCD_TYPE_HDMI 51 | #if CONFIG_BSP_LCD_HDMI_800x600_60HZ 52 | .hdmi_resolution = BSP_HDMI_RES_800x600, 53 | #elif CONFIG_BSP_LCD_HDMI_1280x720_60HZ 54 | .hdmi_resolution = BSP_HDMI_RES_1280x720, 55 | #elif CONFIG_BSP_LCD_HDMI_1280x800_60HZ 56 | .hdmi_resolution = BSP_HDMI_RES_1280x800, 57 | #elif CONFIG_BSP_LCD_HDMI_1920x1080_30HZ 58 | .hdmi_resolution = BSP_HDMI_RES_1920x1080, 59 | #endif 60 | #else 61 | .hdmi_resolution = BSP_HDMI_RES_NONE, 62 | #endif 63 | .dsi_bus = 64 | { 65 | .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, 66 | .lane_bit_rate_mbps = BSP_LCD_MIPI_DSI_LANE_BITRATE_MBPS, 67 | }}, 68 | .flags = { 69 | #if CONFIG_BSP_LCD_COLOR_FORMAT_RGB888 70 | .buff_dma = false, 71 | #else 72 | .buff_dma = true, 73 | #endif 74 | .buff_spiram = false, 75 | .sw_rotate = true, 76 | }}; 77 | bsp_display_start_with_config(&cfg); 78 | ESP_ERROR_CHECK(bsp_display_backlight_on()); 79 | } 80 | #endif 81 | void WhoLCD::create_canvas() 82 | { 83 | bsp_display_lock(0); 84 | m_canvas = lv_canvas_create(lv_scr_act()); 85 | lv_obj_set_size(m_canvas, BSP_LCD_H_RES, BSP_LCD_V_RES); 86 | bsp_display_unlock(); 87 | } 88 | } // namespace lcd 89 | } // namespace who 90 | #endif 91 | -------------------------------------------------------------------------------- /components/who_peripherals/who_lcd/who_lvgl_lcd.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "esp_lcd_types.h" 3 | #include "bsp/esp-bsp.h" 4 | #if !BSP_CONFIG_NO_GRAPHIC_LIB 5 | #include "lvgl.h" 6 | 7 | namespace who { 8 | namespace lcd { 9 | class WhoLCD { 10 | public: 11 | WhoLCD(const lvgl_port_cfg_t &lvgl_port_cfg = {4, 6144, 0, 500, 5}) { init(lvgl_port_cfg); } 12 | void init(const lvgl_port_cfg_t &lvgl_port_cfg); 13 | void create_canvas(); 14 | lv_obj_t *get_canvas() { return m_canvas; } 15 | 16 | private: 17 | lv_obj_t *m_canvas; 18 | }; 19 | } // namespace lcd 20 | } // namespace who 21 | #endif 22 | -------------------------------------------------------------------------------- /components/who_peripherals/who_lcd/who_lvgl_utils/who_lvgl_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "who_lvgl_utils.hpp" 2 | 3 | namespace who { 4 | lv_obj_t *create_lvgl_btn(const char *text, const lv_font_t *font, lv_obj_t *parent) 5 | { 6 | lv_obj_t *btn = lv_button_create(parent); 7 | lv_obj_t *label = lv_label_create(btn); 8 | lv_label_set_text(label, text); 9 | lv_obj_set_style_text_font(label, font, LV_PART_MAIN); 10 | lv_obj_center(label); 11 | return btn; 12 | } 13 | 14 | lv_obj_t *create_lvgl_label(const char *text, 15 | const lv_font_t *font, 16 | const std::vector &color, 17 | lv_obj_t *parent) 18 | { 19 | #if CONFIG_IDF_TARGET_ESP32P4 20 | lv_color_t c = lv_color_make(color[0], color[1], color[2]); 21 | #else 22 | lv_color_t c = cvt_little_endian_lv_color(lv_color_make(color[0], color[1], color[2])); 23 | #endif 24 | lv_obj_t *label = lv_label_create(parent); 25 | lv_label_set_text(label, text); 26 | lv_obj_set_style_text_font(label, font, LV_PART_MAIN); 27 | lv_obj_set_style_text_color(label, c, LV_PART_MAIN); 28 | return label; 29 | } 30 | } // namespace who 31 | -------------------------------------------------------------------------------- /components/who_peripherals/who_lcd/who_lvgl_utils/who_lvgl_utils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lvgl.h" 4 | #include 5 | 6 | namespace who { 7 | inline lv_color_t cvt_little_endian_lv_color(const lv_color_t &color) 8 | { 9 | lv_color_t new_color; 10 | new_color.red = (color.green & 0x1c) << 3 | (color.blue & 0xc0) >> 3; 11 | new_color.green = (color.blue & 0x38) << 2 | (color.red & 0xe0) >> 3; 12 | new_color.blue = (color.red & 0x18) << 3 | (color.green & 0xe0) >> 2; 13 | return new_color; 14 | } 15 | 16 | inline lv_color_t cvt_to_lv_color(const std::vector &color) 17 | { 18 | #if CONFIG_IDF_TARGET_ESP32P4 19 | return lv_color_make(color[0], color[1], color[2]); 20 | #else 21 | return cvt_little_endian_lv_color(lv_color_make(color[0], color[1], color[2])); 22 | #endif 23 | } 24 | 25 | inline std::vector cvt_to_lv_palette(const std::vector> &palette) 26 | { 27 | std::vector lv_palette; 28 | for (int i = 0; i < palette.size(); i++) { 29 | lv_palette.emplace_back(cvt_to_lv_color(palette[i])); 30 | } 31 | return lv_palette; 32 | } 33 | 34 | lv_obj_t *create_lvgl_btn(const char *text, const lv_font_t *font, lv_obj_t *parent = lv_scr_act()); 35 | lv_obj_t *create_lvgl_label(const char *text, 36 | const lv_font_t *font, 37 | const std::vector &color = {255, 0, 0}, 38 | lv_obj_t *parent = lv_scr_act()); 39 | } // namespace who 40 | -------------------------------------------------------------------------------- /components/who_peripherals/who_spiflash_fatfs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(src_dirs .) 2 | 3 | set(include_dirs .) 4 | 5 | set(requires fatfs vfs) 6 | 7 | idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires}) -------------------------------------------------------------------------------- /components/who_peripherals/who_spiflash_fatfs/Kconfig: -------------------------------------------------------------------------------- 1 | menu "esp-who: human_face_recognition" 2 | config SPIFLASH_MOUNT_POINT 3 | string "spiflash fatfs mount point" 4 | default "/spiflash" 5 | 6 | config SPIFLASH_MOUNT_PARTITION 7 | string "spiflash fatfs mount partition" 8 | default "storage" 9 | endmenu 10 | -------------------------------------------------------------------------------- /components/who_peripherals/who_spiflash_fatfs/who_spiflash_fatfs.cpp: -------------------------------------------------------------------------------- 1 | #include "who_spiflash_fatfs.hpp" 2 | 3 | static const char *TAG = "spiflash_fatfs"; 4 | static wl_handle_t wl_handle; 5 | 6 | esp_err_t fatfs_flash_mount() 7 | { 8 | esp_vfs_fat_mount_config_t mount_config; 9 | memset(&mount_config, 0, sizeof(esp_vfs_fat_mount_config_t)); 10 | mount_config.max_files = 5; 11 | mount_config.format_if_mount_failed = true; 12 | ESP_ERROR_CHECK(esp_vfs_fat_spiflash_mount_rw_wl( 13 | CONFIG_SPIFLASH_MOUNT_POINT, CONFIG_SPIFLASH_MOUNT_PARTITION, &mount_config, &wl_handle)); 14 | return ESP_OK; 15 | } 16 | 17 | esp_err_t fatfs_flash_unmount() 18 | { 19 | ESP_RETURN_ON_ERROR( 20 | esp_vfs_fat_spiflash_unmount_rw_wl(CONFIG_SPIFLASH_MOUNT_POINT, wl_handle), TAG, "Failed to unmount."); 21 | return ESP_OK; 22 | } 23 | -------------------------------------------------------------------------------- /components/who_peripherals/who_spiflash_fatfs/who_spiflash_fatfs.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "esp_check.h" 4 | #include "esp_err.h" 5 | #include "esp_log.h" 6 | #include "esp_vfs.h" 7 | #include "esp_vfs_fat.h" 8 | 9 | esp_err_t fatfs_flash_mount(); 10 | esp_err_t fatfs_flash_unmount(); 11 | -------------------------------------------------------------------------------- /components/who_qrcode/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(src_dirs .) 2 | 3 | set(include_dirs .) 4 | 5 | set(requires who_frame_cap 6 | quirc) 7 | 8 | idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires}) -------------------------------------------------------------------------------- /components/who_qrcode/idf_component.yml: -------------------------------------------------------------------------------- 1 | ## IDF Component Manager Manifest File 2 | dependencies: 3 | espressif/quirc: 4 | version: "*" -------------------------------------------------------------------------------- /components/who_qrcode/who_qrcode_base.cpp: -------------------------------------------------------------------------------- 1 | #include "who_qrcode_base.hpp" 2 | 3 | namespace who { 4 | namespace qrcode { 5 | void WhoQRCodeBase::task() 6 | { 7 | while (true) { 8 | set_and_clear_bits(BLOCKING, RUNNING); 9 | EventBits_t event_bits = 10 | xEventGroupWaitBits(m_event_group, NEW_FRAME | PAUSE | STOP, pdTRUE, pdFALSE, portMAX_DELAY); 11 | if (event_bits & STOP) { 12 | set_and_clear_bits(TERMINATE, BLOCKING); 13 | break; 14 | } else if (event_bits & PAUSE) { 15 | EventBits_t pause_event_bits = 16 | xEventGroupWaitBits(m_event_group, RESUME | STOP, pdTRUE, pdFALSE, portMAX_DELAY); 17 | if (pause_event_bits & STOP) { 18 | set_and_clear_bits(TERMINATE, BLOCKING); 19 | break; 20 | } else { 21 | continue; 22 | } 23 | } 24 | set_and_clear_bits(RUNNING, BLOCKING); 25 | auto fb = m_frame_cap->get_cam()->cam_fb_peek(); 26 | auto img = cam::fb2img(fb); 27 | quirc_begin(m_qr, nullptr, nullptr); 28 | #if CONFIG_IDF_TARGET_ESP32S3 29 | uint32_t caps = 0; 30 | #elif CONFIG_IDF_TARGET_ESP32P4 31 | uint32_t caps = DL_IMAGE_CAP_RGB565_BIG_ENDIAN; 32 | #endif 33 | dl::image::resize(img, m_input, dl::image::DL_IMAGE_INTERPOLATE_NEAREST, caps); 34 | quirc_end(m_qr); 35 | int num_codes = quirc_count(m_qr); 36 | for (int i = 0; i < num_codes; i++) { 37 | struct quirc_code code; 38 | struct quirc_data data; 39 | quirc_decode_error_t err; 40 | quirc_extract(m_qr, i, &code); 41 | err = quirc_decode(&code, &data); 42 | if (err == QUIRC_ERROR_DATA_ECC) { 43 | quirc_flip(&code); 44 | err = quirc_decode(&code, &data); 45 | } 46 | // Even if there are multiple codes, only process one of them. 47 | if (!err) { 48 | on_new_qrcode_result(reinterpret_cast(data.payload)); 49 | break; 50 | } 51 | } 52 | } 53 | vTaskDelete(NULL); 54 | } 55 | } // namespace qrcode 56 | } // namespace who 57 | -------------------------------------------------------------------------------- /components/who_qrcode/who_qrcode_base.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "quirc.h" 3 | #include "who_cam_define.hpp" 4 | #include "who_frame_cap.hpp" 5 | #include "who_subscriber.hpp" 6 | 7 | namespace who { 8 | namespace qrcode { 9 | class WhoQRCodeBase : public WhoSubscriber { 10 | public: 11 | WhoQRCodeBase(frame_cap::WhoFrameCap *frame_cap, const std::string &name) : 12 | WhoSubscriber(name), m_frame_cap(frame_cap), m_qr(quirc_new()) 13 | { 14 | frame_cap->add_element(this); 15 | #if CONFIG_IDF_TARGET_ESP32S3 16 | int w = BSP_LCD_H_RES, h = BSP_LCD_V_RES; 17 | #elif CONFIG_IDF_TARGET_ESP32P4 18 | int w = BSP_LCD_H_RES / 2, h = BSP_LCD_V_RES / 2; 19 | #endif 20 | quirc_resize(m_qr, w, h); 21 | uint8_t *data = quirc_begin(m_qr, nullptr, nullptr); 22 | m_input = {.data = data, .width = w, .height = h, .pix_type = dl::image::DL_IMAGE_PIX_TYPE_GRAY}; 23 | } 24 | 25 | protected: 26 | void task() override; 27 | 28 | private: 29 | virtual void on_new_qrcode_result(const char *result) = 0; 30 | frame_cap::WhoFrameCap *m_frame_cap; 31 | struct quirc *m_qr; 32 | dl::image::img_t m_input; 33 | }; 34 | } // namespace qrcode 35 | } // namespace who 36 | -------------------------------------------------------------------------------- /components/who_qrcode/who_qrcode_lcd.cpp: -------------------------------------------------------------------------------- 1 | #include "who_qrcode_lcd.hpp" 2 | #include "who_lvgl_utils.hpp" 3 | #if CONFIG_IDF_TARGET_ESP32P4 4 | #define WHO_QRCODE_RES_SHOW_N_FRAMES (60) 5 | #elif CONFIG_IDF_TARGET_ESP32S3 6 | #define WHO_QRCODE_RES_SHOW_N_FRAMES (30) 7 | #endif 8 | LV_FONT_DECLARE(montserrat_bold_26); 9 | LV_FONT_DECLARE(montserrat_bold_20); 10 | 11 | static const char *TAG = "WhoQRCode"; 12 | 13 | namespace who { 14 | namespace qrcode { 15 | void WhoQRCodeLCD::lcd_display_cb(who::cam::cam_fb_t *fb) 16 | { 17 | xSemaphoreTake(m_res_mutex, portMAX_DELAY); 18 | static int cnt = WHO_QRCODE_RES_SHOW_N_FRAMES; 19 | if (!m_results.empty()) { 20 | lv_label_set_text(m_label, m_results.back().c_str()); 21 | m_results.clear(); 22 | cnt = 0; 23 | } 24 | if (cnt < WHO_QRCODE_RES_SHOW_N_FRAMES && ++cnt == WHO_QRCODE_RES_SHOW_N_FRAMES) { 25 | lv_label_set_text(m_label, ""); 26 | } 27 | xSemaphoreGive(m_res_mutex); 28 | } 29 | 30 | void WhoQRCodeLCD::task() 31 | { 32 | create_label(); 33 | WhoQRCodeBase::task(); 34 | } 35 | 36 | void WhoQRCodeLCD::create_label() 37 | { 38 | bsp_display_lock(0); 39 | #if CONFIG_IDF_TARGET_ESP32S3 40 | m_label = create_lvgl_label("", &montserrat_bold_20); 41 | #elif CONFIG_IDF_TARGET_ESP32P4 42 | m_label = create_lvgl_label("", &montserrat_bold_26); 43 | #endif 44 | const lv_font_t *font = lv_obj_get_style_text_font(m_label, LV_PART_MAIN); 45 | lv_obj_set_width(m_label, BSP_LCD_H_RES - 2 * font->line_height); 46 | lv_obj_align(m_label, LV_ALIGN_TOP_LEFT, font->line_height, font->line_height); 47 | lv_label_set_long_mode(m_label, LV_LABEL_LONG_WRAP); 48 | bsp_display_unlock(); 49 | } 50 | 51 | void WhoQRCodeLCD::on_new_qrcode_result(const char *result) 52 | { 53 | ESP_LOGI(TAG, "%s", result); 54 | xSemaphoreTake(m_res_mutex, portMAX_DELAY); 55 | m_results.emplace_back(std::string(result)); 56 | xSemaphoreGive(m_res_mutex); 57 | } 58 | } // namespace qrcode 59 | } // namespace who 60 | -------------------------------------------------------------------------------- /components/who_qrcode/who_qrcode_lcd.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "who_qrcode_base.hpp" 3 | #include 4 | #include 5 | 6 | namespace who { 7 | namespace qrcode { 8 | class WhoQRCodeLCD : public WhoQRCodeBase { 9 | public: 10 | WhoQRCodeLCD(frame_cap::WhoFrameCap *frame_cap, const std::string &name) : 11 | WhoQRCodeBase(frame_cap, name), m_res_mutex(xSemaphoreCreateMutex()) 12 | { 13 | } 14 | void lcd_display_cb(who::cam::cam_fb_t *fb) override; 15 | 16 | private: 17 | void task() override; 18 | void create_label(); 19 | void on_new_qrcode_result(const char *result) override; 20 | SemaphoreHandle_t m_res_mutex; 21 | std::list m_results; 22 | lv_obj_t *m_label; 23 | }; 24 | } // namespace qrcode 25 | } // namespace who 26 | -------------------------------------------------------------------------------- /components/who_qrcode/who_qrcode_term.cpp: -------------------------------------------------------------------------------- 1 | #include "who_qrcode_term.hpp" 2 | 3 | static const char *TAG = "WhoQRCode"; 4 | 5 | namespace who { 6 | namespace qrcode { 7 | void WhoQRCodeTerm::on_new_qrcode_result(const char *result) 8 | { 9 | ESP_LOGI(TAG, "%s", result); 10 | } 11 | } // namespace qrcode 12 | } // namespace who 13 | -------------------------------------------------------------------------------- /components/who_qrcode/who_qrcode_term.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "who_qrcode_base.hpp" 3 | #include 4 | #include 5 | 6 | namespace who { 7 | namespace qrcode { 8 | class WhoQRCodeTerm : public WhoQRCodeBase { 9 | public: 10 | using WhoQRCodeBase::WhoQRCodeBase; 11 | void on_new_qrcode_result(const char *result) override; 12 | }; 13 | } // namespace qrcode 14 | } // namespace who 15 | -------------------------------------------------------------------------------- /components/who_recognition/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(src_dirs .) 2 | 3 | set(include_dirs .) 4 | 5 | set(requires who_detect 6 | human_face_recognition) 7 | 8 | idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires}) -------------------------------------------------------------------------------- /components/who_recognition/idf_component.yml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | espressif/human_face_recognition: 3 | version: "*" -------------------------------------------------------------------------------- /components/who_recognition/who_recognition.cpp: -------------------------------------------------------------------------------- 1 | #include "who_recognition.hpp" 2 | #include "who_lvgl_utils.hpp" 3 | #if CONFIG_IDF_TARGET_ESP32P4 4 | #define WHO_REC_RES_SHOW_N_FRAMES (60) 5 | #elif CONFIG_IDF_TARGET_ESP32S3 6 | #define WHO_REC_RES_SHOW_N_FRAMES (30) 7 | #endif 8 | LV_FONT_DECLARE(montserrat_bold_26); 9 | 10 | namespace who { 11 | namespace recognition { 12 | detect::WhoDetectBase::result_t WhoDetectLCD::get_result() 13 | { 14 | xSemaphoreTake(m_res_mutex, portMAX_DELAY); 15 | result_t result = m_result; 16 | xSemaphoreGive(m_res_mutex); 17 | return result; 18 | } 19 | 20 | void WhoDetectLCD::on_new_detect_result(const result_t &result) 21 | { 22 | detect::WhoDetectLCD::on_new_detect_result(result); 23 | xSemaphoreTake(m_res_mutex, portMAX_DELAY); 24 | m_result = result; 25 | xSemaphoreGive(m_res_mutex); 26 | } 27 | 28 | void WhoRecognition::task() 29 | { 30 | create_btns(); 31 | create_label(); 32 | while (true) { 33 | set_and_clear_bits(BLOCKING, RUNNING); 34 | EventBits_t event_bits = xEventGroupWaitBits( 35 | m_event_group, RECOGNIZE | ENROLL | DELETE | PAUSE | STOP, pdTRUE, pdFALSE, portMAX_DELAY); 36 | if (event_bits & STOP) { 37 | set_and_clear_bits(TERMINATE, BLOCKING); 38 | break; 39 | } else if (event_bits & PAUSE) { 40 | EventBits_t pause_event_bits = 41 | xEventGroupWaitBits(m_event_group, RESUME | STOP, pdTRUE, pdFALSE, portMAX_DELAY); 42 | if (pause_event_bits & STOP) { 43 | set_and_clear_bits(TERMINATE, BLOCKING); 44 | break; 45 | } else { 46 | continue; 47 | } 48 | } 49 | set_and_clear_bits(RUNNING, BLOCKING); 50 | m_detect->pause(); 51 | if (event_bits & (RECOGNIZE | ENROLL)) { 52 | auto result = m_detect->get_result(); 53 | auto img = who::cam::fb2img(result.fb); 54 | if (event_bits & RECOGNIZE) { 55 | auto rec_res = m_recognizer->recognize(img, result.det_res); 56 | char *text = new char[64]; 57 | if (rec_res.empty()) { 58 | strcpy(text, "who?"); 59 | } else { 60 | snprintf(text, 64, "id: %d, sim: %.2f", rec_res[0].id, rec_res[0].similarity); 61 | } 62 | xSemaphoreTake(m_res_mutex, portMAX_DELAY); 63 | m_results.emplace_back(text); 64 | xSemaphoreGive(m_res_mutex); 65 | } 66 | if (event_bits & ENROLL) { 67 | esp_err_t ret = m_recognizer->enroll(img, result.det_res); 68 | char *text = new char[64]; 69 | if (ret == ESP_FAIL) { 70 | strcpy(text, "Failed to enroll."); 71 | } else { 72 | snprintf(text, 64, "id: %d enrolled.", m_recognizer->get_num_feats()); 73 | } 74 | xSemaphoreTake(m_res_mutex, portMAX_DELAY); 75 | m_results.emplace_back(text); 76 | xSemaphoreGive(m_res_mutex); 77 | } 78 | } 79 | if (event_bits & DELETE) { 80 | esp_err_t ret = m_recognizer->delete_last_feat(); 81 | char *text = new char[64]; 82 | if (ret == ESP_FAIL) { 83 | strcpy(text, "Failed to delete."); 84 | } else { 85 | snprintf(text, 64, "id: %d deleted.", m_recognizer->get_num_feats() + 1); 86 | } 87 | xSemaphoreTake(m_res_mutex, portMAX_DELAY); 88 | m_results.emplace_back(text); 89 | xSemaphoreGive(m_res_mutex); 90 | } 91 | m_detect->resume(); 92 | } 93 | vTaskDelete(NULL); 94 | } 95 | 96 | void WhoRecognition::lvgl_btn_event_handler(lv_event_t *e) 97 | { 98 | user_data_t *user_data = reinterpret_cast(lv_event_get_user_data(e)); 99 | EventGroupHandle_t event_group = user_data->who_rec_ptr->get_event_group(); 100 | EventBits_t event_bits = xEventGroupGetBits(event_group); 101 | if (event_bits & BLOCKING && !(event_bits & PAUSE)) { 102 | xEventGroupSetBits(event_group, user_data->event); 103 | } 104 | } 105 | 106 | void WhoRecognition::iot_btn_event_handler(void *button_handle, void *usr_data) 107 | { 108 | user_data_t *user_data = reinterpret_cast(usr_data); 109 | EventGroupHandle_t event_group = user_data->who_rec_ptr->get_event_group(); 110 | EventBits_t event_bits = xEventGroupGetBits(event_group); 111 | if (event_bits & BLOCKING && !(event_bits & PAUSE)) { 112 | xEventGroupSetBits(event_group, user_data->event); 113 | } 114 | } 115 | 116 | void WhoRecognition::create_btns() 117 | { 118 | #if CONFIG_IDF_TARGET_ESP32P4 119 | bsp_display_lock(0); 120 | lv_obj_t *btn_recognize = create_lvgl_btn("recognize", &montserrat_bold_26); 121 | lv_obj_t *btn_enroll = create_lvgl_btn("enroll", &montserrat_bold_26); 122 | lv_obj_t *btn_delete = create_lvgl_btn("delete", &montserrat_bold_26); 123 | lv_obj_add_event_cb(btn_recognize, lvgl_btn_event_handler, LV_EVENT_CLICKED, (void *)m_btn_user_data); 124 | lv_obj_add_event_cb(btn_enroll, lvgl_btn_event_handler, LV_EVENT_CLICKED, (void *)(m_btn_user_data + 1)); 125 | lv_obj_add_event_cb(btn_delete, lvgl_btn_event_handler, LV_EVENT_CLICKED, (void *)(m_btn_user_data + 2)); 126 | lv_obj_update_layout(btn_recognize); 127 | lv_obj_update_layout(btn_enroll); 128 | lv_obj_update_layout(btn_delete); 129 | int32_t w = lv_obj_get_width(btn_recognize); 130 | w = std::max(w, lv_obj_get_width(btn_enroll)); 131 | w = std::max(w, lv_obj_get_width(btn_delete)); 132 | int32_t h = lv_obj_get_height(btn_recognize); 133 | lv_obj_set_size(btn_recognize, w, h); 134 | lv_obj_set_size(btn_enroll, w, h); 135 | lv_obj_set_size(btn_delete, w, h); 136 | int32_t pad = h / 2; 137 | lv_obj_align(btn_recognize, LV_ALIGN_TOP_RIGHT, -pad, pad); 138 | lv_obj_align(btn_enroll, LV_ALIGN_TOP_RIGHT, -pad, pad + h + pad); 139 | lv_obj_align(btn_delete, LV_ALIGN_TOP_RIGHT, -pad, pad + 2 * (h + pad)); 140 | bsp_display_unlock(); 141 | #elif CONFIG_IDF_TARGET_ESP32S3 142 | button_handle_t btns[BSP_BUTTON_NUM]; 143 | ESP_ERROR_CHECK(bsp_iot_button_create(btns, NULL, BSP_BUTTON_NUM)); 144 | // play recognize 145 | ESP_ERROR_CHECK( 146 | iot_button_register_cb(btns[1], BUTTON_SINGLE_CLICK, nullptr, iot_btn_event_handler, (void *)m_btn_user_data)); 147 | // up enroll 148 | ESP_ERROR_CHECK(iot_button_register_cb( 149 | btns[3], BUTTON_SINGLE_CLICK, nullptr, iot_btn_event_handler, (void *)(m_btn_user_data + 1))); 150 | // down delete 151 | ESP_ERROR_CHECK(iot_button_register_cb( 152 | btns[2], BUTTON_SINGLE_CLICK, nullptr, iot_btn_event_handler, (void *)(m_btn_user_data + 2))); 153 | #endif 154 | } 155 | 156 | void WhoRecognition::create_label() 157 | { 158 | bsp_display_lock(0); 159 | m_label = create_lvgl_label("", &montserrat_bold_26); 160 | const lv_font_t *font = lv_obj_get_style_text_font(m_label, LV_PART_MAIN); 161 | lv_obj_align(m_label, LV_ALIGN_TOP_MID, 0, font->line_height); 162 | bsp_display_unlock(); 163 | } 164 | 165 | void WhoRecognition::lcd_display_cb(who::cam::cam_fb_t *fb) 166 | { 167 | xSemaphoreTake(m_res_mutex, portMAX_DELAY); 168 | static int cnt = WHO_REC_RES_SHOW_N_FRAMES; 169 | if (!m_results.empty()) { 170 | lv_label_set_text(m_label, m_results.back()); 171 | for (auto iter = m_results.begin(); iter != m_results.end(); iter++) { 172 | delete[] *iter; 173 | } 174 | m_results.clear(); 175 | cnt = 0; 176 | } 177 | if (cnt < WHO_REC_RES_SHOW_N_FRAMES && ++cnt == WHO_REC_RES_SHOW_N_FRAMES) { 178 | lv_label_set_text(m_label, ""); 179 | } 180 | xSemaphoreGive(m_res_mutex); 181 | } 182 | 183 | } // namespace recognition 184 | } // namespace who 185 | -------------------------------------------------------------------------------- /components/who_recognition/who_recognition.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "human_face_detect.hpp" 3 | #include "human_face_recognition.hpp" 4 | #include "who_cam.hpp" 5 | #include "who_detect_lcd.hpp" 6 | #include "who_subscriber.hpp" 7 | #include "bsp/esp-bsp.h" 8 | 9 | namespace who { 10 | namespace recognition { 11 | class WhoRecognition; 12 | class WhoDetectLCD : public detect::WhoDetectLCD { 13 | friend class WhoRecognition; 14 | 15 | public: 16 | WhoDetectLCD(frame_cap::WhoFrameCap *frame_cap, 17 | dl::detect::Detect *detect, 18 | const std::string &name, 19 | const std::vector> &palette) : 20 | detect::WhoDetectLCD(frame_cap, detect, name, palette), m_res_mutex(xSemaphoreCreateMutex()) 21 | { 22 | } 23 | ~WhoDetectLCD() { vSemaphoreDelete(m_res_mutex); } 24 | detect::WhoDetectBase::result_t get_result(); 25 | 26 | private: 27 | void on_new_detect_result(const result_t &result) override; 28 | SemaphoreHandle_t m_res_mutex; 29 | result_t m_result; 30 | }; 31 | 32 | class WhoRecognition : public WhoSubscriber { 33 | public: 34 | using result_t = char *; 35 | typedef struct { 36 | WhoRecognition *who_rec_ptr; 37 | event_type_t event; 38 | } user_data_t; 39 | 40 | WhoRecognition(WhoDetectLCD *detect, HumanFaceRecognizer *recognizer, const std::string &name) : 41 | WhoSubscriber(name), m_detect(detect), m_recognizer(recognizer), m_res_mutex(xSemaphoreCreateMutex()) 42 | { 43 | m_detect->m_frame_cap->add_element(this); 44 | m_btn_user_data = new user_data_t[3]; 45 | m_btn_user_data[0] = {this, RECOGNIZE}; 46 | m_btn_user_data[1] = {this, ENROLL}; 47 | m_btn_user_data[2] = {this, DELETE}; 48 | } 49 | 50 | ~WhoRecognition() 51 | { 52 | vSemaphoreDelete(m_res_mutex); 53 | delete[] m_btn_user_data; 54 | } 55 | 56 | void task() override; 57 | void lcd_display_cb(who::cam::cam_fb_t *fb) override; 58 | 59 | private: 60 | static void lvgl_btn_event_handler(lv_event_t *e); 61 | static void iot_btn_event_handler(void *button_handle, void *usr_data); 62 | void create_btns(); 63 | void create_label(); 64 | 65 | WhoDetectLCD *m_detect; 66 | HumanFaceRecognizer *m_recognizer; 67 | 68 | SemaphoreHandle_t m_res_mutex; 69 | std::list m_results; 70 | lv_obj_t *m_label; 71 | user_data_t *m_btn_user_data; 72 | }; 73 | } // namespace recognition 74 | } // namespace who 75 | -------------------------------------------------------------------------------- /components/who_task/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(src_dirs .) 2 | 3 | set(include_dirs .) 4 | 5 | idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs}) -------------------------------------------------------------------------------- /components/who_task/who_container.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace who { 7 | template 8 | class WhoContainer { 9 | public: 10 | virtual ~WhoContainer() {} 11 | bool add_element(T element) 12 | { 13 | if constexpr (std::is_pointer_v) { 14 | if (!element) { 15 | ESP_LOGE("WhoContainer", "element is nullptr."); 16 | return false; 17 | } 18 | } 19 | auto it = std::find(m_elements.begin(), m_elements.end(), element); 20 | if constexpr (AllowExist) { 21 | if (it != m_elements.end()) { 22 | return true; 23 | } 24 | } else { 25 | if (it != m_elements.end()) { 26 | ESP_LOGE("WhoContainer", "Failed to add element, element already exists."); 27 | return false; 28 | } 29 | } 30 | m_elements.push_back(element); 31 | return true; 32 | } 33 | 34 | protected: 35 | std::vector m_elements; 36 | }; 37 | } // namespace who 38 | -------------------------------------------------------------------------------- /components/who_task/who_task.cpp: -------------------------------------------------------------------------------- 1 | #include "who_task.hpp" 2 | #include "who_yield2idle.hpp" 3 | #include 4 | 5 | static const char *TAG = "WhoTask"; 6 | 7 | namespace who { 8 | bool WhoTaskBase::run(const configSTACK_DEPTH_TYPE uxStackDepth, UBaseType_t uxPriority, const BaseType_t xCoreID) 9 | { 10 | if (xEventGroupGetBits(m_event_group) & (RUNNING | BLOCKING)) { 11 | return false; 12 | } 13 | set_and_clear_bits(RUNNING, TERMINATE); 14 | if (xTaskCreatePinnedToCore(task, m_name.c_str(), uxStackDepth, this, uxPriority, &m_task_handle, xCoreID) != 15 | pdPASS) { 16 | ESP_LOGE(TAG, "Failed to create task.\n"); 17 | set_and_clear_bits(TERMINATE, RUNNING); 18 | return false; 19 | } 20 | return true; 21 | } 22 | 23 | bool WhoTaskBase::stop() 24 | { 25 | if (xEventGroupGetBits(m_event_group) & TERMINATE) { 26 | return false; 27 | } 28 | xEventGroupSetBits(m_event_group, STOP); 29 | xEventGroupWaitBits(m_event_group, TERMINATE, pdFALSE, pdFALSE, portMAX_DELAY); 30 | return true; 31 | } 32 | 33 | bool WhoTaskBase::pause() 34 | { 35 | if (xEventGroupGetBits(m_event_group) & TERMINATE) { 36 | return false; 37 | } 38 | xEventGroupSetBits(m_event_group, PAUSE); 39 | return true; 40 | } 41 | 42 | bool WhoTaskBase::resume() 43 | { 44 | if (xEventGroupGetBits(m_event_group) & TERMINATE) { 45 | return false; 46 | } 47 | xEventGroupSetBits(m_event_group, RESUME); 48 | return true; 49 | } 50 | 51 | void WhoTaskBase::set_and_clear_bits(EventBits_t bit_to_set, EventBits_t bit_to_clear) 52 | { 53 | xEventGroupSetBits(m_event_group, bit_to_set); 54 | xEventGroupClearBits(m_event_group, bit_to_clear); 55 | } 56 | 57 | void WhoTaskBase::task(void *args) 58 | { 59 | WhoTaskBase *self = static_cast(args); 60 | self->task(); 61 | } 62 | 63 | bool WhoTask::run(const configSTACK_DEPTH_TYPE uxStackDepth, UBaseType_t uxPriority, const BaseType_t xCoreID) 64 | { 65 | // Never run other tasks when yield2idle running. 66 | auto yield2idle = WhoYield2Idle::get_instance(xCoreID); 67 | EventBits_t event_bits = 68 | xEventGroupWaitBits(yield2idle->get_event_group(), BLOCKING | TERMINATE, pdFALSE, pdFALSE, portMAX_DELAY); 69 | if (event_bits & BLOCKING) { 70 | yield2idle->monitor(this); 71 | } 72 | return WhoTaskBase::run(uxStackDepth, uxPriority, xCoreID); 73 | } 74 | 75 | } // namespace who 76 | -------------------------------------------------------------------------------- /components/who_task/who_task.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "who_container.hpp" 3 | #include 4 | #include 5 | 6 | namespace who { 7 | typedef enum { 8 | // WhoTask 9 | RUNNING = 1 << 0, 10 | BLOCKING = 1 << 1, 11 | TERMINATE = 1 << 2, 12 | STOP = 1 << 3, 13 | PAUSE = 1 << 4, 14 | RESUME = 1 << 5, 15 | WHO_TASK_LAST = 1 << 6, 16 | 17 | // WhoFramCap 18 | NEW_FRAME = 1 << 6, 19 | 20 | // WhoRecognition 21 | RECOGNIZE = 1 << 7, 22 | ENROLL = 1 << 8, 23 | DELETE = 1 << 9, 24 | } event_type_t; 25 | 26 | class WhoTaskBase { 27 | public: 28 | WhoTaskBase(const std::string &name) : m_name(name), m_event_group(xEventGroupCreate()) 29 | { 30 | xEventGroupSetBits(m_event_group, TERMINATE); 31 | } 32 | virtual ~WhoTaskBase() { vEventGroupDelete(m_event_group); } 33 | virtual bool run(const configSTACK_DEPTH_TYPE uxStackDepth, UBaseType_t uxPriority, const BaseType_t xCoreID); 34 | virtual bool stop(); 35 | virtual bool pause(); 36 | virtual bool resume(); 37 | void set_and_clear_bits(EventBits_t bit_to_clear, EventBits_t bit_to_set); 38 | std::string get_name() { return m_name; } 39 | EventGroupHandle_t get_event_group() { return m_event_group; } 40 | TaskHandle_t get_task_handle() { return m_task_handle; } 41 | 42 | protected: 43 | std::string m_name; 44 | EventGroupHandle_t m_event_group; 45 | TaskHandle_t m_task_handle; 46 | 47 | private: 48 | virtual void task() = 0; 49 | static void task(void *args); 50 | }; 51 | 52 | class WhoTask : public WhoTaskBase { 53 | public: 54 | using WhoTaskBase::WhoTaskBase; 55 | virtual bool run(const configSTACK_DEPTH_TYPE uxStackDepth, UBaseType_t uxPriority, const BaseType_t xCoreID); 56 | }; 57 | 58 | class WhoTasks : public WhoContainer { 59 | public: 60 | virtual bool run() = 0; 61 | virtual bool stop() { return operate_all(&WhoTask::stop); }; 62 | virtual bool pause() { return operate_all(&WhoTask::pause); }; 63 | virtual bool resume() { return operate_all(&WhoTask::resume); }; 64 | 65 | private: 66 | template 67 | bool operate_all(Func func) const 68 | { 69 | bool ret = true; 70 | for (const auto &element : m_elements) { 71 | ret &= (element->*func)(); 72 | } 73 | return ret; 74 | } 75 | }; 76 | } // namespace who 77 | -------------------------------------------------------------------------------- /components/who_task/who_task_state.cpp: -------------------------------------------------------------------------------- 1 | #include "who_task_state.hpp" 2 | #include 3 | 4 | namespace who { 5 | namespace task { 6 | WhoTaskState::WhoTaskState(int interval) : WhoTask("TaskState"), m_interval(interval) 7 | { 8 | m_task_state = {"Running", "Ready", "Blocked", "Suspended", "Deleted", "Invalid"}; 9 | } 10 | 11 | void WhoTaskState::task() 12 | { 13 | const TickType_t interval = pdMS_TO_TICKS(1000 * m_interval); 14 | TickType_t last_wake_time = xTaskGetTickCount(); 15 | while (true) { 16 | set_and_clear_bits(BLOCKING, RUNNING); 17 | vTaskDelayUntil(&last_wake_time, interval); 18 | EventBits_t event_bits = xEventGroupGetBits(m_event_group); 19 | if (event_bits & STOP) { 20 | set_and_clear_bits(TERMINATE, BLOCKING | STOP); 21 | break; 22 | } else if (event_bits & PAUSE) { 23 | xEventGroupClearBits(m_event_group, PAUSE); 24 | EventBits_t pause_event_bits = 25 | xEventGroupWaitBits(m_event_group, RESUME | STOP, pdTRUE, pdFALSE, portMAX_DELAY); 26 | if (pause_event_bits & STOP) { 27 | set_and_clear_bits(TERMINATE, BLOCKING); 28 | break; 29 | } 30 | } 31 | set_and_clear_bits(RUNNING, BLOCKING); 32 | print_task_status(); 33 | } 34 | vTaskDelete(NULL); 35 | } 36 | 37 | bool WhoTaskState::stop() 38 | { 39 | if (xEventGroupGetBits(m_event_group) & TERMINATE) { 40 | return false; 41 | } 42 | xEventGroupSetBits(m_event_group, STOP); 43 | xTaskAbortDelay(m_task_handle); 44 | xEventGroupWaitBits(m_event_group, TERMINATE, pdFALSE, pdFALSE, portMAX_DELAY); 45 | return true; 46 | } 47 | 48 | void WhoTaskState::print_task_status() 49 | { 50 | configRUN_TIME_COUNTER_TYPE total_run_time; 51 | UBaseType_t num_tasks = uxTaskGetNumberOfTasks(); 52 | TaskStatus_t *task_status_array = 53 | (TaskStatus_t *)heap_caps_malloc(num_tasks * sizeof(TaskStatus_t), MALLOC_CAP_SPIRAM); 54 | uxTaskGetSystemState(task_status_array, num_tasks, &total_run_time); 55 | 56 | printf("\nTask Name | coreid | State | Priority | Stack HWM | Run Time | Run Time Per |\n"); 57 | printf("----------------------------------------------------------------------------------------------\n"); 58 | 59 | for (UBaseType_t i = 0; i < num_tasks; i++) { 60 | #if CONFIG_FREERTOS_RUN_TIME_COUNTER_TYPE_U32 61 | printf("%-15s | %-8x | %-9s | %-8u | %-11lu | %-11lu | %-12lu |\n", 62 | #else 63 | printf("%-15s | %-8x | %-9s | %-8u | %-11lu | %-11llu | %-12llu |\n", 64 | #endif 65 | task_status_array[i].pcTaskName, 66 | task_status_array[i].xCoreID, 67 | m_task_state[task_status_array[i].eCurrentState].c_str(), 68 | task_status_array[i].uxCurrentPriority, 69 | task_status_array[i].usStackHighWaterMark, 70 | task_status_array[i].ulRunTimeCounter, 71 | task_status_array[i].ulRunTimeCounter * 100 / total_run_time); 72 | } 73 | printf("\n"); 74 | heap_caps_free(task_status_array); 75 | } 76 | } // namespace task 77 | } // namespace who 78 | -------------------------------------------------------------------------------- /components/who_task/who_task_state.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "who_task.hpp" 3 | #include 4 | #include 5 | 6 | namespace who { 7 | namespace task { 8 | class WhoTaskState : public WhoTask { 9 | public: 10 | WhoTaskState(int interval = 2); 11 | void task() override; 12 | bool stop() override; 13 | 14 | private: 15 | void print_task_status(); 16 | std::vector m_task_state; 17 | int m_interval; 18 | }; 19 | } // namespace task 20 | } // namespace who 21 | -------------------------------------------------------------------------------- /components/who_task/who_yield2idle.cpp: -------------------------------------------------------------------------------- 1 | #include "who_yield2idle.hpp" 2 | #include 3 | static const char *TAG = "WhoYield2Idle"; 4 | 5 | namespace who { 6 | WhoYield2Idle *WhoYield2Idle::get_instance(const BaseType_t xCoreID) 7 | { 8 | static WhoYield2Idle core0_instance("Yield2Idle0", 0); 9 | static WhoYield2Idle core1_instance("Yield2Idle1", 1); 10 | if (xCoreID == 0) { 11 | return &core0_instance; 12 | } else if (xCoreID == 1) { 13 | return &core1_instance; 14 | } else { 15 | ESP_LOGE(TAG, "Error Core id, only support 0 or 1"); 16 | return nullptr; 17 | } 18 | } 19 | 20 | bool WhoYield2Idle::run() 21 | { 22 | bool ret = who::WhoYield2Idle::get_instance(0)->run(1024, 3, 0); 23 | return ret & who::WhoYield2Idle::get_instance(1)->run(1024, 3, 1); 24 | } 25 | 26 | bool WhoYield2Idle::stop() 27 | { 28 | if (xEventGroupGetBits(m_event_group) & TERMINATE) { 29 | return false; 30 | } 31 | xEventGroupWaitBits(m_event_group, BLOCKING, pdFALSE, pdFALSE, portMAX_DELAY); 32 | xEventGroupSetBits(m_event_group, STOP); 33 | xTaskAbortDelay(m_task_handle); 34 | xEventGroupWaitBits(m_event_group, TERMINATE, pdFALSE, pdFALSE, portMAX_DELAY); 35 | return true; 36 | } 37 | 38 | bool WhoYield2Idle::monitor(WhoTask *task) 39 | { 40 | if (!add_element(task)) { 41 | return false; 42 | } 43 | WhoYield2Idle *other = (m_coreid == 0) ? get_instance(1) : get_instance(0); 44 | auto other_it = std::find(other->m_elements.begin(), other->m_elements.end(), task); 45 | if (other_it != other->m_elements.end()) { 46 | other->m_elements.erase(other_it); 47 | } 48 | return true; 49 | } 50 | 51 | void WhoYield2Idle::task() 52 | { 53 | const TickType_t interval = pdMS_TO_TICKS((CONFIG_ESP_TASK_WDT_TIMEOUT_S - 1) * 1000); 54 | TickType_t last_wake_time = xTaskGetTickCount(); 55 | while (true) { 56 | set_and_clear_bits(BLOCKING, RUNNING); 57 | vTaskDelayUntil(&last_wake_time, interval); 58 | EventBits_t event_bits = xEventGroupGetBits(m_event_group); 59 | if (event_bits & STOP) { 60 | set_and_clear_bits(TERMINATE, BLOCKING | STOP); 61 | break; 62 | } else if (event_bits & PAUSE) { 63 | xEventGroupClearBits(m_event_group, PAUSE); 64 | EventBits_t pause_event_bits = 65 | xEventGroupWaitBits(m_event_group, RESUME | STOP, pdTRUE, pdFALSE, portMAX_DELAY); 66 | if (pause_event_bits & STOP) { 67 | set_and_clear_bits(TERMINATE, BLOCKING); 68 | break; 69 | } else { 70 | last_wake_time = xTaskGetTickCount(); 71 | continue; 72 | } 73 | } 74 | set_and_clear_bits(RUNNING, BLOCKING); 75 | for (const auto &task : m_elements) { 76 | task->pause(); 77 | xEventGroupWaitBits(task->get_event_group(), BLOCKING | TERMINATE, pdFALSE, pdFALSE, portMAX_DELAY); 78 | } 79 | vTaskDelay(pdMS_TO_TICKS(10)); 80 | for (const auto &task : m_elements) { 81 | task->resume(); 82 | } 83 | } 84 | vTaskDelete(NULL); 85 | } 86 | } // namespace who 87 | -------------------------------------------------------------------------------- /components/who_task/who_yield2idle.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "who_task.hpp" 3 | #include 4 | 5 | namespace who { 6 | class WhoYield2Idle : public WhoTaskBase, public WhoContainer { 7 | public: 8 | static WhoYield2Idle *get_instance(const BaseType_t xCoreID); 9 | using WhoTaskBase::run; 10 | static bool run(); 11 | bool stop() override; 12 | bool monitor(WhoTask *task); 13 | 14 | private: 15 | WhoYield2Idle(const std::string &name, const BaseType_t xCoreID) : WhoTaskBase(name), m_coreid(xCoreID) {}; 16 | WhoYield2Idle(const WhoYield2Idle &) = delete; 17 | WhoYield2Idle &operator=(const WhoYield2Idle &) = delete; 18 | void task() override; 19 | const BaseType_t m_coreid; 20 | }; 21 | } // namespace who 22 | -------------------------------------------------------------------------------- /default_bin/esp-eye/esp-eye-bin-v1.0.0.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/default_bin/esp-eye/esp-eye-bin-v1.0.0.bin -------------------------------------------------------------------------------- /default_bin/esp32-s3-eye/v2.1/esp32-s3-eye-v2.1-firmware-v0.2.0-cn.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/default_bin/esp32-s3-eye/v2.1/esp32-s3-eye-v2.1-firmware-v0.2.0-cn.bin -------------------------------------------------------------------------------- /default_bin/esp32-s3-eye/v2.1/esp32-s3-eye-v2.1-firmware-v0.2.0-en.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/default_bin/esp32-s3-eye/v2.1/esp32-s3-eye-v2.1-firmware-v0.2.0-en.bin -------------------------------------------------------------------------------- /default_bin/esp32-s3-eye/v2.2/esp32-s3-eye-v2.2-firmware-v0.2.0-cn.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/default_bin/esp32-s3-eye/v2.2/esp32-s3-eye-v2.2-firmware-v0.2.0-cn.bin -------------------------------------------------------------------------------- /default_bin/esp32-s3-eye/v2.2/esp32-s3-eye-v2.2-firmware-v0.2.0-en.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/default_bin/esp32-s3-eye/v2.2/esp32-s3-eye-v2.2-firmware-v0.2.0-en.bin -------------------------------------------------------------------------------- /docs/_static/get-started/ESP32-S3-EYE-isometric.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/get-started/ESP32-S3-EYE-isometric.png -------------------------------------------------------------------------------- /docs/_static/get-started/ESP32-S3-EYE-v2-1-camera-ps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/get-started/ESP32-S3-EYE-v2-1-camera-ps.png -------------------------------------------------------------------------------- /docs/_static/get-started/ESP32-S3-EYE-v2-1-module-ps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/get-started/ESP32-S3-EYE-v2-1-module-ps.png -------------------------------------------------------------------------------- /docs/_static/get-started/ESP32-S3-EYE_20210913_V03_SystemBlock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/get-started/ESP32-S3-EYE_20210913_V03_SystemBlock.png -------------------------------------------------------------------------------- /docs/_static/get-started/ESP32-S3-EYE_3dpcase_btm.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/get-started/ESP32-S3-EYE_3dpcase_btm.STL -------------------------------------------------------------------------------- /docs/_static/get-started/ESP32-S3-EYE_3dpcase_top.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/get-started/ESP32-S3-EYE_3dpcase_top.STL -------------------------------------------------------------------------------- /docs/_static/get-started/ESP32-S3-EYE_MB-annotated-photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/get-started/ESP32-S3-EYE_MB-annotated-photo.png -------------------------------------------------------------------------------- /docs/_static/get-started/ESP32-S3-EYE_SUB-annotated-photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/get-started/ESP32-S3-EYE_SUB-annotated-photo.png -------------------------------------------------------------------------------- /docs/_static/get-started/S3-eye_banner_photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/get-started/S3-eye_banner_photo.png -------------------------------------------------------------------------------- /docs/_static/get-started/esp-eye_callout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/get-started/esp-eye_callout.png -------------------------------------------------------------------------------- /docs/_static/get-started/esp32-s3-eye-v2_1-marking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/get-started/esp32-s3-eye-v2_1-marking.png -------------------------------------------------------------------------------- /docs/_static/get-started/esp32-s3-eye-v2_1-resistor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/get-started/esp32-s3-eye-v2_1-resistor.png -------------------------------------------------------------------------------- /docs/_static/get-started/esp32-s3-eye-v2_2-marking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/get-started/esp32-s3-eye-v2_2-marking.png -------------------------------------------------------------------------------- /docs/_static/get-started/esp32-s3-eye-v2_2-resistor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/get-started/esp32-s3-eye-v2_2-resistor.png -------------------------------------------------------------------------------- /docs/_static/get-started/face_id_enrollment_cn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/get-started/face_id_enrollment_cn.jpg -------------------------------------------------------------------------------- /docs/_static/get-started/face_id_enrollment_en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/get-started/face_id_enrollment_en.png -------------------------------------------------------------------------------- /docs/_static/get-started/wifi_connection.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/get-started/wifi_connection.jpeg -------------------------------------------------------------------------------- /docs/_static/get-started/work_flow_cn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/get-started/work_flow_cn.jpg -------------------------------------------------------------------------------- /docs/_static/get-started/work_flow_en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/get-started/work_flow_en.png -------------------------------------------------------------------------------- /docs/_static/source-graphics/ESP32-S3-EYE_20210913_V03_SystemBlock.odg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/source-graphics/ESP32-S3-EYE_20210913_V03_SystemBlock.odg -------------------------------------------------------------------------------- /docs/_static/source-graphics/ESP32-S3-EYE_MB_V2.2 callouts.odg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/source-graphics/ESP32-S3-EYE_MB_V2.2 callouts.odg -------------------------------------------------------------------------------- /docs/_static/source-graphics/ESP32-S3-EYE_SUB_V1.1_callouts.odg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/_static/source-graphics/ESP32-S3-EYE_SUB_V1.1_callouts.odg -------------------------------------------------------------------------------- /docs/docs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/docs/docs.png -------------------------------------------------------------------------------- /docs/en/Camera_connections.md: -------------------------------------------------------------------------------- 1 | 2 | # Connecting 3 | 4 | The table below lists the specific pins used in this example for connecting the ESP32 module and the camera module. 5 | 6 | | Interface | Camera Pin | ESP-EYE | 7 | | :--- | :---: | :---: | 8 | | SCCB Clock | SIOC | IO23 | 9 | | SCCB Data | SIOD | IO18 | 10 | | System Clock | XCLK | IO4 | 11 | | Vertical Sync | VSYNC | IO5 | 12 | | Horizontal Reference | HREF | IO27 | 13 | | Pixel Clock | PCLK | IO25 | 14 | | Pixel Data Bit 0 | D2 | IO34 | 15 | | Pixel Data Bit 1 | D3 | IO13 | 16 | | Pixel Data Bit 2 | D4 | IO14 | 17 | | Pixel Data Bit 3 | D5 | IO35 | 18 | | Pixel Data Bit 4 | D6 | IO39 | 19 | | Pixel Data Bit 5 | D7 | IO38 | 20 | | Pixel Data Bit 6 | D8 | IO37 | 21 | | Pixel Data Bit 7 | D9 | IO36 | 22 | | Camera Reset | RESET | -1 | 23 | | Camera Power Down | PWDN | -1 | 24 | | Power Supply 3.3V | 3V3 | 3v3 | 25 | | Ground | GND | GND | 26 | 27 | > The pin mapping will be slightly different if you use other ESP32 modules. 28 | 29 | -------------------------------------------------------------------------------- /docs/en/get-started/ESP-EYE_Getting_Started_Guide.md: -------------------------------------------------------------------------------- 1 | # ESP-EYE Getting Started Guide 2 | 3 | [[中文]](../../zh_CN/get-started/ESP-EYE_Getting_Started_Guide.md) 4 | 5 | ## What You Need 6 | 7 | * 1 × ESP-EYE V2.1 board 8 | * 1 × Micro USB cable 9 | * 1 × PC with Windows, Linux or Mac OS 10 | 11 | ## Overview 12 | 13 | ESP-EYE is an ESP32-based development board that integrates a digital microphone, an 8 MB PSRAM and a 4 MB flash, while also providing an external 2-Megapixel camera. These features make the board ideal for applications relating to face detection, face recognition and speech recognition. Besides, the board can also support image transmission over Wi-Fi and debugging through a Micro USB port, which enables the development of advanced AI solutions. 14 | 15 | ## Hardware Preparation 16 | 17 | The list and figure below describe the key components, interfaces and functions of the ESP-EYE development board: 18 | 19 | ![ESP-EYE image](../../_static/get-started/esp-eye_callout.png) 20 | 21 | * **3D_PIFA Antenna** 22 | 23 | A 3D PIFA antenna. With the R14 resistor users can select the external IPEX antenna, whereas with the R15 resistor they can select the 3D antenna. 24 | 25 | * **IPEX Connector** 26 | 27 | Used for connecting the external IPEX antenna. With the R14 resistor users can select the external IPEX antenna, whereas with the R15 resistor they can select the 3D antenna. 28 | 29 | * **ESP32 Chip** 30 | 31 | A 2.4 GHz Wi-Fi and Bluetooth combo chip. 32 | 33 | * **Crystal Oscillator** 34 | 35 | Provides an external clock to ESP32. 36 | 37 | * **Flash & PSRAM** 38 | 39 | Provides memory for storing applications. 40 | 41 | * **CP2102 USB-to-UART Chip** 42 | 43 | Converts the USB signals to UART signals. 44 | 45 | * **USB Port** 46 | 47 | Provides power supply to the whole system. 48 | 49 | * **LDO Power Supply** 50 | 51 | Provides the required power supply to the ESP32 chip, camera and LED indicators. 52 | 53 | * **Side Tactile Button** 54 | 55 | A function key. 56 | 57 | * **Top Tactile Button** 58 | 59 | Reset/Boot button. We recommend that you do not configure this button for other uses. 60 | 61 | * **LED Indicators** 62 | 63 | The board has a red and a white indicator. Different flashing combinations of the red and white indicators reflect the different statuses of the board, e.g. waking up, networking, face detection, face recognition, face enrollment and face recognition. 64 | 65 | * **Camera** 66 | 67 | An external 2-Megapixel camera module for face detection, face recognition and Face ID enrollment. 68 | 69 | * **Camera Connector** 70 | 71 | Used for connecting the external camera. 72 | 73 | * **MIC** 74 | 75 | A digital microphone for voice control functions. 76 | 77 | * **SPI Port** 78 | 79 | A reserved port for data transmission. 80 | 81 | 82 | -------------------------------------------------------------------------------- /docs/zh_CN/get-started/ESP-EYE_Getting_Started_Guide.md: -------------------------------------------------------------------------------- 1 | # ESP-EYE 入门指南 2 | 3 | [[EN]](../../en/get-started/ESP-EYE_Getting_Started_Guide.md) 4 | 5 | ## 准备工作 6 | 7 | * 1 × ESP-EYE V2.1 开发板 8 | * 1 × Micro USB B 电缆 9 | * 1 × PC(Windows、Linux 或 Mac OS) 10 | 11 | ## 简介 12 | 13 | ESP-EYE 是一款面向人脸识别和语音识别市场的开发板,搭载 ESP32 芯片、200 W 像素摄像头、数字麦克风、8 MB PSRAM 和 4 MB Flash,可满足各种 AI 应用开发需求。此外,该开发板还支持 Wi-Fi 图像传输、Micro USB 调试和供电,可以实现语音唤醒、人脸检测与识别等功能,可协助用户开发高度集成的 AI 解决方案。 14 | 15 | ## 硬件组成 16 | 17 | ESP-EYE 开发板的产品图请见下方: 18 | 19 | ![ESP-EYE image](../../_static/get-started/esp-eye_callout.png) 20 | 21 | 具体包括以下硬件组成: 22 | 23 | * **3D_PIFA Antenna(3D_PIFA 天线)** 24 | 25 | 3D PIFA 天线。用户可通过选贴 R14/R15 电阻,选用 3D 天线(选贴 R15)或外接 IPEX 天线(选贴 R14)。 26 | 27 | * **IPEX Connector(IPEX 连接器)** 28 | 29 | 用于外接 IPEX 天线。用户可通过选贴 R14/R15 电阻,选用 3D 天线(选贴 R15)或外接 IPEX 天线(选贴 R14)。 30 | 31 | * **ESP32 Chip(ESP32 芯片)** 32 | 33 | 集成 2.4 GHz Wi-Fi 和蓝牙双模的单芯片。 34 | 35 | * **Crystal(晶振)** 36 | 37 | ESP32 的外部晶振时钟源。 38 | 39 | * **Flash & PSRAM** 40 | 41 | 存储芯片,用于储存程序。 42 | 43 | * **CP2102 USB-UART Chip(USB 转 UART 芯片)** 44 | 45 | 实现 USB 到 UART 的转换功能。 46 | 47 | * **USB Port(USB 供电接口)** 48 | 49 | 为整个系统供电。 50 | 51 | * **LDO Power Supply(LDO 供电芯片)** 52 | 53 | 为 ESP32 芯片、摄像头、LED 指示灯等部件提供各自所需的电压。 54 | 55 | * **Side Tactile Button(侧面轻触按键)** 56 | 57 | 功能按键。 58 | 59 | * **Top Tactile Button(正面轻触按键)** 60 | 61 | 用于 ESP32 的 RST(复位)、BOOT(下载),不建议设置他用。 62 | 63 | * **LED 指示灯** 64 | 65 | 红灯和白灯各一个,可用于指示唤醒、联网、人脸检测、人脸录入、人脸识别等不同过程中的状态。 66 | 67 | * **Camera(摄像头)** 68 | 69 | 实现检测识别等功能。 70 | 71 | * **Camera Connector(摄像头连接器)** 72 | 73 | 用于外接摄像头模块。 74 | 75 | * **MIC(麦克风)** 76 | 77 | 数字型麦克风,实现语音控制功能。 78 | 79 | * **SPI Port(SPI 接口)** 80 | 81 | 预留数据传输接口。 82 | 83 | 84 | ## 软件开发 85 | 86 | ESP-EYE 可在 Linux、MacOs、Windows 操作系统中完成软件烧写。目前,必须进行开发环境的工具链配置,详见下方介绍。 87 | 88 | ### 准备工作 89 | 90 | - 阅读 [ESP-IDF编程指南](https://docs.espressif.com/projects/esp-idf/zh_CN/v3.1.1/get-started/index.html),参考相应章节,配置工具链; 91 | - 准备 Micro USB 线,用于连接 PC 和 ESP-EYE 开发板; 92 | - 选择一款适合开发环境的工具,例如 Terminal (Linux/MacOS) 或 MinGW (Windows) 等。 93 | 94 | ### 软件获取 95 | 96 | 打开终端(例如 Linux 环境下的 Terminal),将软件代码克隆到本地: 97 | 98 | ``` 99 | git clone --recursive https://github.com/espressif/esp-who.git 100 | ``` 101 | 102 | 执行以上命令会默认生成一个 `esp-who` 的文件夹。 103 | 104 | > 注意不要忘记 `--recursive` 选项。如果你克隆 ESP-IDF 时没有带这个选项,你还需要运进入相应文件夹中,执行以下命令下载相应的子模块: 105 | ``` 106 | git submodule update --init --recursive 107 | ``` 108 | 109 | ### 设置路径 110 | 111 | 请参考[设置路径](https://docs.espressif.com/projects/esp-idf/zh_CN/v3.1.1/get-started/index.html#get-started-setup-path)章节,将 `IDF_PATH` 设置为 `esp-who/esp-idf`。 112 | 113 | ### 软件烧写 114 | 115 | 下面,我们以 Linux 环境为例,介绍向 ESP-EYE 烧写程序的过程: 116 | 117 | - 首先将 ESP-EYE 接入 PC,接入即上电; 118 | - 通过命令 `ls /dev/ttyUSB*` 查看开发板是否成功接入 PC。成功接入后,列表将新增类似 `/dev/ttyUSB0` 的信息; 119 | - 进入一个 example 工程文件中,例如 `cd esp-who/examples/single_chip/recognition_solution`; 120 | - 执行 `make defconfig` 进行默认配置; 121 | - 执行 `make menuconfig`,在 `Serial flasher config` 中设置 `Default serial port` 设备名称(与第二步查看的设备名称一致,一般设置为 `/dev/ttyUSB0`),保存退出; 122 | - 执行 `make flash`,进行软件烧写。 123 | 124 | ### 终端获取日志 125 | 126 | 下面,我们以 Linux 环境为例,介绍如何查看日志: 127 | 128 | - 打开终端; 129 | - 执行 `make monitor`。 130 | 131 | > 注意:这个过程会重启开发板。 132 | 133 | ### 交互功能 134 | 135 | ESP-EYE 开发板的工作流程如下图所示: 136 | 137 | ![esp-eye-workflow](../../_static/get-started/work_flow_cn.jpg) 138 | 139 | 140 | #### 1. 语音唤醒 141 | 142 | 开发板上电后,会进入“等待唤醒”状态(红灯常亮、白灯常灭),需要用户通过语音进行唤醒。支持“Hi 乐鑫”唤醒,当用户说出“Hi 乐鑫”的唤醒词后,开发板唤醒并进入“等待联网”状态(红灯闪烁,白灯常灭)。此时,用户可进行联网操作。 143 | 144 | #### 2. 连接网络 145 | 146 | 用户可通过 PC、手机等设备,连接 ESP-EYE 创建的 Wi-Fi 热点。该热点的默认信息如下: 147 | 148 | - 用户名:esp-eye-xxxx(xxxx 为设备 MAC 地址) 149 | - 密码:无需密码 150 | 151 | 用户也可通过如下方式,自行设置用户名和密码: 152 | 153 | - 打开终端; 154 | - 执行 `make menuconfig`,并按照下图进行设置: 155 | 156 | ![wifi connection](../../_static/get-started/wifi_connection.jpeg) 157 | 158 | > 注:用户重新设置 Wi-Fi 热点的用户名和密码后,需要重新进行软件烧录。 159 | 160 | #### 3. 人脸检测 161 | 162 | 联网成功后,ESP-EYE 会进行“人脸检测”。用户可以打开浏览器,输入地址 `192.168.4.1/face_stream`,在网页上即可看到实时图像信息。此时,开发板红灯熄灭、白灯常亮。 163 | 164 | #### 4. 人脸识别 165 | 166 | 当开发板检测到人脸时,如已存在录入的 Face ID,则开发板将进行“人脸识别”: 167 | 168 | - “人脸识别”匹配成功 -- 开发板红灯闪烁 1 次,网页显示 **HELLO ID XXX** 169 | - “人脸识别”匹配失败 -- 开发板无反应,网页显示 **WHO?**” 170 | 171 | 否则,开发板仅进行“人脸检测”。此时,若用户希望使用人脸识别功能,则请首先录入至少一个 Face ID。 172 | 173 | #### 5. 人脸录入与删除 174 | 175 | 在联网成功的前提下,可通过摄像头采集人脸,录入 Face ID。 176 | 177 | ##### 5.1 录入 Face ID 178 | 179 | ![录入 Face ID](../../_static/get-started/face_id_enrollment_cn.jpg) 180 | 181 | - 用户单击侧面轻触按键,可进入“录入 Face ID”(红灯常亮),网页显示: **START ENROLLING**; 182 | - 用户面对摄像头,开始采集人像。每次成功一次采集,开发板将红灯闪烁,网页显示对应的采集次数,比如 **THE 1st SAMPLE** 等。默认情况下,用户每录入一个 Face ID 需要采集 3 次人像(可配置)。在人像采集过程中,如果红灯长时间未闪烁,建议用户调整姿态和角度,然后再试; 183 | - 人像采集完成后,开发板红灯常灭,表明已完成录入该 Face ID。此时,网页显示:**ENROLLED FACE ID xxx**; 184 | - Face ID 录入成功后,系统将返回“人脸检测”。 185 | 186 | 目前,ESP-EYE 开发板默认可录入 10 个 Face ID(可配置,具体与用户的 flash 内存分配有关)。 187 | 188 | ##### 5.2 删除 Face ID 189 | 190 | - 用户单击表面BOOT按键,进入“删除 FACE ID”; 191 | - 双击后,开发板白灯闪烁,系统将自动删除系统中存在的最早一条 FACE ID,终端显示:**XXX ID(S) LEFT**。 192 | 193 | #### 异常情况 194 | 195 | 当出现“网络断开”或“联网超时”等异常情况时,开发板会回到“等待唤醒”状态。 196 | -------------------------------------------------------------------------------- /examples/human_face_detect/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The following lines of boilerplate have to be in your project's 2 | # CMakeLists in this exact order for cmake to work correctly 3 | cmake_minimum_required(VERSION 3.5) 4 | 5 | set(EXTRA_COMPONENT_DIRS ../../components/who_task 6 | ../../components/who_peripherals/who_cam 7 | ../../components/who_peripherals/who_lcd 8 | ../../components/who_frame_cap 9 | ../../components/who_detect 10 | ../../components/who_app/who_detect_app) 11 | 12 | add_compile_options(-fdiagnostics-color=always) 13 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 14 | idf_build_set_property(DEPENDENCIES_LOCK dependencies.lock.${IDF_TARGET}) 15 | project(human_face_detect) 16 | -------------------------------------------------------------------------------- /examples/human_face_detect/dependencies.lock.esp32p4: -------------------------------------------------------------------------------- 1 | dependencies: 2 | espressif/cmake_utilities: 3 | component_hash: 351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f 4 | dependencies: 5 | - name: idf 6 | require: private 7 | version: '>=4.1' 8 | source: 9 | registry_url: https://components.espressif.com 10 | type: service 11 | version: 0.5.3 12 | espressif/esp-dl: 13 | component_hash: f451adb8650cf7cbfd94001d07099190cc15273156fc53f748a1288b727c48cb 14 | dependencies: 15 | - name: espressif/esp_jpeg 16 | registry_url: https://components.espressif.com 17 | require: private 18 | version: ^1.0.5~3 19 | - name: idf 20 | require: private 21 | version: '>=5.3' 22 | source: 23 | registry_url: https://components.espressif.com/ 24 | type: service 25 | targets: 26 | - esp32s3 27 | - esp32p4 28 | version: 3.1.2 29 | espressif/esp32_p4_function_ev_board_noglib: 30 | component_hash: 00c80e12ee9d3f056f63437c1a868ac887a8a4e9cdca95b7a08eefca0322f734 31 | dependencies: 32 | - name: espressif/esp_codec_dev 33 | registry_url: https://components.espressif.com 34 | require: public 35 | version: 1.2.* 36 | - name: espressif/esp_lcd_ek79007 37 | registry_url: https://components.espressif.com 38 | require: private 39 | version: 1.* 40 | - name: espressif/esp_lcd_ili9881c 41 | registry_url: https://components.espressif.com 42 | require: private 43 | version: 1.* 44 | - name: espressif/esp_lcd_touch_gt911 45 | registry_url: https://components.espressif.com 46 | require: private 47 | version: ^1 48 | - name: espressif/esp_lcd_lt8912b 49 | registry_url: https://components.espressif.com 50 | require: private 51 | version: '>=0.1.1,<1.0.0' 52 | - name: idf 53 | require: private 54 | version: '>=5.3' 55 | source: 56 | registry_url: https://components.espressif.com/ 57 | type: service 58 | targets: 59 | - esp32p4 60 | version: 5.0.0 61 | espressif/esp_cam_sensor: 62 | component_hash: 7b110b08542aeae833895dacd74425e926dd36eed68ae1a26f2b6109e04ea984 63 | dependencies: 64 | - name: espressif/cmake_utilities 65 | registry_url: https://components.espressif.com 66 | require: private 67 | version: 0.* 68 | - name: espressif/esp_sccb_intf 69 | registry_url: https://components.espressif.com 70 | require: private 71 | version: '>=0.0.2' 72 | - name: idf 73 | require: private 74 | version: '>=5.3' 75 | source: 76 | registry_url: https://components.espressif.com 77 | type: service 78 | targets: 79 | - esp32p4 80 | version: 0.9.0 81 | espressif/esp_codec_dev: 82 | component_hash: 014948481bda426cd46714f297fe1891711246c62bea288863a8cc8cf13ef1f0 83 | dependencies: 84 | - name: idf 85 | require: private 86 | version: '>=4.0' 87 | source: 88 | registry_url: https://components.espressif.com 89 | type: service 90 | version: 1.2.0 91 | espressif/esp_h264: 92 | component_hash: fa5daaebc8a304f0b79bc57e51aab43e0a03eabc2ba3865bff4063c56b5d4564 93 | dependencies: 94 | - name: idf 95 | require: private 96 | version: '>=4.4' 97 | source: 98 | registry_url: https://components.espressif.com/ 99 | type: service 100 | version: 1.0.4 101 | espressif/esp_ipa: 102 | component_hash: 7547b050a99351a85aaba8ba38211c36fd4769c2ae3e570fa330dc90dfd2704c 103 | dependencies: 104 | - name: espressif/cmake_utilities 105 | registry_url: https://components.espressif.com 106 | require: private 107 | version: 0.* 108 | - name: idf 109 | require: private 110 | version: '>=5.4' 111 | source: 112 | registry_url: https://components.espressif.com 113 | type: service 114 | targets: 115 | - esp32p4 116 | version: 0.2.0 117 | espressif/esp_jpeg: 118 | component_hash: fdddaa1ceeee223e0abd7e865b05dbceea7ff175440a5ea26eeff8304564e7aa 119 | dependencies: 120 | - name: idf 121 | require: private 122 | version: '>=5.0' 123 | source: 124 | registry_url: https://components.espressif.com 125 | type: service 126 | version: 1.3.0 127 | espressif/esp_lcd_ek79007: 128 | component_hash: 07c1afab7e9fd4dd2fd06ff9245e65327c5bbd5485efec199496e19a9304d47b 129 | dependencies: 130 | - name: espressif/cmake_utilities 131 | registry_url: https://components.espressif.com 132 | require: private 133 | version: 0.* 134 | - name: idf 135 | require: private 136 | version: '>=5.3' 137 | source: 138 | registry_url: https://components.espressif.com 139 | type: service 140 | targets: 141 | - esp32p4 142 | version: 1.0.2 143 | espressif/esp_lcd_ili9881c: 144 | component_hash: f4f374226b62baf13f735864e8fae58e17c537df34d598e059f6caad4761ef65 145 | dependencies: 146 | - name: idf 147 | require: private 148 | version: '>=5.3' 149 | source: 150 | registry_url: https://components.espressif.com 151 | type: service 152 | targets: 153 | - esp32p4 154 | version: 1.0.1 155 | espressif/esp_lcd_lt8912b: 156 | component_hash: 232578085e67a0fe1a22d58f290ba5c10959d9a247022bec561500b5661fb360 157 | dependencies: 158 | - name: idf 159 | require: private 160 | version: '>=5.3' 161 | source: 162 | registry_url: https://components.espressif.com 163 | type: service 164 | version: 0.1.1 165 | espressif/esp_lcd_touch: 166 | component_hash: 779b4ba2464a3ae85681e4b860caa5fdc35801458c23f3039ee761bae7f442a4 167 | dependencies: 168 | - name: idf 169 | require: private 170 | version: '>=4.4.2' 171 | source: 172 | registry_url: https://components.espressif.com 173 | type: service 174 | version: 1.1.2 175 | espressif/esp_lcd_touch_gt911: 176 | component_hash: acc1c184358aa29ef72506f618c9c76a8cc2bf12af38a2bff3d44d84f3a08857 177 | dependencies: 178 | - name: espressif/esp_lcd_touch 179 | registry_url: https://components.espressif.com 180 | require: public 181 | version: ^1.1.0 182 | - name: idf 183 | require: private 184 | version: '>=4.4.2' 185 | source: 186 | registry_url: https://components.espressif.com 187 | type: service 188 | version: 1.1.3 189 | espressif/esp_sccb_intf: 190 | component_hash: 71e3def402f6193a23c599bdde4fa0b544ca2b1f63608b6d0ec2bee3cd9a1c33 191 | dependencies: 192 | - name: idf 193 | require: private 194 | version: '>=5.3' 195 | source: 196 | registry_url: https://components.espressif.com 197 | type: service 198 | version: 0.0.5 199 | espressif/esp_video: 200 | component_hash: 37f7a3b16aa842e612180d5a4698db1c3bc36142a0b78664eb4ffe67c8cd0510 201 | dependencies: 202 | - name: espressif/cmake_utilities 203 | registry_url: https://components.espressif.com 204 | require: private 205 | version: 0.* 206 | - name: espressif/esp_cam_sensor 207 | registry_url: https://components.espressif.com 208 | require: private 209 | version: 0.9.* 210 | - name: espressif/esp_h264 211 | registry_url: https://components.espressif.com 212 | require: private 213 | version: '>=1.0.3' 214 | - name: espressif/esp_ipa 215 | registry_url: https://components.espressif.com 216 | require: private 217 | version: 0.2.* 218 | - name: idf 219 | require: private 220 | version: '>=5.4' 221 | source: 222 | registry_url: https://components.espressif.com/ 223 | type: service 224 | targets: 225 | - esp32p4 226 | version: 0.8.0~3 227 | espressif/human_face_detect: 228 | component_hash: cba8a6be8221aa08618e2ffb8087f732210731f1f3e6f17e025a81ae413b139f 229 | dependencies: 230 | - name: espressif/esp-dl 231 | registry_url: https://components.espressif.com 232 | require: private 233 | version: ^3.1.1 234 | source: 235 | registry_url: https://components.espressif.com/ 236 | type: service 237 | version: 0.2.2 238 | idf: 239 | source: 240 | type: idf 241 | version: 5.4.0 242 | direct_dependencies: 243 | - espressif/esp-dl 244 | - espressif/esp32_p4_function_ev_board_noglib 245 | - espressif/esp_h264 246 | - espressif/esp_video 247 | - espressif/human_face_detect 248 | - idf 249 | manifest_hash: ff42149b30f1ba67b26ebd94317f72a369fe0ddfd576aa293e4d197c2ce5b648 250 | target: esp32p4 251 | version: 2.0.0 252 | -------------------------------------------------------------------------------- /examples/human_face_detect/dependencies.lock.esp32s3: -------------------------------------------------------------------------------- 1 | dependencies: 2 | espressif/button: 3 | component_hash: f53face2ab21fa0ffaf4cf0f6e513d393f56df6586bb2ad1146120f03f19ee05 4 | dependencies: 5 | - name: espressif/cmake_utilities 6 | registry_url: https://components.espressif.com 7 | require: private 8 | version: '*' 9 | - name: idf 10 | require: private 11 | version: '>=4.0' 12 | source: 13 | registry_url: https://components.espressif.com 14 | type: service 15 | version: 4.1.3 16 | espressif/cmake_utilities: 17 | component_hash: 351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f 18 | dependencies: 19 | - name: idf 20 | require: private 21 | version: '>=4.1' 22 | source: 23 | registry_url: https://components.espressif.com 24 | type: service 25 | version: 0.5.3 26 | espressif/esp-dl: 27 | component_hash: f451adb8650cf7cbfd94001d07099190cc15273156fc53f748a1288b727c48cb 28 | dependencies: 29 | - name: espressif/esp_jpeg 30 | registry_url: https://components.espressif.com 31 | require: private 32 | version: ^1.0.5~3 33 | - name: idf 34 | require: private 35 | version: '>=5.3' 36 | source: 37 | registry_url: https://components.espressif.com/ 38 | type: service 39 | targets: 40 | - esp32s3 41 | - esp32p4 42 | version: 3.1.2 43 | espressif/esp32-camera: 44 | component_hash: c3eb05fbeeae884a23bed9b17d48d5f0da8872beadae0c0e747d2fbea6094f06 45 | dependencies: [] 46 | source: 47 | registry_url: https://components.espressif.com 48 | type: service 49 | version: 2.0.15 50 | espressif/esp32_s3_eye_noglib: 51 | component_hash: 270a15b503a9977bf394dd5cc659f12adc05663bb9ac24bbc104c8a95cb58fe9 52 | dependencies: 53 | - name: espressif/button 54 | registry_url: https://components.espressif.com 55 | require: public 56 | version: ^4 57 | - name: espressif/esp32-camera 58 | registry_url: https://components.espressif.com 59 | require: public 60 | version: ^2.0.13 61 | - name: espressif/esp_codec_dev 62 | registry_url: https://components.espressif.com 63 | require: public 64 | version: ~1.3.1 65 | - name: idf 66 | require: private 67 | version: '>=5.4' 68 | - name: espressif/qma6100p 69 | registry_url: https://components.espressif.com 70 | require: public 71 | version: ^2 72 | source: 73 | registry_url: https://components.espressif.com/ 74 | type: service 75 | targets: 76 | - esp32s3 77 | version: 5.0.0 78 | espressif/esp_codec_dev: 79 | component_hash: 18c22e1411224ba6103c4aca1b01bc740af33926756e9e106370a477d52bcba1 80 | dependencies: 81 | - name: idf 82 | require: private 83 | version: '>=4.0' 84 | source: 85 | registry_url: https://components.espressif.com 86 | type: service 87 | version: 1.3.4 88 | espressif/esp_jpeg: 89 | component_hash: fdddaa1ceeee223e0abd7e865b05dbceea7ff175440a5ea26eeff8304564e7aa 90 | dependencies: 91 | - name: idf 92 | require: private 93 | version: '>=5.0' 94 | source: 95 | registry_url: https://components.espressif.com 96 | type: service 97 | version: 1.3.0 98 | espressif/human_face_detect: 99 | component_hash: cba8a6be8221aa08618e2ffb8087f732210731f1f3e6f17e025a81ae413b139f 100 | dependencies: 101 | - name: espressif/esp-dl 102 | registry_url: https://components.espressif.com 103 | require: private 104 | version: ^3.1.1 105 | source: 106 | registry_url: https://components.espressif.com/ 107 | type: service 108 | version: 0.2.2 109 | espressif/qma6100p: 110 | component_hash: dee71383df1d07ad56557eccf8b6f6de3689bee5afc14e353f9149299daf5ca5 111 | dependencies: 112 | - name: espressif/cmake_utilities 113 | registry_url: https://components.espressif.com 114 | require: private 115 | version: 0.* 116 | - name: idf 117 | require: private 118 | version: '>=5.2' 119 | source: 120 | registry_url: https://components.espressif.com 121 | type: service 122 | version: 2.0.0 123 | idf: 124 | source: 125 | type: idf 126 | version: 5.4.0 127 | direct_dependencies: 128 | - espressif/esp-dl 129 | - espressif/esp32_s3_eye_noglib 130 | - espressif/human_face_detect 131 | - idf 132 | manifest_hash: ff42149b30f1ba67b26ebd94317f72a369fe0ddfd576aa293e4d197c2ce5b648 133 | target: esp32s3 134 | version: 2.0.0 135 | -------------------------------------------------------------------------------- /examples/human_face_detect/main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(src_dirs ./) 2 | 3 | set(include_dirs ./) 4 | 5 | set(requires who_detect_app 6 | human_face_detect) 7 | 8 | idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires}) 9 | -------------------------------------------------------------------------------- /examples/human_face_detect/main/app_main.cpp: -------------------------------------------------------------------------------- 1 | #include "human_face_detect.hpp" 2 | #include "who_detect_app.hpp" 3 | 4 | using namespace who::cam; 5 | using namespace who::lcd; 6 | using namespace who::app; 7 | 8 | #define WITH_LCD 1 9 | 10 | extern "C" void app_main(void) 11 | { 12 | #if CONFIG_HUMAN_FACE_DETECT_MODEL_IN_SDCARD 13 | ESP_ERROR_CHECK(bsp_sdcard_mount()); 14 | #endif 15 | 16 | #if CONFIG_IDF_TARGET_ESP32S3 17 | ESP_ERROR_CHECK(bsp_leds_init()); 18 | ESP_ERROR_CHECK(bsp_led_set(BSP_LED_GREEN, false)); 19 | #endif 20 | 21 | #if CONFIG_IDF_TARGET_ESP32P4 22 | auto cam = new WhoP4Cam(VIDEO_PIX_FMT_RGB565, 3, V4L2_MEMORY_USERPTR, true); 23 | // auto cam = new WhoP4PPACam(VIDEO_PIX_FMT_RGB565, 4, V4L2_MEMORY_USERPTR, 160, 120, true); 24 | #elif CONFIG_IDF_TARGET_ESP32S3 25 | auto cam = new WhoS3Cam(PIXFORMAT_RGB565, FRAMESIZE_240X240, 2, true); 26 | #endif 27 | auto lcd = new WhoLCD(); 28 | 29 | #if WITH_LCD 30 | auto model = new HumanFaceDetect(); 31 | auto detect = new WhoDetectAppLCD({{255, 0, 0}}); 32 | detect->set_cam(cam); 33 | detect->set_model(model); 34 | detect->set_lcd(lcd); 35 | // detect->set_fps(5); 36 | detect->run(); 37 | #else 38 | auto model = new HumanFaceDetect(); 39 | auto detect = new WhoDetectAppTerm(); 40 | detect->set_cam(cam); 41 | detect->set_model(model); 42 | // detect->set_fps(5); 43 | detect->run(); 44 | #endif 45 | } 46 | -------------------------------------------------------------------------------- /examples/human_face_detect/main/idf_component.yml: -------------------------------------------------------------------------------- 1 | ## IDF Component Manager Manifest File 2 | dependencies: 3 | espressif/human_face_detect: 4 | version: "*" -------------------------------------------------------------------------------- /examples/human_face_detect/partitions.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild 3 | 4 | nvs, data, nvs, 0x9000, 24K, 5 | phy_init, data, phy, 0xf000, 4K, 6 | factory, app, factory, 0x010000, 8000K, 7 | -------------------------------------------------------------------------------- /examples/human_face_detect/partitions2.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild 3 | 4 | nvs, data, nvs, 0x9000, 24K, 5 | phy_init, data, phy, 0xf000, 4K, 6 | factory, app, factory, 0x010000, 2000K, 7 | human_face_det, data, spiffs, , 200K, 8 | -------------------------------------------------------------------------------- /examples/human_face_detect/sdkconfig.defaults: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/examples/human_face_detect/sdkconfig.defaults -------------------------------------------------------------------------------- /examples/human_face_detect/sdkconfig.defaults.esp32p4: -------------------------------------------------------------------------------- 1 | # This file was generated using idf.py save-defconfig. It can be edited manually. 2 | # Espressif IoT Development Framework (ESP-IDF) 5.5.0 Project Minimal Configuration 3 | # 4 | CONFIG_IDF_TARGET="esp32p4" 5 | CONFIG_ESPTOOLPY_FLASHMODE_QIO=y 6 | CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y 7 | CONFIG_PARTITION_TABLE_CUSTOM=y 8 | CONFIG_COMPILER_OPTIMIZATION_PERF=y 9 | CONFIG_SPIRAM=y 10 | CONFIG_SPIRAM_SPEED_200M=y 11 | CONFIG_SPIRAM_XIP_FROM_PSRAM=y 12 | CONFIG_CACHE_L2_CACHE_256KB=y 13 | CONFIG_CACHE_L2_CACHE_LINE_128B=y 14 | CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=n 15 | CONFIG_FATFS_LFN_HEAP=y 16 | CONFIG_FREERTOS_HZ=1000 17 | CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y 18 | CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y 19 | CONFIG_FREERTOS_RUN_TIME_COUNTER_TYPE_U64=y 20 | CONFIG_BSP_SD_FORMAT_ON_MOUNT_FAIL=y 21 | CONFIG_CAMERA_SC2336=y 22 | CONFIG_CAMERA_SC2336_MIPI_RAW8_1024x600_30FPS=y 23 | CONFIG_ESP_VIDEO_ENABLE_ISP_PIPELINE_CONTROLLER=y 24 | CONFIG_IDF_EXPERIMENTAL_FEATURES=y 25 | -------------------------------------------------------------------------------- /examples/human_face_detect/sdkconfig.defaults.esp32s3: -------------------------------------------------------------------------------- 1 | # This file was generated using idf.py save-defconfig. It can be edited manually. 2 | # Espressif IoT Development Framework (ESP-IDF) 5.5.0 Project Minimal Configuration 3 | # 4 | CONFIG_IDF_TARGET="esp32s3" 5 | CONFIG_ESPTOOLPY_FLASHMODE_QIO=y 6 | CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y 7 | CONFIG_PARTITION_TABLE_CUSTOM=y 8 | CONFIG_COMPILER_OPTIMIZATION_PERF=y 9 | CONFIG_SPIRAM=y 10 | CONFIG_SPIRAM_MODE_OCT=y 11 | CONFIG_SPIRAM_XIP_FROM_PSRAM=y 12 | CONFIG_SPIRAM_SPEED_80M=y 13 | CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y 14 | CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB=y 15 | CONFIG_ESP32S3_DATA_CACHE_64KB=y 16 | CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y 17 | CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=n 18 | CONFIG_FATFS_LFN_HEAP=y 19 | CONFIG_FREERTOS_HZ=1000 20 | CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y 21 | CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y 22 | CONFIG_FREERTOS_RUN_TIME_COUNTER_TYPE_U64=y 23 | CONFIG_BSP_SD_FORMAT_ON_MOUNT_FAIL=y 24 | -------------------------------------------------------------------------------- /examples/human_face_recognition/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The following lines of boilerplate have to be in your project's 2 | # CMakeLists in this exact order for cmake to work correctly 3 | cmake_minimum_required(VERSION 3.5) 4 | 5 | set(EXTRA_COMPONENT_DIRS ../../components/who_peripherals/who_cam 6 | ../../components/who_peripherals/who_lcd 7 | ../../components/who_peripherals/who_spiflash_fatfs 8 | ../../components/who_task 9 | ../../components/who_frame_cap 10 | ../../components/who_detect 11 | ../../components/who_recognition 12 | ../../components/who_app/who_recognition_app) 13 | 14 | add_compile_options(-fdiagnostics-color=always) 15 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 16 | idf_build_set_property(DEPENDENCIES_LOCK dependencies.lock.${IDF_TARGET}) 17 | project(human_face_recognition) 18 | -------------------------------------------------------------------------------- /examples/human_face_recognition/README.md: -------------------------------------------------------------------------------- 1 | | Supported Targets | ESP32-P4 | 2 | | ----------------- | -------- | 3 | 4 | 5 | # Human Face Recognition Example 6 | 7 | ### Interaction 8 | 9 | #### ESP-S3-EYE 10 | 11 | Physical buttons 12 | 13 | | btn | opertion | 14 | |------|------------------| 15 | | play | recognize | 16 | | up | enroll | 17 | | down | delete last feat | 18 | 19 | #### ESP32-P4-Function-EV-Board 20 | 21 | Touch screen buttons 22 | 23 | | btn | opertion | 24 | |-----------|------------------| 25 | | recognize | recognize | 26 | | enroll | enroll | 27 | | delete | delete last feat | 28 | 29 | -------------------------------------------------------------------------------- /examples/human_face_recognition/dependencies.lock.esp32s3: -------------------------------------------------------------------------------- 1 | dependencies: 2 | espressif/button: 3 | component_hash: f53face2ab21fa0ffaf4cf0f6e513d393f56df6586bb2ad1146120f03f19ee05 4 | dependencies: 5 | - name: espressif/cmake_utilities 6 | registry_url: https://components.espressif.com 7 | require: private 8 | version: '*' 9 | - name: idf 10 | require: private 11 | version: '>=4.0' 12 | source: 13 | registry_url: https://components.espressif.com 14 | type: service 15 | version: 4.1.3 16 | espressif/cmake_utilities: 17 | component_hash: 351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f 18 | dependencies: 19 | - name: idf 20 | require: private 21 | version: '>=4.1' 22 | source: 23 | registry_url: https://components.espressif.com 24 | type: service 25 | version: 0.5.3 26 | espressif/esp-dl: 27 | component_hash: f451adb8650cf7cbfd94001d07099190cc15273156fc53f748a1288b727c48cb 28 | dependencies: 29 | - name: espressif/esp_jpeg 30 | registry_url: https://components.espressif.com 31 | require: private 32 | version: ^1.0.5~3 33 | - name: idf 34 | require: private 35 | version: '>=5.3' 36 | source: 37 | registry_url: https://components.espressif.com/ 38 | type: service 39 | targets: 40 | - esp32s3 41 | - esp32p4 42 | version: 3.1.2 43 | espressif/esp32-camera: 44 | component_hash: c3eb05fbeeae884a23bed9b17d48d5f0da8872beadae0c0e747d2fbea6094f06 45 | dependencies: [] 46 | source: 47 | registry_url: https://components.espressif.com 48 | type: service 49 | version: 2.0.15 50 | espressif/esp32_s3_eye_noglib: 51 | component_hash: 270a15b503a9977bf394dd5cc659f12adc05663bb9ac24bbc104c8a95cb58fe9 52 | dependencies: 53 | - name: espressif/button 54 | registry_url: https://components.espressif.com 55 | require: public 56 | version: ^4 57 | - name: espressif/esp32-camera 58 | registry_url: https://components.espressif.com 59 | require: public 60 | version: ^2.0.13 61 | - name: espressif/esp_codec_dev 62 | registry_url: https://components.espressif.com 63 | require: public 64 | version: ~1.3.1 65 | - name: idf 66 | require: private 67 | version: '>=5.4' 68 | - name: espressif/qma6100p 69 | registry_url: https://components.espressif.com 70 | require: public 71 | version: ^2 72 | source: 73 | registry_url: https://components.espressif.com/ 74 | type: service 75 | targets: 76 | - esp32s3 77 | version: 5.0.0 78 | espressif/esp_codec_dev: 79 | component_hash: 18c22e1411224ba6103c4aca1b01bc740af33926756e9e106370a477d52bcba1 80 | dependencies: 81 | - name: idf 82 | require: private 83 | version: '>=4.0' 84 | source: 85 | registry_url: https://components.espressif.com 86 | type: service 87 | version: 1.3.4 88 | espressif/esp_jpeg: 89 | component_hash: fdddaa1ceeee223e0abd7e865b05dbceea7ff175440a5ea26eeff8304564e7aa 90 | dependencies: 91 | - name: idf 92 | require: private 93 | version: '>=5.0' 94 | source: 95 | registry_url: https://components.espressif.com 96 | type: service 97 | version: 1.3.0 98 | espressif/esp_lvgl_port: 99 | component_hash: e720c95cf0667554a204591bb5fade4655fb2990465557041200fa44b5bc7556 100 | dependencies: 101 | - name: idf 102 | require: private 103 | version: '>=4.4' 104 | - name: lvgl/lvgl 105 | registry_url: https://components.espressif.com 106 | require: public 107 | version: '>=8,<10' 108 | source: 109 | registry_url: https://components.espressif.com/ 110 | type: service 111 | version: 2.6.0 112 | espressif/human_face_detect: 113 | component_hash: cba8a6be8221aa08618e2ffb8087f732210731f1f3e6f17e025a81ae413b139f 114 | dependencies: 115 | - name: espressif/esp-dl 116 | registry_url: https://components.espressif.com 117 | require: private 118 | version: ^3.1.1 119 | source: 120 | registry_url: https://components.espressif.com 121 | type: service 122 | version: 0.2.2 123 | espressif/human_face_recognition: 124 | component_hash: 6e158c3501d53d6fa65c2ea35194fd43dc2994d9f3b032798c544657664223b6 125 | dependencies: 126 | - name: espressif/human_face_detect 127 | registry_url: https://components.espressif.com 128 | require: private 129 | version: ^0.2.1 130 | source: 131 | registry_url: https://components.espressif.com/ 132 | type: service 133 | version: 0.2.2 134 | espressif/qma6100p: 135 | component_hash: dee71383df1d07ad56557eccf8b6f6de3689bee5afc14e353f9149299daf5ca5 136 | dependencies: 137 | - name: espressif/cmake_utilities 138 | registry_url: https://components.espressif.com 139 | require: private 140 | version: 0.* 141 | - name: idf 142 | require: private 143 | version: '>=5.2' 144 | source: 145 | registry_url: https://components.espressif.com 146 | type: service 147 | version: 2.0.0 148 | idf: 149 | source: 150 | type: idf 151 | version: 5.4.0 152 | lvgl/lvgl: 153 | component_hash: 096c69af22eaf8a2b721e3913da91918c5e6bf1a762a113ec01f401aa61337a0 154 | dependencies: [] 155 | source: 156 | registry_url: https://components.espressif.com 157 | type: service 158 | version: 9.2.2 159 | direct_dependencies: 160 | - espressif/esp-dl 161 | - espressif/esp32_s3_eye_noglib 162 | - espressif/esp_lvgl_port 163 | - espressif/human_face_recognition 164 | - idf 165 | manifest_hash: 40f12dea6eb8d013bdf75319cc6425d959451fd3a01e33b855533ccc886afc4c 166 | target: esp32s3 167 | version: 2.0.0 168 | -------------------------------------------------------------------------------- /examples/human_face_recognition/main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(src_dirs ./) 2 | 3 | set(include_dirs ./) 4 | 5 | set(requires who_spiflash_fatfs 6 | who_recognition_app) 7 | 8 | idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires}) 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/human_face_recognition/main/app_main.cpp: -------------------------------------------------------------------------------- 1 | #include "who_recognition_app.hpp" 2 | #include "who_spiflash_fatfs.hpp" 3 | 4 | using namespace who::cam; 5 | using namespace who::lcd; 6 | using namespace who::app; 7 | 8 | extern "C" void app_main(void) 9 | { 10 | #if CONFIG_DB_FATFS_FLASH 11 | ESP_ERROR_CHECK(fatfs_flash_mount()); 12 | #elif CONFIG_DB_SPIFFS 13 | ESP_ERROR_CHECK(bsp_spiffs_mount()); 14 | #endif 15 | #if CONFIG_DB_FATFS_SDCARD || CONFIG_HUMAN_FACE_DETECT_MODEL_IN_SDCARD || CONFIG_HUMAN_FACE_FEAT_MODEL_IN_SDCARD 16 | ESP_ERROR_CHECK(bsp_sdcard_mount()); 17 | #endif 18 | 19 | #if CONFIG_IDF_TARGET_ESP32S3 20 | ESP_ERROR_CHECK(bsp_leds_init()); 21 | ESP_ERROR_CHECK(bsp_led_set(BSP_LED_GREEN, false)); 22 | #endif 23 | 24 | #if CONFIG_IDF_TARGET_ESP32P4 25 | auto cam = new WhoP4Cam(VIDEO_PIX_FMT_RGB565, 3, V4L2_MEMORY_USERPTR, true); 26 | // auto cam = new WhoP4PPACam(VIDEO_PIX_FMT_RGB565, 4, V4L2_MEMORY_USERPTR, 160, 120, true); 27 | #elif CONFIG_IDF_TARGET_ESP32S3 28 | auto cam = new WhoS3Cam(PIXFORMAT_RGB565, FRAMESIZE_240X240, 2, true); 29 | #endif 30 | auto lcd = new WhoLCD(); 31 | 32 | auto recognition = new WhoRecognitionApp(); 33 | recognition->set_cam(cam); 34 | recognition->set_lcd(lcd); 35 | recognition->run(); 36 | } 37 | -------------------------------------------------------------------------------- /examples/human_face_recognition/main/idf_component.yml: -------------------------------------------------------------------------------- 1 | ## IDF Component Manager Manifest File 2 | dependencies: 3 | espressif/esp_lvgl_port: "*" -------------------------------------------------------------------------------- /examples/human_face_recognition/partitions.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild 3 | 4 | nvs, data, nvs, 0x9000, 24K, 5 | phy_init, data, phy, 0xf000, 4K, 6 | factory, app, factory, 0x010000, 7000K, 7 | storage, data, fat, , 1M, 8 | -------------------------------------------------------------------------------- /examples/human_face_recognition/partitions2.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild 3 | 4 | nvs, data, nvs, 0x9000, 24K, 5 | phy_init, data, phy, 0xf000, 4K, 6 | factory, app, factory, 0x010000, 1900K, 7 | human_face_det, data, spiffs, , 200K, 8 | human_face_feat, data, spiffs, , 5000K, 9 | storage, data, fat, , 1M, 10 | -------------------------------------------------------------------------------- /examples/human_face_recognition/sdkconfig.defaults: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/examples/human_face_recognition/sdkconfig.defaults -------------------------------------------------------------------------------- /examples/human_face_recognition/sdkconfig.defaults.esp32p4: -------------------------------------------------------------------------------- 1 | # This file was generated using idf.py save-defconfig. It can be edited manually. 2 | # Espressif IoT Development Framework (ESP-IDF) 5.5.0 Project Minimal Configuration 3 | # 4 | CONFIG_IDF_TARGET="esp32p4" 5 | CONFIG_ESPTOOLPY_FLASHMODE_QIO=y 6 | CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y 7 | CONFIG_PARTITION_TABLE_CUSTOM=y 8 | CONFIG_COMPILER_OPTIMIZATION_PERF=y 9 | CONFIG_SPIRAM=y 10 | CONFIG_SPIRAM_SPEED_200M=y 11 | CONFIG_SPIRAM_XIP_FROM_PSRAM=y 12 | CONFIG_CACHE_L2_CACHE_256KB=y 13 | CONFIG_CACHE_L2_CACHE_LINE_128B=y 14 | CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=n 15 | CONFIG_FATFS_LFN_HEAP=y 16 | CONFIG_FREERTOS_HZ=1000 17 | CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y 18 | CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y 19 | CONFIG_FREERTOS_RUN_TIME_COUNTER_TYPE_U64=y 20 | CONFIG_BSP_SD_FORMAT_ON_MOUNT_FAIL=y 21 | CONFIG_BSP_SPIFFS_FORMAT_ON_MOUNT_FAIL=y 22 | CONFIG_BSP_LCD_DPI_BUFFER_NUMS=2 23 | CONFIG_BSP_DISPLAY_LVGL_AVOID_TEAR=y 24 | CONFIG_CAMERA_SC2336=y 25 | CONFIG_CAMERA_SC2336_MIPI_RAW8_1024x600_30FPS=y 26 | CONFIG_ESP_VIDEO_ENABLE_ISP_PIPELINE_CONTROLLER=y 27 | CONFIG_IDF_EXPERIMENTAL_FEATURES=y -------------------------------------------------------------------------------- /examples/human_face_recognition/sdkconfig.defaults.esp32s3: -------------------------------------------------------------------------------- 1 | # This file was generated using idf.py save-defconfig. It can be edited manually. 2 | # Espressif IoT Development Framework (ESP-IDF) 5.5.0 Project Minimal Configuration 3 | # 4 | CONFIG_IDF_TARGET="esp32s3" 5 | CONFIG_ESPTOOLPY_FLASHMODE_QIO=y 6 | CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y 7 | CONFIG_PARTITION_TABLE_CUSTOM=y 8 | CONFIG_COMPILER_OPTIMIZATION_PERF=y 9 | CONFIG_SPIRAM=y 10 | CONFIG_SPIRAM_MODE_OCT=y 11 | CONFIG_SPIRAM_XIP_FROM_PSRAM=y 12 | CONFIG_SPIRAM_SPEED_80M=y 13 | CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y 14 | CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB=y 15 | CONFIG_ESP32S3_DATA_CACHE_64KB=y 16 | CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y 17 | CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=n 18 | CONFIG_FATFS_LFN_HEAP=y 19 | CONFIG_FREERTOS_HZ=1000 20 | CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y 21 | CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y 22 | CONFIG_FREERTOS_RUN_TIME_COUNTER_TYPE_U64=y 23 | CONFIG_BSP_SPIFFS_FORMAT_ON_MOUNT_FAIL=y 24 | CONFIG_BSP_SD_FORMAT_ON_MOUNT_FAIL=y 25 | -------------------------------------------------------------------------------- /examples/pedestrian_detect/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The following lines of boilerplate have to be in your project's 2 | # CMakeLists in this exact order for cmake to work correctly 3 | cmake_minimum_required(VERSION 3.5) 4 | 5 | set(EXTRA_COMPONENT_DIRS ../../components/who_task 6 | ../../components/who_peripherals/who_cam 7 | ../../components/who_peripherals/who_lcd 8 | ../../components/who_frame_cap 9 | ../../components/who_detect 10 | ../../components/who_app/who_detect_app) 11 | 12 | add_compile_options(-fdiagnostics-color=always) 13 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 14 | idf_build_set_property(DEPENDENCIES_LOCK dependencies.lock.${IDF_TARGET}) 15 | project(pedestrian_detect) 16 | -------------------------------------------------------------------------------- /examples/pedestrian_detect/dependencies.lock.esp32s3: -------------------------------------------------------------------------------- 1 | dependencies: 2 | espressif/button: 3 | component_hash: f53face2ab21fa0ffaf4cf0f6e513d393f56df6586bb2ad1146120f03f19ee05 4 | dependencies: 5 | - name: espressif/cmake_utilities 6 | registry_url: https://components.espressif.com 7 | require: private 8 | version: '*' 9 | - name: idf 10 | require: private 11 | version: '>=4.0' 12 | source: 13 | registry_url: https://components.espressif.com 14 | type: service 15 | version: 4.1.3 16 | espressif/cmake_utilities: 17 | component_hash: 351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f 18 | dependencies: 19 | - name: idf 20 | require: private 21 | version: '>=4.1' 22 | source: 23 | registry_url: https://components.espressif.com 24 | type: service 25 | version: 0.5.3 26 | espressif/esp-dl: 27 | component_hash: f451adb8650cf7cbfd94001d07099190cc15273156fc53f748a1288b727c48cb 28 | dependencies: 29 | - name: espressif/esp_jpeg 30 | registry_url: https://components.espressif.com 31 | require: private 32 | version: ^1.0.5~3 33 | - name: idf 34 | require: private 35 | version: '>=5.3' 36 | source: 37 | registry_url: https://components.espressif.com/ 38 | type: service 39 | targets: 40 | - esp32s3 41 | - esp32p4 42 | version: 3.1.2 43 | espressif/esp32-camera: 44 | component_hash: c3eb05fbeeae884a23bed9b17d48d5f0da8872beadae0c0e747d2fbea6094f06 45 | dependencies: [] 46 | source: 47 | registry_url: https://components.espressif.com 48 | type: service 49 | version: 2.0.15 50 | espressif/esp32_s3_eye_noglib: 51 | component_hash: 270a15b503a9977bf394dd5cc659f12adc05663bb9ac24bbc104c8a95cb58fe9 52 | dependencies: 53 | - name: espressif/button 54 | registry_url: https://components.espressif.com 55 | require: public 56 | version: ^4 57 | - name: espressif/esp32-camera 58 | registry_url: https://components.espressif.com 59 | require: public 60 | version: ^2.0.13 61 | - name: espressif/esp_codec_dev 62 | registry_url: https://components.espressif.com 63 | require: public 64 | version: ~1.3.1 65 | - name: idf 66 | require: private 67 | version: '>=5.4' 68 | - name: espressif/qma6100p 69 | registry_url: https://components.espressif.com 70 | require: public 71 | version: ^2 72 | source: 73 | registry_url: https://components.espressif.com/ 74 | type: service 75 | targets: 76 | - esp32s3 77 | version: 5.0.0 78 | espressif/esp_codec_dev: 79 | component_hash: 18c22e1411224ba6103c4aca1b01bc740af33926756e9e106370a477d52bcba1 80 | dependencies: 81 | - name: idf 82 | require: private 83 | version: '>=4.0' 84 | source: 85 | registry_url: https://components.espressif.com 86 | type: service 87 | version: 1.3.4 88 | espressif/esp_jpeg: 89 | component_hash: fdddaa1ceeee223e0abd7e865b05dbceea7ff175440a5ea26eeff8304564e7aa 90 | dependencies: 91 | - name: idf 92 | require: private 93 | version: '>=5.0' 94 | source: 95 | registry_url: https://components.espressif.com 96 | type: service 97 | version: 1.3.0 98 | espressif/pedestrian_detect: 99 | component_hash: bb65e7192026bb9369eac7445a80e156ba5a8cb9264a5f254db0308248bf103c 100 | dependencies: 101 | - name: espressif/esp-dl 102 | registry_url: https://components.espressif.com 103 | require: private 104 | version: ^3.1.1 105 | source: 106 | registry_url: https://components.espressif.com/ 107 | type: service 108 | version: 0.2.2 109 | espressif/qma6100p: 110 | component_hash: dee71383df1d07ad56557eccf8b6f6de3689bee5afc14e353f9149299daf5ca5 111 | dependencies: 112 | - name: espressif/cmake_utilities 113 | registry_url: https://components.espressif.com 114 | require: private 115 | version: 0.* 116 | - name: idf 117 | require: private 118 | version: '>=5.2' 119 | source: 120 | registry_url: https://components.espressif.com 121 | type: service 122 | version: 2.0.0 123 | idf: 124 | source: 125 | type: idf 126 | version: 5.4.0 127 | direct_dependencies: 128 | - espressif/esp-dl 129 | - espressif/esp32_s3_eye_noglib 130 | - espressif/pedestrian_detect 131 | - idf 132 | manifest_hash: 657c1d66365a4ca506f5423ce87ec71ecf53bc356afb93092a896db885b0e584 133 | target: esp32s3 134 | version: 2.0.0 135 | -------------------------------------------------------------------------------- /examples/pedestrian_detect/main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(src_dirs ./) 2 | 3 | set(include_dirs ./) 4 | 5 | set(requires who_detect_app 6 | pedestrian_detect) 7 | 8 | idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires}) 9 | -------------------------------------------------------------------------------- /examples/pedestrian_detect/main/app_main.cpp: -------------------------------------------------------------------------------- 1 | #include "pedestrian_detect.hpp" 2 | #include "who_detect_app.hpp" 3 | 4 | using namespace who::cam; 5 | using namespace who::lcd; 6 | using namespace who::app; 7 | 8 | #define WITH_LCD 1 9 | 10 | extern "C" void app_main(void) 11 | { 12 | #if CONFIG_PEDESTRIAN_DETECT_MODEL_IN_SDCARD 13 | ESP_ERROR_CHECK(bsp_sdcard_mount()); 14 | #endif 15 | 16 | #if CONFIG_IDF_TARGET_ESP32S3 17 | ESP_ERROR_CHECK(bsp_leds_init()); 18 | ESP_ERROR_CHECK(bsp_led_set(BSP_LED_GREEN, false)); 19 | #endif 20 | 21 | #if CONFIG_IDF_TARGET_ESP32P4 22 | auto cam = new WhoP4Cam(VIDEO_PIX_FMT_RGB565, 3, V4L2_MEMORY_USERPTR, true); 23 | // auto cam = new WhoP4PPACam(VIDEO_PIX_FMT_RGB565, 4, V4L2_MEMORY_USERPTR, 224, 224, true); 24 | #elif CONFIG_IDF_TARGET_ESP32S3 25 | auto cam = new WhoS3Cam(PIXFORMAT_RGB565, FRAMESIZE_240X240, 2, true); 26 | #endif 27 | auto lcd = new WhoLCD(); 28 | 29 | #if WITH_LCD 30 | auto model = new PedestrianDetect(); 31 | auto detect = new WhoDetectAppLCD({{255, 0, 0}}); 32 | detect->set_cam(cam); 33 | detect->set_lcd(lcd); 34 | detect->set_model(model); 35 | // detect->set_fps(5); 36 | detect->run(); 37 | #else 38 | auto model = new PedestrianDetect(); 39 | auto detect = new WhoDetectAppTerm(); 40 | detect->set_cam(cam); 41 | detect->set_model(model); 42 | // detect->set_fps(5); 43 | detect->run(); 44 | #endif 45 | } 46 | -------------------------------------------------------------------------------- /examples/pedestrian_detect/main/idf_component.yml: -------------------------------------------------------------------------------- 1 | ## IDF Component Manager Manifest File 2 | dependencies: 3 | espressif/pedestrian_detect: 4 | version: "*" -------------------------------------------------------------------------------- /examples/pedestrian_detect/partitions.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild 3 | 4 | nvs, data, nvs, 0x9000, 24K, 5 | phy_init, data, phy, 0xf000, 4K, 6 | factory, app, factory, 0x010000, 8000K, 7 | -------------------------------------------------------------------------------- /examples/pedestrian_detect/partitions2.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild 3 | 4 | nvs, data, nvs, 0x9000, 24K, 5 | phy_init, data, phy, 0xf000, 4K, 6 | factory, app, factory, 0x010000, 2000K, 7 | pedestrian_det, data, spiffs, , 500K, 8 | -------------------------------------------------------------------------------- /examples/pedestrian_detect/sdkconfig.defaults: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/examples/pedestrian_detect/sdkconfig.defaults -------------------------------------------------------------------------------- /examples/pedestrian_detect/sdkconfig.defaults.esp32p4: -------------------------------------------------------------------------------- 1 | # This file was generated using idf.py save-defconfig. It can be edited manually. 2 | # Espressif IoT Development Framework (ESP-IDF) 5.5.0 Project Minimal Configuration 3 | # 4 | CONFIG_IDF_TARGET="esp32p4" 5 | CONFIG_ESPTOOLPY_FLASHMODE_QIO=y 6 | CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y 7 | CONFIG_PARTITION_TABLE_CUSTOM=y 8 | CONFIG_COMPILER_OPTIMIZATION_PERF=y 9 | CONFIG_SPIRAM=y 10 | CONFIG_SPIRAM_SPEED_200M=y 11 | CONFIG_SPIRAM_XIP_FROM_PSRAM=y 12 | CONFIG_CACHE_L2_CACHE_256KB=y 13 | CONFIG_CACHE_L2_CACHE_LINE_128B=y 14 | CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=n 15 | CONFIG_FATFS_LFN_HEAP=y 16 | CONFIG_FREERTOS_HZ=1000 17 | CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y 18 | CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y 19 | CONFIG_FREERTOS_RUN_TIME_COUNTER_TYPE_U64=y 20 | CONFIG_BSP_SD_FORMAT_ON_MOUNT_FAIL=y 21 | CONFIG_CAMERA_SC2336=y 22 | CONFIG_CAMERA_SC2336_MIPI_RAW8_1024x600_30FPS=y 23 | CONFIG_ESP_VIDEO_ENABLE_ISP_PIPELINE_CONTROLLER=y 24 | CONFIG_IDF_EXPERIMENTAL_FEATURES=y 25 | -------------------------------------------------------------------------------- /examples/pedestrian_detect/sdkconfig.defaults.esp32s3: -------------------------------------------------------------------------------- 1 | # This file was generated using idf.py save-defconfig. It can be edited manually. 2 | # Espressif IoT Development Framework (ESP-IDF) 5.5.0 Project Minimal Configuration 3 | # 4 | CONFIG_IDF_TARGET="esp32s3" 5 | CONFIG_ESPTOOLPY_FLASHMODE_QIO=y 6 | CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y 7 | CONFIG_PARTITION_TABLE_CUSTOM=y 8 | CONFIG_COMPILER_OPTIMIZATION_PERF=y 9 | CONFIG_SPIRAM=y 10 | CONFIG_SPIRAM_MODE_OCT=y 11 | CONFIG_SPIRAM_XIP_FROM_PSRAM=y 12 | CONFIG_SPIRAM_SPEED_80M=y 13 | CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y 14 | CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB=y 15 | CONFIG_ESP32S3_DATA_CACHE_64KB=y 16 | CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y 17 | CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=n 18 | CONFIG_FATFS_LFN_HEAP=y 19 | CONFIG_FREERTOS_HZ=1000 20 | CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y 21 | CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y 22 | CONFIG_FREERTOS_RUN_TIME_COUNTER_TYPE_U64=y 23 | CONFIG_BSP_SD_FORMAT_ON_MOUNT_FAIL=y 24 | -------------------------------------------------------------------------------- /examples/qrcode_recognition/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The following lines of boilerplate have to be in your project's 2 | # CMakeLists in this exact order for cmake to work correctly 3 | cmake_minimum_required(VERSION 3.5) 4 | 5 | set(EXTRA_COMPONENT_DIRS ../../components/who_task 6 | ../../components/who_peripherals/who_cam 7 | ../../components/who_peripherals/who_lcd 8 | ../../components/who_frame_cap 9 | ../../components/who_qrcode 10 | ../../components/who_app/who_qrcode_app) 11 | 12 | add_compile_options(-fdiagnostics-color=always) 13 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 14 | idf_build_set_property(DEPENDENCIES_LOCK dependencies.lock.${IDF_TARGET}) 15 | project(qrcode_recognition) 16 | -------------------------------------------------------------------------------- /examples/qrcode_recognition/dependencies.lock.esp32s3: -------------------------------------------------------------------------------- 1 | dependencies: 2 | espressif/button: 3 | component_hash: f53face2ab21fa0ffaf4cf0f6e513d393f56df6586bb2ad1146120f03f19ee05 4 | dependencies: 5 | - name: espressif/cmake_utilities 6 | registry_url: https://components.espressif.com 7 | require: private 8 | version: '*' 9 | - name: idf 10 | require: private 11 | version: '>=4.0' 12 | source: 13 | registry_url: https://components.espressif.com 14 | type: service 15 | version: 4.1.3 16 | espressif/cmake_utilities: 17 | component_hash: 351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f 18 | dependencies: 19 | - name: idf 20 | require: private 21 | version: '>=4.1' 22 | source: 23 | registry_url: https://components.espressif.com 24 | type: service 25 | version: 0.5.3 26 | espressif/esp-dl: 27 | component_hash: f451adb8650cf7cbfd94001d07099190cc15273156fc53f748a1288b727c48cb 28 | dependencies: 29 | - name: espressif/esp_jpeg 30 | registry_url: https://components.espressif.com 31 | require: private 32 | version: ^1.0.5~3 33 | - name: idf 34 | require: private 35 | version: '>=5.3' 36 | source: 37 | registry_url: https://components.espressif.com/ 38 | type: service 39 | targets: 40 | - esp32s3 41 | - esp32p4 42 | version: 3.1.2 43 | espressif/esp32-camera: 44 | component_hash: c3eb05fbeeae884a23bed9b17d48d5f0da8872beadae0c0e747d2fbea6094f06 45 | dependencies: [] 46 | source: 47 | registry_url: https://components.espressif.com 48 | type: service 49 | version: 2.0.15 50 | espressif/esp32_s3_eye_noglib: 51 | component_hash: 270a15b503a9977bf394dd5cc659f12adc05663bb9ac24bbc104c8a95cb58fe9 52 | dependencies: 53 | - name: espressif/button 54 | registry_url: https://components.espressif.com 55 | require: public 56 | version: ^4 57 | - name: espressif/esp32-camera 58 | registry_url: https://components.espressif.com 59 | require: public 60 | version: ^2.0.13 61 | - name: espressif/esp_codec_dev 62 | registry_url: https://components.espressif.com 63 | require: public 64 | version: ~1.3.1 65 | - name: idf 66 | require: private 67 | version: '>=5.4' 68 | - name: espressif/qma6100p 69 | registry_url: https://components.espressif.com 70 | require: public 71 | version: ^2 72 | source: 73 | registry_url: https://components.espressif.com/ 74 | type: service 75 | targets: 76 | - esp32s3 77 | version: 5.0.0 78 | espressif/esp_codec_dev: 79 | component_hash: 18c22e1411224ba6103c4aca1b01bc740af33926756e9e106370a477d52bcba1 80 | dependencies: 81 | - name: idf 82 | require: private 83 | version: '>=4.0' 84 | source: 85 | registry_url: https://components.espressif.com 86 | type: service 87 | version: 1.3.4 88 | espressif/esp_jpeg: 89 | component_hash: fdddaa1ceeee223e0abd7e865b05dbceea7ff175440a5ea26eeff8304564e7aa 90 | dependencies: 91 | - name: idf 92 | require: private 93 | version: '>=5.0' 94 | source: 95 | registry_url: https://components.espressif.com 96 | type: service 97 | version: 1.3.0 98 | espressif/esp_lvgl_port: 99 | component_hash: e720c95cf0667554a204591bb5fade4655fb2990465557041200fa44b5bc7556 100 | dependencies: 101 | - name: idf 102 | require: private 103 | version: '>=4.4' 104 | - name: lvgl/lvgl 105 | registry_url: https://components.espressif.com 106 | require: public 107 | version: '>=8,<10' 108 | source: 109 | registry_url: https://components.espressif.com/ 110 | type: service 111 | version: 2.6.0 112 | espressif/qma6100p: 113 | component_hash: dee71383df1d07ad56557eccf8b6f6de3689bee5afc14e353f9149299daf5ca5 114 | dependencies: 115 | - name: espressif/cmake_utilities 116 | registry_url: https://components.espressif.com 117 | require: private 118 | version: 0.* 119 | - name: idf 120 | require: private 121 | version: '>=5.2' 122 | source: 123 | registry_url: https://components.espressif.com 124 | type: service 125 | version: 2.0.0 126 | espressif/quirc: 127 | component_hash: 3be250a06364f0d71a7903b66ac93084d2ce3998c2e75a168b9f1f0621dd6218 128 | dependencies: 129 | - name: idf 130 | require: private 131 | version: '>=4.3.0' 132 | source: 133 | registry_url: https://components.espressif.com/ 134 | type: service 135 | version: 1.2.0 136 | idf: 137 | source: 138 | type: idf 139 | version: 5.4.0 140 | lvgl/lvgl: 141 | component_hash: 096c69af22eaf8a2b721e3913da91918c5e6bf1a762a113ec01f401aa61337a0 142 | dependencies: [] 143 | source: 144 | registry_url: https://components.espressif.com 145 | type: service 146 | version: 9.2.2 147 | direct_dependencies: 148 | - espressif/esp-dl 149 | - espressif/esp32_s3_eye_noglib 150 | - espressif/esp_lvgl_port 151 | - espressif/quirc 152 | - idf 153 | manifest_hash: 924cd9d1f65456c78a55760760b7465d4fd0e7ddb24f892bc5d950952f847972 154 | target: esp32s3 155 | version: 2.0.0 156 | -------------------------------------------------------------------------------- /examples/qrcode_recognition/main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(src_dirs ./) 2 | 3 | set(include_dirs ./) 4 | 5 | set(requires who_qrcode_app) 6 | 7 | idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires}) 8 | -------------------------------------------------------------------------------- /examples/qrcode_recognition/main/app_main.cpp: -------------------------------------------------------------------------------- 1 | #include "who_qrcode_app.hpp" 2 | 3 | using namespace who::cam; 4 | using namespace who::lcd; 5 | using namespace who::app; 6 | 7 | #define WITH_LCD 1 8 | 9 | extern "C" void app_main(void) 10 | { 11 | #if CONFIG_IDF_TARGET_ESP32S3 12 | ESP_ERROR_CHECK(bsp_leds_init()); 13 | ESP_ERROR_CHECK(bsp_led_set(BSP_LED_GREEN, false)); 14 | #endif 15 | 16 | #if CONFIG_IDF_TARGET_ESP32P4 17 | auto cam = new WhoP4Cam(VIDEO_PIX_FMT_RGB565, 3, V4L2_MEMORY_USERPTR, true); 18 | #elif CONFIG_IDF_TARGET_ESP32S3 19 | auto cam = new WhoS3Cam(PIXFORMAT_RGB565, FRAMESIZE_240X240, 2, true); 20 | #endif 21 | 22 | #if WITH_LCD 23 | auto lcd = new WhoLCD(); 24 | auto qrcode = new WhoQRCodeAppLCD(); 25 | qrcode->set_cam(cam); 26 | qrcode->set_lcd(lcd); 27 | qrcode->run(); 28 | #else 29 | auto qrcode = new WhoQRCodeAppTerm(); 30 | qrcode->set_cam(cam); 31 | qrcode->run(); 32 | #endif 33 | } 34 | -------------------------------------------------------------------------------- /examples/qrcode_recognition/main/idf_component.yml: -------------------------------------------------------------------------------- 1 | ## IDF Component Manager Manifest File 2 | dependencies: 3 | espressif/esp_lvgl_port: "*" -------------------------------------------------------------------------------- /examples/qrcode_recognition/partitions.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild 3 | 4 | nvs, data, nvs, 0x9000, 24K, 5 | phy_init, data, phy, 0xf000, 4K, 6 | factory, app, factory, 0x010000, 8000K, 7 | -------------------------------------------------------------------------------- /examples/qrcode_recognition/sdkconfig.defaults: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/examples/qrcode_recognition/sdkconfig.defaults -------------------------------------------------------------------------------- /examples/qrcode_recognition/sdkconfig.defaults.esp32p4: -------------------------------------------------------------------------------- 1 | # This file was generated using idf.py save-defconfig. It can be edited manually. 2 | # Espressif IoT Development Framework (ESP-IDF) 5.5.0 Project Minimal Configuration 3 | # 4 | CONFIG_IDF_TARGET="esp32p4" 5 | CONFIG_ESPTOOLPY_FLASHMODE_QIO=y 6 | CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y 7 | CONFIG_PARTITION_TABLE_CUSTOM=y 8 | CONFIG_COMPILER_OPTIMIZATION_PERF=y 9 | CONFIG_SPIRAM=y 10 | CONFIG_SPIRAM_SPEED_200M=y 11 | CONFIG_SPIRAM_XIP_FROM_PSRAM=y 12 | CONFIG_CACHE_L2_CACHE_256KB=y 13 | CONFIG_CACHE_L2_CACHE_LINE_128B=y 14 | CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=n 15 | CONFIG_FATFS_LFN_HEAP=y 16 | CONFIG_FREERTOS_HZ=1000 17 | CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y 18 | CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y 19 | CONFIG_FREERTOS_RUN_TIME_COUNTER_TYPE_U64=y 20 | CONFIG_BSP_SD_FORMAT_ON_MOUNT_FAIL=y 21 | CONFIG_CAMERA_SC2336=y 22 | CONFIG_CAMERA_SC2336_MIPI_RAW8_1024x600_30FPS=y 23 | CONFIG_ESP_VIDEO_ENABLE_ISP_PIPELINE_CONTROLLER=y 24 | CONFIG_IDF_EXPERIMENTAL_FEATURES=y 25 | -------------------------------------------------------------------------------- /examples/qrcode_recognition/sdkconfig.defaults.esp32s3: -------------------------------------------------------------------------------- 1 | # This file was generated using idf.py save-defconfig. It can be edited manually. 2 | # Espressif IoT Development Framework (ESP-IDF) 5.5.0 Project Minimal Configuration 3 | # 4 | CONFIG_IDF_TARGET="esp32s3" 5 | CONFIG_ESPTOOLPY_FLASHMODE_QIO=y 6 | CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y 7 | CONFIG_PARTITION_TABLE_CUSTOM=y 8 | CONFIG_COMPILER_OPTIMIZATION_PERF=y 9 | CONFIG_SPIRAM=y 10 | CONFIG_SPIRAM_MODE_OCT=y 11 | CONFIG_SPIRAM_XIP_FROM_PSRAM=y 12 | CONFIG_SPIRAM_SPEED_80M=y 13 | CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y 14 | CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB=y 15 | CONFIG_ESP32S3_DATA_CACHE_64KB=y 16 | CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y 17 | CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=n 18 | CONFIG_FATFS_LFN_HEAP=y 19 | CONFIG_FREERTOS_HZ=1000 20 | CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y 21 | CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y 22 | CONFIG_FREERTOS_RUN_TIME_COUNTER_TYPE_U64=y 23 | CONFIG_BSP_SD_FORMAT_ON_MOUNT_FAIL=y 24 | -------------------------------------------------------------------------------- /img/esp-who_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/img/esp-who_config.png -------------------------------------------------------------------------------- /img/esp-who_config_camera_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/img/esp-who_config_camera_config.png -------------------------------------------------------------------------------- /img/esp-who_config_camera_config_custom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/img/esp-who_config_camera_config_custom.png -------------------------------------------------------------------------------- /img/esp-who_config_camera_config_select_pinout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/img/esp-who_config_camera_config_select_pinout.png -------------------------------------------------------------------------------- /img/esp-who_config_wifi_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/img/esp-who_config_wifi_config.png -------------------------------------------------------------------------------- /img/esp_eye_Wechat_cross.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/img/esp_eye_Wechat_cross.jpeg -------------------------------------------------------------------------------- /img/esp_eye_Wechat_list.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/img/esp_eye_Wechat_list.jpg -------------------------------------------------------------------------------- /img/esp_eye_Wechat_network_configuration.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/img/esp_eye_Wechat_network_configuration.jpg -------------------------------------------------------------------------------- /img/esp_eye_wechat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/img/esp_eye_wechat.jpg -------------------------------------------------------------------------------- /img/esp_eye_wechat_qr.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/img/esp_eye_wechat_qr.jpg -------------------------------------------------------------------------------- /img/face_recognition_model_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espressif/esp-who/6d8b10961bdd70cbadcc80c0bcfb9fcb4d8217cf/img/face_recognition_model_config.png -------------------------------------------------------------------------------- /tools/ci/build_apps.py: -------------------------------------------------------------------------------- 1 | from idf_build_apps import build_apps, find_apps 2 | import argparse 3 | 4 | 5 | if __name__ == "__main__": 6 | parser = argparse.ArgumentParser( 7 | description="Build all the apps.", 8 | formatter_class=argparse.ArgumentDefaultsHelpFormatter, 9 | ) 10 | parser.add_argument("paths", nargs="+", help="Paths to the apps to build.") 11 | args = parser.parse_args() 12 | apps = find_apps( 13 | args.paths, 14 | target="all", 15 | # recursive=True, 16 | default_build_targets=["esp32s3", "esp32p4"], 17 | build_dir=f"build_@n_@v_@t_@w", 18 | config_rules="sdkconfig.*=", 19 | # build_log_filename="build_log.txt", 20 | size_json_filename="size.json", 21 | ) 22 | build_apps(apps, copy_sdkconfig=True) 23 | -------------------------------------------------------------------------------- /tools/ci/check_readme_links.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Checks that all links in the readme markdown files are valid 4 | # 5 | # SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD 6 | # SPDX-License-Identifier: Apache-2.0 7 | 8 | import argparse 9 | import concurrent.futures 10 | import os 11 | import os.path 12 | import re 13 | import sys 14 | import urllib.error 15 | import urllib.request 16 | from collections import defaultdict, namedtuple 17 | from pathlib import Path 18 | 19 | EXCLUDE_DOCS_LIST = [] 20 | 21 | # The apple apps links are not accessible from the company network for some reason 22 | EXCLUDE_URL_LIST = [ 23 | "sales@espressif.com", 24 | "https://docs.espressif.com/projects/esp-idf/zh_CN/v3.1.1/get-started/index.html", 25 | ] 26 | 27 | Link = namedtuple("Link", ["file", "url"]) 28 | 29 | 30 | class ReadmeLinkError(Exception): 31 | def __init__(self, file, url): 32 | self.file = file 33 | self.url = url 34 | 35 | 36 | class RelativeLinkError(ReadmeLinkError): 37 | def __str__(self): 38 | return "Relative link error, file - {} not found, linked from {}".format( 39 | self.url, self.file 40 | ) 41 | 42 | 43 | class UrlLinkError(ReadmeLinkError): 44 | def __init__(self, file, url, error_code): 45 | self.error_code = error_code 46 | super().__init__(file, url) 47 | 48 | def __str__(self): 49 | files = [str(f) for f in self.file] 50 | return "URL error, url - {} in files - {} is not accessible, request returned {}".format( 51 | self.url, ", ".join(files), self.error_code 52 | ) 53 | 54 | 55 | # we do not want a failed test just due to bad network conditions, for non 404 errors we simply print a warning 56 | def check_url(url, files, timeout): 57 | try: 58 | with urllib.request.urlopen(url, timeout=timeout): 59 | return 60 | except urllib.error.HTTPError as e: 61 | if e.code == 404: 62 | raise UrlLinkError(files, url, str(e)) 63 | else: 64 | print("Unable to access {}, err = {}".format(url, str(e))) 65 | except Exception as e: 66 | print("Unable to access {}, err = {}".format(url, str(e))) 67 | 68 | 69 | def check_web_links(web_links): 70 | 71 | with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor: 72 | errors = [] 73 | future_to_url = { 74 | executor.submit(check_url, url, files, timeout=30): (url, files) 75 | for url, files in web_links.items() 76 | } 77 | for future in concurrent.futures.as_completed(future_to_url): 78 | try: 79 | future.result() 80 | except UrlLinkError as e: 81 | errors.append(e) 82 | 83 | return errors 84 | 85 | 86 | def check_file_links(file_links): 87 | errors = [] 88 | 89 | for link in file_links: 90 | link_path = link.file.parent / link.url 91 | 92 | if not Path.exists(link_path): 93 | errors.append(RelativeLinkError(link.file, link.url)) 94 | 95 | print("Found {} errors with relative links".format(len(errors))) 96 | return errors 97 | 98 | 99 | def get_md_links(folder): 100 | MD_LINK_RE = r"\[.+?\]\((.+?)(#.+)?\)" 101 | links = [] 102 | 103 | for path in Path(folder).rglob("*.md"): 104 | if any([path.match(exclude_doc) for exclude_doc in EXCLUDE_DOCS_LIST]): 105 | print("{} - excluded".format(path)) 106 | continue 107 | 108 | print("-open {}".format(path)) 109 | with path.open(encoding="utf8") as f: 110 | content = f.read() 111 | 112 | for url in re.findall(MD_LINK_RE, content): 113 | link = Link(path, url[0].lstrip()) 114 | # Ignore "local" links 115 | if not link.url.startswith("#"): 116 | links.append(link) 117 | 118 | return links 119 | 120 | 121 | def check_readme_links(args): 122 | 123 | # Get all links from the readme files 124 | links = get_md_links(args.dir) 125 | print("Found {} links".format(len(links))) 126 | 127 | errors = [] 128 | 129 | web_links = defaultdict(list) 130 | file_links = [] 131 | 132 | # Sort links into file and web links 133 | for link in links: 134 | if link.url not in EXCLUDE_URL_LIST: 135 | if link.url.startswith("http"): 136 | web_links[link.url].append(link.file) 137 | else: 138 | file_links.append(link) 139 | 140 | errors.extend(check_file_links(file_links)) 141 | 142 | if not args.skip_weburl: 143 | errors.extend(check_web_links(web_links)) 144 | 145 | print("Found {} errors:".format(len(errors))) 146 | for e in errors: 147 | print(e) 148 | 149 | return 1 if len(errors) > 0 else 0 150 | 151 | 152 | if __name__ == "__main__": 153 | 154 | parser = argparse.ArgumentParser( 155 | description="check_readme_links.py: Checks for dead links in example READMEs", 156 | prog="check_readme_links.py", 157 | ) 158 | parser.add_argument( 159 | "dir", 160 | type=str, 161 | help="README files dir", 162 | ) 163 | parser.add_argument( 164 | "--skip-weburl", 165 | "-w", 166 | action="store_true", 167 | help="Skip checking of web URLs, only check links to local files", 168 | ) 169 | args = parser.parse_args() 170 | 171 | sys.exit(check_readme_links(args)) 172 | -------------------------------------------------------------------------------- /tools/ci/push_to_github.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # gitlab-ci script to push current tested revision (tag or branch) to github 4 | 5 | set -ex 6 | 7 | if [ -n "${CI_COMMIT_TAG}" ]; then 8 | # for tags 9 | git push github "${CI_COMMIT_TAG}" 10 | else 11 | # for branches 12 | git push github "${CI_COMMIT_SHA}:refs/heads/${CI_COMMIT_REF_NAME}" 13 | fi 14 | 15 | --------------------------------------------------------------------------------