-
Notifications
You must be signed in to change notification settings - Fork 93
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Quirc esp-eye example (IEC-51) #240
base: master
Are you sure you want to change the base?
Changes from 4 commits
302913f
a7e61d9
e4616b8
70ee9c4
018a689
88a3f31
f3e9132
e2f8508
eff35ad
4f787d0
d9f2fb6
d0043a2
9b3ae06
0cbc4af
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
FROM espressif/idf | ||
|
||
ARG DEBIAN_FRONTEND=nointeractive | ||
ARG CONTAINER_USER=esp | ||
ARG USER_UID=1000 | ||
ARG USER_GID=$USER_UID | ||
|
||
RUN apt-get update \ | ||
&& apt install -y -q \ | ||
cmake \ | ||
git \ | ||
hwdata \ | ||
libglib2.0-0 \ | ||
libnuma1 \ | ||
libpixman-1-0 \ | ||
linux-tools-virtual \ | ||
&& rm -rf /var/lib/apt/lists/* | ||
|
||
RUN update-alternatives --install /usr/local/bin/usbip usbip `ls /usr/lib/linux-tools/*/usbip | tail -n1` 20 | ||
|
||
# QEMU | ||
ENV QEMU_REL=esp-develop-20220919 | ||
ENV QEMU_SHA256=f6565d3f0d1e463a63a7f81aec94cce62df662bd42fc7606de4b4418ed55f870 | ||
ENV QEMU_DIST=qemu-${QEMU_REL}.tar.bz2 | ||
ENV QEMU_URL=https://github.com/espressif/qemu/releases/download/${QEMU_REL}/${QEMU_DIST} | ||
|
||
ENV LC_ALL=C.UTF-8 | ||
ENV LANG=C.UTF-8 | ||
|
||
RUN wget --no-verbose ${QEMU_URL} \ | ||
&& echo "${QEMU_SHA256} *${QEMU_DIST}" | sha256sum --check --strict - \ | ||
&& tar -xf $QEMU_DIST -C /opt \ | ||
&& rm ${QEMU_DIST} | ||
|
||
ENV PATH=/opt/qemu/bin:${PATH} | ||
|
||
RUN groupadd --gid $USER_GID $CONTAINER_USER \ | ||
&& adduser --uid $USER_UID --gid $USER_GID --disabled-password --gecos "" ${CONTAINER_USER} \ | ||
&& usermod -a -G dialout $CONTAINER_USER | ||
USER ${CONTAINER_USER} | ||
ENV USER=${CONTAINER_USER} | ||
WORKDIR /home/${CONTAINER_USER} | ||
|
||
RUN echo "source /opt/esp/idf/export.sh > /dev/null 2>&1" >> ~/.bashrc | ||
|
||
ENTRYPOINT [ "/opt/esp/entrypoint.sh" ] | ||
|
||
CMD ["/bin/bash", "-c"] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: | ||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.183.0/containers/ubuntu | ||
{ | ||
"name": "ESP-IDF QEMU", | ||
"build": { | ||
"dockerfile": "Dockerfile" | ||
}, | ||
// Add the IDs of extensions you want installed when the container is created | ||
"workspaceMount": "source=${localWorkspaceFolder},target=${localWorkspaceFolder},type=bind", | ||
/* the path of workspace folder to be opened after container is running | ||
*/ | ||
"workspaceFolder": "${localWorkspaceFolder}", | ||
"mounts": [ | ||
"source=extensionCache,target=/root/.vscode-server/extensions,type=volume" | ||
], | ||
"customizations": { | ||
"vscode": { | ||
"settings": { | ||
"terminal.integrated.defaultProfile.linux": "bash", | ||
"idf.espIdfPath": "/opt/esp/idf", | ||
"idf.customExtraPaths": "", | ||
"idf.pythonBinPath": "/opt/esp/python_env/idf5.1_py3.8_env/bin/python", | ||
"idf.toolsPath": "/opt/esp", | ||
"idf.gitPath": "/usr/bin/git" | ||
}, | ||
"extensions": [ | ||
"ms-vscode.cpptools", | ||
"espressif.esp-idf-extension" | ||
], | ||
}, | ||
"codespaces": { | ||
"settings": { | ||
"terminal.integrated.defaultProfile.linux": "bash", | ||
"idf.espIdfPath": "/opt/esp/idf", | ||
"idf.customExtraPaths": "", | ||
"idf.pythonBinPath": "/opt/esp/python_env/idf5.1_py3.8_env/bin/python", | ||
"idf.toolsPath": "/opt/esp", | ||
"idf.gitPath": "/usr/bin/git" | ||
}, | ||
"extensions": [ | ||
"ms-vscode.cpptools", | ||
"espressif.esp-idf-extension" | ||
], | ||
} | ||
}, | ||
"runArgs": ["--privileged"] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# For more information about build system see | ||
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html | ||
# The following five lines of boilerplate have to be in your project's | ||
# CMakeLists in this exact order for cmake to work correctly | ||
cmake_minimum_required(VERSION 3.16) | ||
|
||
include($ENV{IDF_PATH}/tools/cmake/project.cmake) | ||
project(app_main) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | | ||
| ------ | ----- | -------- | -------- | -------- | -------- | -------- | -------- | | ||
| | X | | | | | | | | ||
# ESP-EYE QR-CODE with QUIRC | ||
|
||
In this example the esp-eye takes a picture every few ms and check if the image contains valid qr-codes. If detected, it shows a message on the terminal (e.g. `Data: This is an esp-eye test`). It may not decode correctly the qr-code and in this case an error message is shown (`DECODE FAILED: ECC failure`). | ||
|
||
## How to use example | ||
|
||
Build and flash on an esp-eye. It may work with small changes also on ESP32-CAM and ESP32-S3-EYE. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
idf_component_register( SRCS | ||
app_peripherals.c | ||
app_main.c | ||
INCLUDE_DIRS | ||
include | ||
) |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,85 @@ | ||||||
#include <stdio.h> | ||||||
#include <stdint.h> | ||||||
#include <string.h> | ||||||
#include "esp_log.h" | ||||||
#include "esp_system.h" | ||||||
#include "freertos/FreeRTOS.h" | ||||||
#include "freertos/task.h" | ||||||
#include "app_peripherals.h" | ||||||
#include "quirc.h" | ||||||
|
||||||
static const char *TAG = "APP_CODE_SCANNER"; | ||||||
|
||||||
static void decode_task() | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FreeRTOS task function definition should look like this:
Suggested change
|
||||||
{ | ||||||
if(ESP_OK != app_camera_init()) { | ||||||
vTaskDelete(NULL); | ||||||
return; | ||||||
} | ||||||
|
||||||
camera_fb_t *fb = NULL; | ||||||
|
||||||
// Initializing the quirc handle | ||||||
struct quirc *q = quirc_new(); | ||||||
if (!q) { | ||||||
ESP_LOGE(TAG,"Failed to allocate memory\n"); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Newline at the end of format strings is not necessary for ESP_LOG, it's added automatically. Also, missing space after comma. (Have you installed the pre-commit hooks using |
||||||
exit(1); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Error handling is a bit inconsistent. In the check above you are doing Let's try to make this more consistent. You can decide the error handling strategy for this function — return or abort — and use the same approach in the whole function. |
||||||
} | ||||||
|
||||||
|
||||||
// Get image size through fb parameters | ||||||
fb = esp_camera_fb_get(); | ||||||
if(fb == NULL){ | ||||||
ESP_LOGI(TAG, "camera get failed\n"); | ||||||
} | ||||||
|
||||||
uint16_t p_width = fb->width; | ||||||
uint16_t p_height = fb->height; | ||||||
|
||||||
|
||||||
if (quirc_resize(q, p_width,p_height) < 0) { | ||||||
ESP_LOGE(TAG,"Failed to allocate video memory\n"); | ||||||
exit(1); | ||||||
} | ||||||
|
||||||
struct quirc_code code; | ||||||
struct quirc_data data; | ||||||
quirc_decode_error_t err; | ||||||
uint16_t num_codes; | ||||||
|
||||||
while (1) | ||||||
{ | ||||||
fb = esp_camera_fb_get(); | ||||||
if(fb == NULL){ | ||||||
ESP_LOGI(TAG, "camera get failed\n"); | ||||||
continue; | ||||||
} | ||||||
// Decode Progress | ||||||
|
||||||
memcpy(quirc_begin(q, NULL, NULL), fb->buf, fb->len); | ||||||
quirc_end(q); | ||||||
|
||||||
num_codes = quirc_count(q); | ||||||
for (uint16_t i = 0; i < num_codes; i++) { | ||||||
|
||||||
quirc_extract(q, i, &code); | ||||||
/* Decoding stage */ | ||||||
err = quirc_decode(&code, &data); | ||||||
if (err) | ||||||
printf("%d/%d] DECODE FAILED: %s\n", i+1,num_codes,quirc_strerror(err)); | ||||||
else | ||||||
printf("%d/%d] DATA: %s\n",i+1,num_codes,data.payload); | ||||||
} | ||||||
|
||||||
esp_camera_fb_return(fb); | ||||||
vTaskDelay(10 / portTICK_PERIOD_MS); | ||||||
} | ||||||
|
||||||
quirc_destroy(q); | ||||||
} | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This part of the code isn't supposed to be reached. I'm not sure what the best approach would be here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Depends on the error handling strategy — see the other comment about this. If you decide to handle errors by terminating the task, probably having the cleanup path with quirc_destroy would make sense. You could use an If you decide to handle errors by aborting (which is not an unreasonable strategy for an example project) then quirc_destroy can be removed since it's unreachable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok then since as you say it's an example, I think it's best to keep it the simplest possible. I removed the quirc_destroy. |
||||||
|
||||||
|
||||||
void app_main() | ||||||
FBEZ marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
{ | ||||||
xTaskCreatePinnedToCore(decode_task, TAG, 40 * 1024, NULL, 6, NULL, 0); | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
#include "app_peripherals.h" | ||
#include "esp_log.h" | ||
#include "esp_system.h" | ||
|
||
static const char *TAG = "app_peripherals"; | ||
|
||
esp_err_t app_camera_init() | ||
{ | ||
ESP_LOGI(TAG, "Camera module is %s", CAMERA_MODULE_NAME); | ||
|
||
camera_config_t config; | ||
config.ledc_channel = LEDC_CHANNEL_0; | ||
config.ledc_timer = LEDC_TIMER_0; | ||
config.pin_d0 = CAMERA_PIN_D0; | ||
config.pin_d1 = CAMERA_PIN_D1; | ||
config.pin_d2 = CAMERA_PIN_D2; | ||
config.pin_d3 = CAMERA_PIN_D3; | ||
config.pin_d4 = CAMERA_PIN_D4; | ||
config.pin_d5 = CAMERA_PIN_D5; | ||
config.pin_d6 = CAMERA_PIN_D6; | ||
config.pin_d7 = CAMERA_PIN_D7; | ||
config.pin_xclk = CAMERA_PIN_XCLK; | ||
config.pin_pclk = CAMERA_PIN_PCLK; | ||
config.pin_vsync = CAMERA_PIN_VSYNC; | ||
config.pin_href = CAMERA_PIN_HREF; | ||
config.pin_sccb_sda = CAMERA_PIN_SIOD; | ||
config.pin_sccb_scl = CAMERA_PIN_SIOC; | ||
config.pin_pwdn = CAMERA_PIN_PWDN; | ||
config.pin_reset = CAMERA_PIN_RESET; | ||
config.xclk_freq_hz = XCLK_FREQ_HZ; | ||
config.pixel_format = CAMERA_PIXFORMAT; | ||
config.frame_size = CAMERA_FRAME_SIZE; | ||
config.jpeg_quality = 5; | ||
config.fb_count = CAMERA_FB_COUNT; | ||
config.fb_location = CAMERA_FB_IN_PSRAM; | ||
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY; | ||
|
||
// camera init | ||
esp_err_t err = esp_camera_init(&config); | ||
if (err != ESP_OK) | ||
{ | ||
ESP_LOGE(TAG, "Camera init failed with error 0x%x", err); | ||
return ESP_FAIL; | ||
} | ||
|
||
sensor_t *s = esp_camera_sensor_get(); | ||
if (s->id.PID == OV3660_PID || s->id.PID == OV2640_PID) | ||
s->set_vflip(s, 1); //flip it back | ||
else if (s->id.PID == GC0308_PID){ | ||
s->set_hmirror(s, 0); | ||
} | ||
else if (s->id.PID == GC032A_PID){ | ||
s->set_vflip(s, 1); | ||
} | ||
|
||
if (s->id.PID == OV3660_PID) | ||
{ | ||
s->set_brightness(s, 2); | ||
s->set_contrast(s, 3); | ||
} | ||
|
||
return ESP_OK; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
## IDF Component Manager Manifest File | ||
dependencies: | ||
espressif/esp32-camera: "^2.0.5" | ||
espressif/quirc: | ||
version: "^1.2.0" | ||
# This line define the local path of the component because this | ||
# example is part of the component. This line is optional. | ||
override_path: "../../.." | ||
## Required IDF version | ||
idf: | ||
version: ">=4.3.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem with devcontainers in general, but we usually don't add them directly to the example projects. Perhaps we can add one at project level, though. Still, I would prefer if this is done in a separate PR.