♻️ common -> modules

pull/190/head
Ye Hang Yang 2021-09-08 20:04:59 +08:00
parent dd58787fab
commit 66b00a1449
32 changed files with 6562 additions and 273 deletions

View File

@ -1,3 +0,0 @@
idf_component_register(SRC_DIRS . INCLUDE_DIRS include wallpaper REQUIRES esp32-camera esp-dl bus screen)
component_compile_options(-ffast-math -O3)

View File

@ -1,53 +0,0 @@
#pragma once
#include "esp_camera.h"
#include "app_define.h"
/**
* @brief Initialize camera
*
* @param pixformat One of
* - PIXFORMAT_RGB565
* - PIXFORMAT_YUV422
* - PIXFORMAT_GRAYSC
* - PIXFORMAT_JPEG
* - PIXFORMAT_RGB888
* - PIXFORMAT_RAW
* - PIXFORMAT_RGB444
* - PIXFORMAT_RGB555
* @param frame_size One of
* - FRAMESIZE_96X96, // 96x96
* - FRAMESIZE_QQVGA, // 160x120
* - FRAMESIZE_QCIF, // 176x144
* - FRAMESIZE_HQVGA, // 240x176
* - FRAMESIZE_240X240, // 240x240
* - FRAMESIZE_QVGA, // 320x240
* - FRAMESIZE_CIF, // 400x296
* - FRAMESIZE_HVGA, // 480x320
* - FRAMESIZE_VGA, // 640x480
* - FRAMESIZE_SVGA, // 800x600
* - FRAMESIZE_XGA, // 1024x768
* - FRAMESIZE_HD, // 1280x720
* - FRAMESIZE_SXGA, // 1280x1024
* - FRAMESIZE_UXGA, // 1600x1200
* - FRAMESIZE_FHD, // 1920x1080
* - FRAMESIZE_P_HD, // 720x1280
* - FRAMESIZE_P_3MP, // 864x1536
* - FRAMESIZE_QXGA, // 2048x1536
* - FRAMESIZE_QHD, // 2560x1440
* - FRAMESIZE_WQXGA, // 2560x1600
* - FRAMESIZE_P_FHD, // 1080x1920
* - FRAMESIZE_QSXGA, // 2560x1920
* @param fb_count Number of frame buffers to be allocated. If more than one, then each frame will be acquired (double speed)
* @param jpeg_quality Quality of JPEG output. 0-63 lower means higher quality
*/
void app_camera_init(const pixformat_t pixel_fromat, const framesize_t frame_size, const uint8_t fb_count, const uint8_t jpeg_quality = 12);
/**
* @brief Decode fb ,
* - if fb->format == PIXFORMAT_RGB565, then return fb->buf
* - else, then return a new memory with RGB888, don't forget to free it
*
* @param fb
*/
void *app_camera_decode(camera_fb_t *fb);

View File

@ -1,18 +0,0 @@
#pragma once
#include <stdint.h>
#include "esp_log.h"
#include "screen_driver.h"
#ifdef __cplusplus
extern "C"
{
#endif
esp_err_t app_lcd_init();
void app_lcd_draw_wallpaper();
void app_lcd_set_color(int color);
void app_lcd_draw_bitmap(uint16_t *image_ptr, const uint16_t image_height, const uint16_t image_width);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,31 @@
set(embed_files "web/www/index_ov2640.html.gz"
"web/www/index_ov3660.html.gz"
"web/www/index_ov5640.html.gz"
"web/www/monitor.html.gz")
set(src_dirs
ai
camera
lcd
led
web)
set(include_dirs
ai
camera
lcd
led
web)
set(requires esp32-camera
esp-dl
bus
screen
esp_http_server
nvs_flash
mdns
fb_gfx)
idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires} EMBED_FILES ${embed_files})
component_compile_options(-ffast-math -O3)

View File

@ -1,30 +1,64 @@
menu "ESP-WHO General Configuration"
menu "Camera Configuration"
choice PIXEL_FORMAT
bool "Select Camera Pixel Format"
default CAMERA_PIXEL_FORMAT_RGB565
help
Select Camera Pixel Format.
config CAMERA_PIXEL_FORMAT_RGB565
bool "RGB565"
config CAMERA_PIXEL_FORMAT_YUV422
bool "YUV422"
config CAMERA_PIXEL_FORMAT_GRAYSCALE
bool "GRAYSCALE"
config CAMERA_PIXEL_FORMAT_JPEG
bool "JPEG"
config CAMERA_PIXEL_FORMAT_RGB888
bool "RGB888"
config CAMERA_PIXEL_FORMAT_RAW
bool "RAW"
config CAMERA_PIXEL_FORMAT_RGB444
bool "RGB444"
config CAMERA_PIXEL_FORMAT_RGB555
bool "RGB555"
menu "WiFi Configuration"
endchoice
config ESP_HOST_NAME
string "Camera Host Name"
default ""
help
Hostname that the camera will advertise over mDNS.
config ESP_WIFI_SSID
string "WiFi STA SSID"
default ""
help
WiFi SSID (network name) to connect to or empty for Off.
config ESP_WIFI_PASSWORD
string "WiFi STA Password"
default ""
help
WiFi Password if WEP/WPA/WPA2 or empty if Open.
config ESP_WIFI_AP_SSID
string "WiFi AP SSID"
default "ESP32-Camera"
help
AP SSID (network name) to create or empty for Off.
config ESP_WIFI_AP_PASSWORD
string "WiFi AP Password"
default ""
help
AP password for WPA2 or empty for Open.
config MAX_STA_CONN
int "Maximal STA connections"
default 1
help
Max number of the STA connects to AP.
config ESP_WIFI_AP_CHANNEL
string "WiFi AP Channel"
default ""
help
AP channel for better connection performance.
config SERVER_IP
string "WiFi AP IP Address"
default "192.168.4.1"
help
IP address that the ESP will assign to it's AP interface. You can use this IP to connect to the camera after flashing.
config ESP_MAXIMUM_RETRY
int "Maximum retry"
default 5
help
Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
endmenu
menu "Camera Configuration"
choice CAMERA_MODULE
bool "Select Camera Pinout"
@ -36,6 +70,8 @@ menu "ESP-WHO General Configuration"
bool "WROVER-KIT With OV2640 Module"
config CAMERA_MODULE_ESP_EYE
bool "ESP-EYE DevKit"
config CAMERA_MODULE_ESP_S2_KALUGA
bool "ESP32-S2-Kaluga-1 V1.3"
config CAMERA_MODULE_ESP_S3_EYE
bool "ESP-S3-EYE DevKit"
config CAMERA_MODEL_ESP32_CAM_BOARD
@ -232,84 +268,4 @@ menu "ESP-WHO General Configuration"
help
Select the LEDC Channel (0-7)
endmenu
menu "DL Configuration"
config DL_ENABLED
bool "Enable Deep-Learning Application"
default y
choice DL_SELECT_APP
bool "Select Application"
depends on DL_ENABLED
default DL_HUMAN_FACE
config DL_HUMAN_FACE
bool "Human Face"
config DL_CAT_FACE
bool "Cat Face"
config DL_HUMAN_HAND
bool "Human Hand"
endchoice
# Human Face Series
choice DL_HUMAN_FACE_DETECTION_S1_MODEL
bool "Select Human Face Detection Stage-1 Model"
depends on DL_HUMAN_FACE
default DL_HUMAN_FACE_DETECTION_S1_MSR01
config DL_HUMAN_FACE_DETECTION_S1_MSR01
bool "HumanFaceDetectMSR01"
endchoice
config DL_HUMAN_FACE_DETECTION_S2_ENABLED
bool "Enable Human Face Detection Stage-2"
depends on DL_HUMAN_FACE
default y
choice DL_HUMAN_FACE_DETECTION_S2_MODEL
bool "Select Human Face Detection Stage-2 Model"
depends on DL_HUMAN_FACE_DETECTION_S2_ENABLED
default DL_HUMAN_FACE_DETECTION_S2_MNP01
config DL_HUMAN_FACE_DETECTION_S2_MNP01
bool "HumanFaceDetectMNP01"
endchoice
config DL_HUMAN_FACE_RECOGNITION_ENABLED
bool "Enable Human Face Recognition"
depends on DL_HUMAN_FACE_DETECTION_S2_ENABLED
default y
choice DL_HUMAN_FACE_RECOGNITION_MODEL
bool "Select Human Face Recognition Model"
depends on DL_HUMAN_FACE_RECOGNITION_ENABLED
default DL_HUMAN_FACE_RECOGNITION_XXX
config DL_HUMAN_FACE_RECOGNITION_XXX
bool "HumanFaceRecognizeXXX"
endchoice
# Cat Face Series
choice DL_CAT_FACE_DETECTION_MODEL
bool "Select Cat Face Detection Model"
depends on DL_CAT_FACE
default DL_CAT_FACE_DETECTION_MN03
config DL_CAT_FACE_DETECTION_MN03
bool "CatFaceDetectMN03"
endchoice
# Human Hand Series
config DL_MOVING_TARGET_DETECTION_ENABLED
bool "Enable Moving Target Detection"
default y
endmenu
endmenu

View File

@ -1,7 +1,10 @@
#include "app_common.hpp"
#include "dl_image.hpp"
#include "esp_log.h"
#include "esp_camera.h"
#include "dl_image.hpp"
void draw_detection_result(uint16_t *image_ptr, int image_height, int image_width, std::list<dl::detect::result_t> &results)
{
@ -52,7 +55,7 @@ void print_detection_result(std::list<dl::detect::result_t> &results)
{
ESP_LOGI("detection_result", "[%d]: (%3d, %3d, %3d, %3d)"
#if CONFIG_DL_HUMAN_FACE_DETECTION_S2_ENABLED
" | left eye: (%3d, %3d), right eye: (%3d, %3d), nose: (%3d, %3d), mouth left: (%3d, %3d), mouth right: (%3d, %3d)"
" | left eye: (%3d, %3d), right eye: (%3d, %3d), nose: (%3d, %3d), mouth left: (%3d, %3d), mouth right: (%3d, %3d)"
#endif
,
i,
@ -67,4 +70,33 @@ void print_detection_result(std::list<dl::detect::result_t> &results)
#endif
);
}
}
void *app_camera_decode(camera_fb_t *fb)
{
if (fb->format == PIXFORMAT_RGB565)
{
return (void *)fb->buf;
}
else
{
uint8_t *image_ptr = (uint8_t *)malloc(fb->height * fb->width * 3 * sizeof(uint8_t));
if (image_ptr)
{
if (fmt2rgb888(fb->buf, fb->len, fb->format, image_ptr))
{
return (void *)image_ptr;
}
else
{
ESP_LOGE(TAG, "fmt2rgb888 failed");
dl::tool::free_aligned(image_ptr);
}
}
else
{
ESP_LOGE(TAG, "malloc memory for image rgb888 failed");
}
}
return NULL;
}

View File

@ -2,7 +2,25 @@
#include <list>
#include "dl_detect_define.hpp"
#include "app_define.h"
#include "esp_camera.h"
// #include "who_define.h"
#if CONFIG_CAMERA_PIXEL_FORMAT_RGB565
#define IMAGE_T uint16_t
#define COLOR_RED 0b0000000011111000
#define COLOR_GREEN 0b1110000000000111
#define COLOR_BLUE 0b0001111100000000
#define COLOR_BLACK 0b0000000000000000
#else
#define IMAGE_T uint8_t
#define COLOR_RED 0x0000FF
#define COLOR_GREEN 0x00FF00
#define COLOR_BLUE 0xFF0000
#define COLOR_BLACK 0x000000
#endif
static const char *TAG = "app_common";
/**
* @brief Draw detection result on RGB565 image.
@ -31,3 +49,12 @@ void draw_detection_result(uint8_t *image_ptr, int image_height, int image_width
* @param results detection results
*/
void print_detection_result(std::list<dl::detect::result_t> &results);
/**
* @brief Decode fb ,
* - if fb->format == PIXFORMAT_RGB565, then return fb->buf
* - else, then return a new memory with RGB888, don't forget to free it
*
* @param fb
*/
void *app_camera_decode(camera_fb_t *fb);

View File

@ -0,0 +1,9 @@
#pragma once
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
void register_cat_face_detection(QueueHandle_t frame_i, QueueHandle_t event,
QueueHandle_t result, QueueHandle_t frame_o = NULL);

View File

@ -0,0 +1,9 @@
#pragma once
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
void register_motion_detection(QueueHandle_t frame_i, QueueHandle_t event,
QueueHandle_t result, QueueHandle_t frame_o = NULL);

View File

@ -1,14 +1,25 @@
#include "app_camera.hpp"
#include "who_camera.h"
#include "esp_log.h"
#include "esp_system.h"
#include "app_define.h"
#include "dl_tool.hpp"
static const char *TAG = "who_camera";
static QueueHandle_t xQueueFrameO = NULL;
static const char *TAG = "app_camera";
static void task_process_handler(void *arg)
{
while (true)
{
camera_fb_t *frame = esp_camera_fb_get();
if (frame)
xQueueSend(xQueueFrameO, &frame, portMAX_DELAY);
}
}
void app_camera_init(const pixformat_t pixel_fromat, const framesize_t frame_size, const uint8_t fb_count, const uint8_t jpeg_quality)
void register_camera(const pixformat_t pixel_fromat,
const framesize_t frame_size,
const uint8_t fb_count,
const QueueHandle_t frame_o)
{
ESP_LOGI(TAG, "Camera module is %s", CAMERA_MODULE_NAME);
@ -49,8 +60,9 @@ void app_camera_init(const pixformat_t pixel_fromat, const framesize_t frame_siz
config.xclk_freq_hz = XCLK_FREQ_HZ;
config.pixel_format = pixel_fromat;
config.frame_size = frame_size;
config.jpeg_quality = jpeg_quality;
config.jpeg_quality = 12;
config.fb_count = fb_count;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
// camera init
@ -69,33 +81,7 @@ void app_camera_init(const pixformat_t pixel_fromat, const framesize_t frame_siz
s->set_brightness(s, 1); //up the blightness just a bit
s->set_saturation(s, -2); //lower the saturation
}
}
void *app_camera_decode(camera_fb_t *fb)
{
if (fb->format == PIXFORMAT_RGB565)
{
return (void *)fb->buf;
}
else
{
uint8_t *image_ptr = (uint8_t *)malloc(fb->height * fb->width * 3 * sizeof(uint8_t));
if (image_ptr)
{
if (fmt2rgb888(fb->buf, fb->len, fb->format, image_ptr))
{
return (void *)image_ptr;
}
else
{
ESP_LOGE(TAG, "fmt2rgb888 failed");
dl::tool::free_aligned(image_ptr);
}
}
else
{
ESP_LOGE(TAG, "malloc memory for image rgb888 failed");
}
}
return NULL;
xQueueFrameO = frame_o;
xTaskCreatePinnedToCore(task_process_handler, TAG, 2 * 1024, NULL, 5, NULL, 1);
}

View File

@ -1,22 +1,11 @@
#pragma once
#include <stdint.h>
#include "esp_camera.h"
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#if CONFIG_CAMERA_PIXEL_FORMAT_RGB565
#define IMAGE_T uint16_t
#define COLOR_RED 0b0000000011111000
#define COLOR_GREEN 0b1110000000000111
#define COLOR_BLUE 0b0001111100000000
#define COLOR_BLACK 0b0000000000000000
#else
#define IMAGE_T uint8_t
#define COLOR_RED 0x0000FF
#define COLOR_GREEN 0x00FF00
#define COLOR_BLUE 0xFF0000
#define COLOR_BLACK 0x000000
#endif
#include "esp_camera.h"
#if CONFIG_CAMERA_MODULE_WROVER_KIT
#define CAMERA_MODULE_NAME "Wrover Kit"
@ -58,10 +47,30 @@
#define CAMERA_PIN_HREF 27
#define CAMERA_PIN_PCLK 25
#elif CONFIG_CAMERA_MODULE_ESP_S2_KALUGA
#define CAMERA_MODULE_NAME "ESP-S2-KALUGA"
#define CAMERA_PIN_PWDN -1
#define CAMERA_PIN_RESET -1
#define CAMERA_PIN_XCLK 1
#define CAMERA_PIN_SIOD 8
#define CAMERA_PIN_SIOC 7
#define CAMERA_PIN_D7 38
#define CAMERA_PIN_D6 21
#define CAMERA_PIN_D5 40
#define CAMERA_PIN_D4 39
#define CAMERA_PIN_D3 42
#define CAMERA_PIN_D2 41
#define CAMERA_PIN_D1 37
#define CAMERA_PIN_D0 36
#define CAMERA_PIN_VSYNC 2
#define CAMERA_PIN_HREF 3
#define CAMERA_PIN_PCLK 33
#elif CONFIG_CAMERA_MODULE_ESP_S3_EYE
#define CAMERA_MODULE_NAME "ESP-S3-EYE"
#define CAMERA_PIN_PWDN 43
#define CAMERA_PIN_RESET 44
#define CAMERA_PIN_PWDN -1
#define CAMERA_PIN_RESET -1
#define CAMERA_PIN_VSYNC 6
#define CAMERA_PIN_HREF 7
@ -185,27 +194,52 @@
#define XCLK_FREQ_HZ 20000000
#if CONFIG_CAMERA_PIXEL_FORMAT_RGB565
#define CAMERA_PIXEL_FORMAT PIXFORMAT_RGB565
#ifdef __cplusplus
extern "C"
{
#endif
#if CONFIG_CAMERA_PIXEL_FORMAT_YUV422
#define CAMERA_PIXEL_FORMAT PIXFORMAT_YUV422
#endif
#if CONFIG_CAMERA_PIXEL_FORMAT_GRAYSCALE
#define CAMERA_PIXEL_FORMAT PIXFORMAT_GRAYSCALE
#endif
#if CONFIG_CAMERA_PIXEL_FORMAT_JPEG
#define CAMERA_PIXEL_FORMAT PIXFORMAT_JPEG
#endif
#if CONFIG_CAMERA_PIXEL_FORMAT_RGB888
#define CAMERA_PIXEL_FORMAT PIXFORMAT_RGB888
#endif
#if CONFIG_CAMERA_PIXEL_FORMAT_RAW
#define CAMERA_PIXEL_FORMAT PIXFORMAT_RAW
#endif
#if CONFIG_CAMERA_PIXEL_FORMAT_RGB444
#define CAMERA_PIXEL_FORMAT PIXFORMAT_RGB444
#endif
#if CONFIG_CAMERA_PIXEL_FORMAT_RGB555
#define CAMERA_PIXEL_FORMAT PIXFORMAT_RGB555
/**
* @brief Initialize camera
*
* @param pixformat One of
* - PIXFORMAT_RGB565
* - PIXFORMAT_YUV422
* - PIXFORMAT_GRAYSC
* - PIXFORMAT_JPEG
* - PIXFORMAT_RGB888
* - PIXFORMAT_RAW
* - PIXFORMAT_RGB444
* - PIXFORMAT_RGB555
* @param frame_size One of
* - FRAMESIZE_96X96, // 96x96
* - FRAMESIZE_QQVGA, // 160x120
* - FRAMESIZE_QCIF, // 176x144
* - FRAMESIZE_HQVGA, // 240x176
* - FRAMESIZE_240X240, // 240x240
* - FRAMESIZE_QVGA, // 320x240
* - FRAMESIZE_CIF, // 400x296
* - FRAMESIZE_HVGA, // 480x320
* - FRAMESIZE_VGA, // 640x480
* - FRAMESIZE_SVGA, // 800x600
* - FRAMESIZE_XGA, // 1024x768
* - FRAMESIZE_HD, // 1280x720
* - FRAMESIZE_SXGA, // 1280x1024
* - FRAMESIZE_UXGA, // 1600x1200
* - FRAMESIZE_FHD, // 1920x1080
* - FRAMESIZE_P_HD, // 720x1280
* - FRAMESIZE_P_3MP, // 864x1536
* - FRAMESIZE_QXGA, // 2048x1536
* - FRAMESIZE_QHD, // 2560x1440
* - FRAMESIZE_WQXGA, // 2560x1600
* - FRAMESIZE_P_FHD, // 1080x1920
* - FRAMESIZE_QSXGA, // 2560x1920
* @param fb_count Number of frame buffers to be allocated. If more than one, then each frame will be acquired (double speed)
*/
void register_camera(const pixformat_t pixel_fromat,
const framesize_t frame_size,
const uint8_t fb_count,
const QueueHandle_t frame_o);
#ifdef __cplusplus
}
#endif

View File

@ -1,26 +1,57 @@
#include "app_lcd.h"
#include "who_lcd.h"
#include "esp_camera.h"
#include <string.h>
#include "wallpaper_128x240_rgb565.h"
static const char *TAG = "app_lcd";
static const char *TAG = "who_lcd";
static scr_driver_t g_lcd;
static scr_info_t g_lcd_info;
esp_err_t app_lcd_init()
static QueueHandle_t xQueueFrameI = NULL;
static QueueHandle_t xQueueFrameO = NULL;
static bool gReturnFB = true;
static void task_process_handler(void *arg)
{
camera_fb_t *frame = NULL;
while (true)
{
if (xQueueReceive(xQueueFrameI, &frame, portMAX_DELAY))
{
g_lcd.draw_bitmap(0, 0, frame->width, frame->height, (uint16_t *)frame->buf);
if (xQueueFrameO)
{
xQueueSend(xQueueFrameO, &frame, portMAX_DELAY);
}
else if (gReturnFB)
{
esp_camera_fb_return(frame);
}
else
{
free(frame);
}
}
}
}
esp_err_t register_lcd(const QueueHandle_t frame_i, const QueueHandle_t frame_o, const bool return_fb)
{
spi_config_t bus_conf = {
.miso_io_num = -1,
.mosi_io_num = 48,
.sclk_io_num = 21,
.miso_io_num = BOARD_LCD_MISO,
.mosi_io_num = BOARD_LCD_MOSI,
.sclk_io_num = BOARD_LCD_SCK,
.max_transfer_sz = 2 * 240 * 240 + 10,
};
spi_bus_handle_t spi_bus = spi_bus_create(SPI2_HOST, &bus_conf);
scr_interface_spi_config_t spi_lcd_cfg = {
.spi_bus = spi_bus,
.pin_num_cs = 43,
.pin_num_dc = 47,
.pin_num_cs = BOARD_LCD_CS,
.pin_num_dc = BOARD_LCD_DC,
.clk_freq = 40 * 1000000,
.swap_data = 0,
};
@ -36,10 +67,10 @@ esp_err_t app_lcd_init()
scr_controller_config_t lcd_cfg = {
.interface_drv = iface_drv,
.pin_num_rst = -1,
.pin_num_bckl = -1,
.pin_num_rst = BOARD_LCD_RST,
.pin_num_bckl = BOARD_LCD_BL,
.rst_active_level = 0,
.bckl_active_level = 1,
.bckl_active_level = 0,
.offset_hor = 0,
.offset_ver = 0,
.width = 240,
@ -55,6 +86,17 @@ esp_err_t app_lcd_init()
g_lcd.get_info(&g_lcd_info);
ESP_LOGI(TAG, "Screen name:%s | width:%d | height:%d", g_lcd_info.name, g_lcd_info.width, g_lcd_info.height);
app_lcd_set_color(0x000000);
vTaskDelay(pdMS_TO_TICKS(500));
app_lcd_draw_wallpaper();
vTaskDelay(pdMS_TO_TICKS(500));
xQueueFrameI = frame_i;
xQueueFrameO = frame_o;
gReturnFB = return_fb;
xTaskCreatePinnedToCore(task_process_handler, TAG, 4 * 1024, NULL, 5, NULL, 1);
return ESP_OK;
}
@ -104,8 +146,3 @@ void app_lcd_set_color(int color)
free(buffer);
}
}
void app_lcd_draw_bitmap(uint16_t *image_ptr, const uint16_t image_height, const uint16_t image_width)
{
g_lcd.draw_bitmap(0, 0, image_width, image_height, image_ptr);
}

View File

@ -0,0 +1,27 @@
#pragma once
#include <stdint.h>
#include "esp_log.h"
#include "screen_driver.h"
#define BOARD_LCD_MOSI 46
#define BOARD_LCD_MISO -1
#define BOARD_LCD_SCK 21
#define BOARD_LCD_CS 44
#define BOARD_LCD_DC 47
#define BOARD_LCD_RST -1
#define BOARD_LCD_BL 48
#ifdef __cplusplus
extern "C"
{
#endif
esp_err_t register_lcd(const QueueHandle_t frame_i, const QueueHandle_t frame_o, const bool return_fb);
void app_lcd_draw_wallpaper();
void app_lcd_set_color(int color);
#ifdef __cplusplus
}
#endif

View File

@ -1,4 +1,4 @@
#include "app_led.h"
#include "who_led.h"
#if CONFIG_LED_ILLUMINATOR_ENABLED
#include "esp_log.h"

View File

@ -0,0 +1,778 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "app_httpd.hpp"
#include <list>
#include "esp_http_server.h"
#include "esp_timer.h"
#include "img_converters.h"
#include "fb_gfx.h"
#include "app_mdns.h"
#include "sdkconfig.h"
#include "who_camera.h"
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
#include "esp32-hal-log.h"
#define TAG ""
#else
#include "esp_log.h"
static const char *TAG = "camera_httpd";
#endif
static QueueHandle_t xQueueFrameI = NULL;
static QueueHandle_t xQueueFrameO = NULL;
static bool gReturnFB = true;
static int8_t detection_enabled = 0;
static int8_t recognition_enabled = 0;
static int8_t is_enrolling = 0;
typedef struct
{
httpd_req_t *req;
size_t len;
} jpg_chunking_t;
#define PART_BOUNDARY "123456789000000000000987654321"
static const char *_STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char *_STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char *_STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\nX-Timestamp: %d.%06d\r\n\r\n";
httpd_handle_t stream_httpd = NULL;
httpd_handle_t camera_httpd = NULL;
static size_t jpg_encode_stream(void *arg, size_t index, const void *data, size_t len)
{
jpg_chunking_t *j = (jpg_chunking_t *)arg;
if (!index)
{
j->len = 0;
}
if (httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK)
{
return 0;
}
j->len += len;
return len;
}
static esp_err_t capture_handler(httpd_req_t *req)
{
camera_fb_t *frame = NULL;
esp_err_t res = ESP_OK;
if (xQueueReceive(xQueueFrameI, &frame, portMAX_DELAY))
{
httpd_resp_set_type(req, "image/jpeg");
httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.jpg");
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
char ts[32];
snprintf(ts, 32, "%ld.%06ld", frame->timestamp.tv_sec, frame->timestamp.tv_usec);
httpd_resp_set_hdr(req, "X-Timestamp", (const char *)ts);
// size_t fb_len = 0;
if (frame->format == PIXFORMAT_JPEG)
{
// fb_len = frame->len;
res = httpd_resp_send(req, (const char *)frame->buf, frame->len);
}
else
{
jpg_chunking_t jchunk = {req, 0};
res = frame2jpg_cb(frame, 80, jpg_encode_stream, &jchunk) ? ESP_OK : ESP_FAIL;
httpd_resp_send_chunk(req, NULL, 0);
// fb_len = jchunk.len;
}
if (xQueueFrameO)
{
xQueueSend(xQueueFrameO, &frame, portMAX_DELAY);
}
else if (gReturnFB)
{
esp_camera_fb_return(frame);
}
else
{
free(frame);
}
}
else
{
ESP_LOGE(TAG, "Camera capture failed");
httpd_resp_send_500(req);
return ESP_FAIL;
}
return res;
}
static esp_err_t stream_handler(httpd_req_t *req)
{
camera_fb_t *frame = NULL;
struct timeval _timestamp;
esp_err_t res = ESP_OK;
size_t _jpg_buf_len = 0;
uint8_t *_jpg_buf = NULL;
char *part_buf[128];
res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
if (res != ESP_OK)
{
return res;
}
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
httpd_resp_set_hdr(req, "X-Framerate", "60");
while (true)
{
if (xQueueReceive(xQueueFrameI, &frame, portMAX_DELAY))
{
_timestamp.tv_sec = frame->timestamp.tv_sec;
_timestamp.tv_usec = frame->timestamp.tv_usec;
if (frame->format == PIXFORMAT_JPEG)
{
_jpg_buf = frame->buf;
_jpg_buf_len = frame->len;
}
else if (!frame2jpg(frame, 80, &_jpg_buf, &_jpg_buf_len))
{
ESP_LOGE(TAG, "JPEG compression failed");
res = ESP_FAIL;
}
}
else
{
res = ESP_FAIL;
}
if (res == ESP_OK)
{
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
}
if (res == ESP_OK)
{
size_t hlen = snprintf((char *)part_buf, 128, _STREAM_PART, _jpg_buf_len, _timestamp.tv_sec, _timestamp.tv_usec);
res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
}
if (res == ESP_OK)
{
res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
}
if (frame->format != PIXFORMAT_JPEG)
{
free(_jpg_buf);
_jpg_buf = NULL;
}
if (xQueueFrameO)
{
xQueueSend(xQueueFrameO, &frame, portMAX_DELAY);
}
else if (gReturnFB)
{
esp_camera_fb_return(frame);
}
else
{
free(frame);
}
if (res != ESP_OK)
{
break;
}
}
return res;
}
static esp_err_t parse_get(httpd_req_t *req, char **obuf)
{
char *buf = NULL;
size_t buf_len = 0;
buf_len = httpd_req_get_url_query_len(req) + 1;
if (buf_len > 1)
{
buf = (char *)malloc(buf_len);
if (!buf)
{
httpd_resp_send_500(req);
return ESP_FAIL;
}
if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK)
{
*obuf = buf;
return ESP_OK;
}
free(buf);
}
httpd_resp_send_404(req);
return ESP_FAIL;
}
static esp_err_t cmd_handler(httpd_req_t *req)
{
char *buf = NULL;
char variable[32];
char value[32];
if (parse_get(req, &buf) != ESP_OK ||
httpd_query_key_value(buf, "var", variable, sizeof(variable)) != ESP_OK ||
httpd_query_key_value(buf, "val", value, sizeof(value)) != ESP_OK)
{
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
free(buf);
int val = atoi(value);
ESP_LOGI(TAG, "%s = %d", variable, val);
sensor_t *s = esp_camera_sensor_get();
int res = 0;
if (!strcmp(variable, "framesize"))
{
if (s->pixformat == PIXFORMAT_JPEG)
{
res = s->set_framesize(s, (framesize_t)val);
if (res == 0)
{
app_mdns_update_framesize(val);
}
}
}
else if (!strcmp(variable, "quality"))
res = s->set_quality(s, val);
else if (!strcmp(variable, "contrast"))
res = s->set_contrast(s, val);
else if (!strcmp(variable, "brightness"))
res = s->set_brightness(s, val);
else if (!strcmp(variable, "saturation"))
res = s->set_saturation(s, val);
else if (!strcmp(variable, "gainceiling"))
res = s->set_gainceiling(s, (gainceiling_t)val);
else if (!strcmp(variable, "colorbar"))
res = s->set_colorbar(s, val);
else if (!strcmp(variable, "awb"))
res = s->set_whitebal(s, val);
else if (!strcmp(variable, "agc"))
res = s->set_gain_ctrl(s, val);
else if (!strcmp(variable, "aec"))
res = s->set_exposure_ctrl(s, val);
else if (!strcmp(variable, "hmirror"))
res = s->set_hmirror(s, val);
else if (!strcmp(variable, "vflip"))
res = s->set_vflip(s, val);
else if (!strcmp(variable, "awb_gain"))
res = s->set_awb_gain(s, val);
else if (!strcmp(variable, "agc_gain"))
res = s->set_agc_gain(s, val);
else if (!strcmp(variable, "aec_value"))
res = s->set_aec_value(s, val);
else if (!strcmp(variable, "aec2"))
res = s->set_aec2(s, val);
else if (!strcmp(variable, "dcw"))
res = s->set_dcw(s, val);
else if (!strcmp(variable, "bpc"))
res = s->set_bpc(s, val);
else if (!strcmp(variable, "wpc"))
res = s->set_wpc(s, val);
else if (!strcmp(variable, "raw_gma"))
res = s->set_raw_gma(s, val);
else if (!strcmp(variable, "lenc"))
res = s->set_lenc(s, val);
else if (!strcmp(variable, "special_effect"))
res = s->set_special_effect(s, val);
else if (!strcmp(variable, "wb_mode"))
res = s->set_wb_mode(s, val);
else if (!strcmp(variable, "ae_level"))
res = s->set_ae_level(s, val);
#ifdef CONFIG_LED_ILLUMINATOR_ENABLED
else if (!strcmp(variable, "led_intensity"))
led_duty = val;
#endif
else if (!strcmp(variable, "face_detect"))
{
detection_enabled = val;
if (!detection_enabled)
{
recognition_enabled = 0;
}
}
else if (!strcmp(variable, "face_enroll"))
is_enrolling = val;
else if (!strcmp(variable, "face_recognize"))
{
recognition_enabled = val;
if (recognition_enabled)
{
detection_enabled = val;
}
}
else
{
res = -1;
}
if (res)
{
return httpd_resp_send_500(req);
}
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, NULL, 0);
}
static int print_reg(char *p, sensor_t *s, uint16_t reg, uint32_t mask)
{
return sprintf(p, "\"0x%x\":%u,", reg, s->get_reg(s, reg, mask));
}
static esp_err_t status_handler(httpd_req_t *req)
{
static char json_response[1024];
sensor_t *s = esp_camera_sensor_get();
char *p = json_response;
*p++ = '{';
if (s->id.PID == OV5640_PID || s->id.PID == OV3660_PID)
{
for (int reg = 0x3400; reg < 0x3406; reg += 2)
{
p += print_reg(p, s, reg, 0xFFF); //12 bit
}
p += print_reg(p, s, 0x3406, 0xFF);
p += print_reg(p, s, 0x3500, 0xFFFF0); //16 bit
p += print_reg(p, s, 0x3503, 0xFF);
p += print_reg(p, s, 0x350a, 0x3FF); //10 bit
p += print_reg(p, s, 0x350c, 0xFFFF); //16 bit
for (int reg = 0x5480; reg <= 0x5490; reg++)
{
p += print_reg(p, s, reg, 0xFF);
}
for (int reg = 0x5380; reg <= 0x538b; reg++)
{
p += print_reg(p, s, reg, 0xFF);
}
for (int reg = 0x5580; reg < 0x558a; reg++)
{
p += print_reg(p, s, reg, 0xFF);
}
p += print_reg(p, s, 0x558a, 0x1FF); //9 bit
}
else
{
p += print_reg(p, s, 0xd3, 0xFF);
p += print_reg(p, s, 0x111, 0xFF);
p += print_reg(p, s, 0x132, 0xFF);
}
p += sprintf(p, "\"board\":\"%s\",", CAMERA_MODULE_NAME);
p += sprintf(p, "\"xclk\":%u,", s->xclk_freq_hz / 1000000);
p += sprintf(p, "\"pixformat\":%u,", s->pixformat);
p += sprintf(p, "\"framesize\":%u,", s->status.framesize);
p += sprintf(p, "\"quality\":%u,", s->status.quality);
p += sprintf(p, "\"brightness\":%d,", s->status.brightness);
p += sprintf(p, "\"contrast\":%d,", s->status.contrast);
p += sprintf(p, "\"saturation\":%d,", s->status.saturation);
p += sprintf(p, "\"sharpness\":%d,", s->status.sharpness);
p += sprintf(p, "\"special_effect\":%u,", s->status.special_effect);
p += sprintf(p, "\"wb_mode\":%u,", s->status.wb_mode);
p += sprintf(p, "\"awb\":%u,", s->status.awb);
p += sprintf(p, "\"awb_gain\":%u,", s->status.awb_gain);
p += sprintf(p, "\"aec\":%u,", s->status.aec);
p += sprintf(p, "\"aec2\":%u,", s->status.aec2);
p += sprintf(p, "\"ae_level\":%d,", s->status.ae_level);
p += sprintf(p, "\"aec_value\":%u,", s->status.aec_value);
p += sprintf(p, "\"agc\":%u,", s->status.agc);
p += sprintf(p, "\"agc_gain\":%u,", s->status.agc_gain);
p += sprintf(p, "\"gainceiling\":%u,", s->status.gainceiling);
p += sprintf(p, "\"bpc\":%u,", s->status.bpc);
p += sprintf(p, "\"wpc\":%u,", s->status.wpc);
p += sprintf(p, "\"raw_gma\":%u,", s->status.raw_gma);
p += sprintf(p, "\"lenc\":%u,", s->status.lenc);
p += sprintf(p, "\"hmirror\":%u,", s->status.hmirror);
p += sprintf(p, "\"dcw\":%u,", s->status.dcw);
p += sprintf(p, "\"colorbar\":%u", s->status.colorbar);
#ifdef CONFIG_LED_ILLUMINATOR_ENABLED
p += sprintf(p, ",\"led_intensity\":%u", led_duty);
#else
p += sprintf(p, ",\"led_intensity\":%d", -1);
#endif
p += sprintf(p, ",\"face_detect\":%u", detection_enabled);
p += sprintf(p, ",\"face_enroll\":%u,", is_enrolling);
p += sprintf(p, "\"face_recognize\":%u", recognition_enabled);
*p++ = '}';
*p++ = 0;
httpd_resp_set_type(req, "application/json");
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, json_response, strlen(json_response));
}
static esp_err_t mdns_handler(httpd_req_t *req)
{
size_t json_len = 0;
const char *json_response = app_mdns_query(&json_len);
httpd_resp_set_type(req, "application/json");
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, json_response, json_len);
}
static esp_err_t xclk_handler(httpd_req_t *req)
{
char *buf = NULL;
char _xclk[32];
if (parse_get(req, &buf) != ESP_OK ||
httpd_query_key_value(buf, "xclk", _xclk, sizeof(_xclk)) != ESP_OK)
{
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
free(buf);
int xclk = atoi(_xclk);
ESP_LOGI(TAG, "Set XCLK: %d MHz", xclk);
sensor_t *s = esp_camera_sensor_get();
int res = s->set_xclk(s, LEDC_TIMER_0, xclk);
if (res)
{
return httpd_resp_send_500(req);
}
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, NULL, 0);
}
static esp_err_t reg_handler(httpd_req_t *req)
{
char *buf = NULL;
char _reg[32];
char _mask[32];
char _val[32];
if (parse_get(req, &buf) != ESP_OK ||
httpd_query_key_value(buf, "reg", _reg, sizeof(_reg)) != ESP_OK ||
httpd_query_key_value(buf, "mask", _mask, sizeof(_mask)) != ESP_OK ||
httpd_query_key_value(buf, "val", _val, sizeof(_val)) != ESP_OK)
{
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
free(buf);
int reg = atoi(_reg);
int mask = atoi(_mask);
int val = atoi(_val);
ESP_LOGI(TAG, "Set Register: reg: 0x%02x, mask: 0x%02x, value: 0x%02x", reg, mask, val);
sensor_t *s = esp_camera_sensor_get();
int res = s->set_reg(s, reg, mask, val);
if (res)
{
return httpd_resp_send_500(req);
}
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, NULL, 0);
}
static esp_err_t greg_handler(httpd_req_t *req)
{
char *buf = NULL;
char _reg[32];
char _mask[32];
if (parse_get(req, &buf) != ESP_OK ||
httpd_query_key_value(buf, "reg", _reg, sizeof(_reg)) != ESP_OK ||
httpd_query_key_value(buf, "mask", _mask, sizeof(_mask)) != ESP_OK)
{
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
free(buf);
int reg = atoi(_reg);
int mask = atoi(_mask);
sensor_t *s = esp_camera_sensor_get();
int res = s->get_reg(s, reg, mask);
if (res < 0)
{
return httpd_resp_send_500(req);
}
ESP_LOGI(TAG, "Get Register: reg: 0x%02x, mask: 0x%02x, value: 0x%02x", reg, mask, res);
char buffer[20];
const char *val = itoa(res, buffer, 10);
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, val, strlen(val));
}
static int parse_get_var(char *buf, const char *key, int def)
{
char _int[16];
if (httpd_query_key_value(buf, key, _int, sizeof(_int)) != ESP_OK)
{
return def;
}
return atoi(_int);
}
static esp_err_t pll_handler(httpd_req_t *req)
{
char *buf = NULL;
if (parse_get(req, &buf) != ESP_OK)
{
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
int bypass = parse_get_var(buf, "bypass", 0);
int mul = parse_get_var(buf, "mul", 0);
int sys = parse_get_var(buf, "sys", 0);
int root = parse_get_var(buf, "root", 0);
int pre = parse_get_var(buf, "pre", 0);
int seld5 = parse_get_var(buf, "seld5", 0);
int pclken = parse_get_var(buf, "pclken", 0);
int pclk = parse_get_var(buf, "pclk", 0);
free(buf);
ESP_LOGI(TAG, "Set Pll: bypass: %d, mul: %d, sys: %d, root: %d, pre: %d, seld5: %d, pclken: %d, pclk: %d", bypass, mul, sys, root, pre, seld5, pclken, pclk);
sensor_t *s = esp_camera_sensor_get();
int res = s->set_pll(s, bypass, mul, sys, root, pre, seld5, pclken, pclk);
if (res)
{
return httpd_resp_send_500(req);
}
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, NULL, 0);
}
static esp_err_t win_handler(httpd_req_t *req)
{
char *buf = NULL;
if (parse_get(req, &buf) != ESP_OK)
{
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
int startX = parse_get_var(buf, "sx", 0);
int startY = parse_get_var(buf, "sy", 0);
int endX = parse_get_var(buf, "ex", 0);
int endY = parse_get_var(buf, "ey", 0);
int offsetX = parse_get_var(buf, "offx", 0);
int offsetY = parse_get_var(buf, "offy", 0);
int totalX = parse_get_var(buf, "tx", 0);
int totalY = parse_get_var(buf, "ty", 0);
int outputX = parse_get_var(buf, "ox", 0);
int outputY = parse_get_var(buf, "oy", 0);
bool scale = parse_get_var(buf, "scale", 0) == 1;
bool binning = parse_get_var(buf, "binning", 0) == 1;
free(buf);
ESP_LOGI(TAG, "Set Window: Start: %d %d, End: %d %d, Offset: %d %d, Total: %d %d, Output: %d %d, Scale: %u, Binning: %u", startX, startY, endX, endY, offsetX, offsetY, totalX, totalY, outputX, outputY, scale, binning);
sensor_t *s = esp_camera_sensor_get();
int res = s->set_res_raw(s, startX, startY, endX, endY, offsetX, offsetY, totalX, totalY, outputX, outputY, scale, binning);
if (res)
{
return httpd_resp_send_500(req);
}
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, NULL, 0);
}
static esp_err_t index_handler(httpd_req_t *req)
{
extern const unsigned char index_ov2640_html_gz_start[] asm("_binary_index_ov2640_html_gz_start");
extern const unsigned char index_ov2640_html_gz_end[] asm("_binary_index_ov2640_html_gz_end");
size_t index_ov2640_html_gz_len = index_ov2640_html_gz_end - index_ov2640_html_gz_start;
extern const unsigned char index_ov3660_html_gz_start[] asm("_binary_index_ov3660_html_gz_start");
extern const unsigned char index_ov3660_html_gz_end[] asm("_binary_index_ov3660_html_gz_end");
size_t index_ov3660_html_gz_len = index_ov3660_html_gz_end - index_ov3660_html_gz_start;
extern const unsigned char index_ov5640_html_gz_start[] asm("_binary_index_ov5640_html_gz_start");
extern const unsigned char index_ov5640_html_gz_end[] asm("_binary_index_ov5640_html_gz_end");
size_t index_ov5640_html_gz_len = index_ov5640_html_gz_end - index_ov5640_html_gz_start;
httpd_resp_set_type(req, "text/html");
httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
sensor_t *s = esp_camera_sensor_get();
if (s != NULL)
{
if (s->id.PID == OV3660_PID)
{
return httpd_resp_send(req, (const char *)index_ov3660_html_gz_start, index_ov3660_html_gz_len);
}
else if (s->id.PID == OV5640_PID)
{
return httpd_resp_send(req, (const char *)index_ov5640_html_gz_start, index_ov5640_html_gz_len);
}
else
{
return httpd_resp_send(req, (const char *)index_ov2640_html_gz_start, index_ov2640_html_gz_len);
}
}
else
{
ESP_LOGE(TAG, "Camera sensor not found");
return httpd_resp_send_500(req);
}
}
static esp_err_t monitor_handler(httpd_req_t *req)
{
extern const unsigned char monitor_html_gz_start[] asm("_binary_monitor_html_gz_start");
extern const unsigned char monitor_html_gz_end[] asm("_binary_monitor_html_gz_end");
size_t monitor_html_gz_len = monitor_html_gz_end - monitor_html_gz_start;
httpd_resp_set_type(req, "text/html");
httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
return httpd_resp_send(req, (const char *)monitor_html_gz_start, monitor_html_gz_len);
}
void register_httpd(const QueueHandle_t frame_i, const QueueHandle_t frame_o, const bool return_fb)
{
xQueueFrameI = frame_i;
xQueueFrameO = frame_o;
gReturnFB = return_fb;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.max_uri_handlers = 12;
httpd_uri_t index_uri = {
.uri = "/",
.method = HTTP_GET,
.handler = index_handler,
.user_ctx = NULL};
httpd_uri_t status_uri = {
.uri = "/status",
.method = HTTP_GET,
.handler = status_handler,
.user_ctx = NULL};
httpd_uri_t cmd_uri = {
.uri = "/control",
.method = HTTP_GET,
.handler = cmd_handler,
.user_ctx = NULL};
httpd_uri_t capture_uri = {
.uri = "/capture",
.method = HTTP_GET,
.handler = capture_handler,
.user_ctx = NULL};
httpd_uri_t stream_uri = {
.uri = "/stream",
.method = HTTP_GET,
.handler = stream_handler,
.user_ctx = NULL};
httpd_uri_t xclk_uri = {
.uri = "/xclk",
.method = HTTP_GET,
.handler = xclk_handler,
.user_ctx = NULL};
httpd_uri_t reg_uri = {
.uri = "/reg",
.method = HTTP_GET,
.handler = reg_handler,
.user_ctx = NULL};
httpd_uri_t greg_uri = {
.uri = "/greg",
.method = HTTP_GET,
.handler = greg_handler,
.user_ctx = NULL};
httpd_uri_t pll_uri = {
.uri = "/pll",
.method = HTTP_GET,
.handler = pll_handler,
.user_ctx = NULL};
httpd_uri_t win_uri = {
.uri = "/resolution",
.method = HTTP_GET,
.handler = win_handler,
.user_ctx = NULL};
httpd_uri_t mdns_uri = {
.uri = "/mdns",
.method = HTTP_GET,
.handler = mdns_handler,
.user_ctx = NULL};
httpd_uri_t monitor_uri = {
.uri = "/monitor",
.method = HTTP_GET,
.handler = monitor_handler,
.user_ctx = NULL};
ESP_LOGI(TAG, "Starting web server on port: '%d'", config.server_port);
if (httpd_start(&camera_httpd, &config) == ESP_OK)
{
httpd_register_uri_handler(camera_httpd, &index_uri);
httpd_register_uri_handler(camera_httpd, &cmd_uri);
httpd_register_uri_handler(camera_httpd, &status_uri);
httpd_register_uri_handler(camera_httpd, &capture_uri);
httpd_register_uri_handler(camera_httpd, &xclk_uri);
httpd_register_uri_handler(camera_httpd, &reg_uri);
httpd_register_uri_handler(camera_httpd, &greg_uri);
httpd_register_uri_handler(camera_httpd, &pll_uri);
httpd_register_uri_handler(camera_httpd, &win_uri);
httpd_register_uri_handler(camera_httpd, &mdns_uri);
httpd_register_uri_handler(camera_httpd, &monitor_uri);
}
config.server_port += 1;
config.ctrl_port += 1;
ESP_LOGI(TAG, "Starting stream server on port: '%d'", config.server_port);
if (httpd_start(&stream_httpd, &config) == ESP_OK)
{
httpd_register_uri_handler(stream_httpd, &stream_uri);
}
}

View File

@ -0,0 +1,8 @@
#pragma once
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
void register_httpd(const QueueHandle_t frame_i, const QueueHandle_t frame_o, const bool return_fb);

View File

@ -0,0 +1,250 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <string.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "esp_camera.h"
#include "mdns.h"
#include "who_camera.h"
static const char *TAG = "camera mdns";
static const char * service_name = "_esp-cam";
static const char * proto = "_tcp";
static mdns_result_t * found_cams = NULL;
static SemaphoreHandle_t query_lock = NULL;
static char iname[64];
static char hname[64];
static char framesize[4];
static char pixformat[4];
static const char * model = NULL;
static void mdns_query_for_cams()
{
mdns_result_t * new_cams = NULL;
esp_err_t err = mdns_query_ptr(service_name, proto, 5000, 4, &new_cams);
if(err){
ESP_LOGE(TAG, "MDNS Query Failed: %s", esp_err_to_name(err));
return;
}
xSemaphoreTake(query_lock, portMAX_DELAY);
if (found_cams != NULL) {
mdns_query_results_free(found_cams);
}
found_cams = new_cams;
xSemaphoreGive(query_lock);
}
static void mdns_task(void * arg)
{
for (;;) {
mdns_query_for_cams();
//delay 55 seconds
vTaskDelay((55 * 1000) / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
/*
* Public Functions
*/
const char * app_mdns_query(size_t * out_len)
{
//build JSON
static char json_response[2048];
char *p = json_response;
*p++ = '[';
//add own data first
tcpip_adapter_ip_info_t ip;
if (strlen(CONFIG_ESP_WIFI_SSID)) {
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip);
} else {
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ip);
}
*p++ = '{';
p += sprintf(p, "\"instance\":\"%s\",", iname);
p += sprintf(p, "\"host\":\"%s.local\",", hname);
p += sprintf(p, "\"port\":80,");
p += sprintf(p, "\"txt\":{");
p += sprintf(p, "\"pixformat\":\"%s\",", pixformat);
p += sprintf(p, "\"framesize\":\"%s\",", framesize);
p += sprintf(p, "\"stream_port\":\"81\",");
p += sprintf(p, "\"board\":\"%s\",", CAMERA_MODULE_NAME);
p += sprintf(p, "\"model\":\"%s\"", model);
*p++ = '}';
*p++ = ',';
p += sprintf(p, "\"ip\":\"" IPSTR "\",", IP2STR(&(ip.ip)));
p += sprintf(p, "\"id\":\"" IPSTR ":80\",", IP2STR(&(ip.ip)));
p += sprintf(p, "\"service\":\"%s\",", service_name);
p += sprintf(p, "\"proto\":\"%s\"", proto);
*p++ = '}';
xSemaphoreTake(query_lock, portMAX_DELAY);
if (found_cams) {
*p++ = ',';
}
mdns_result_t * r = found_cams;
mdns_ip_addr_t * a = NULL;
int t;
while(r){
*p++ = '{';
if(r->instance_name){
p += sprintf(p, "\"instance\":\"%s\",", r->instance_name);
}
if(r->hostname){
p += sprintf(p, "\"host\":\"%s.local\",", r->hostname);
p += sprintf(p, "\"port\":%u,", r->port);
}
if(r->txt_count){
p += sprintf(p, "\"txt\":{");
for(t=0; t<r->txt_count; t++){
if (t > 0) {
*p++ = ',';
}
p += sprintf(p, "\"%s\":\"%s\"", r->txt[t].key, r->txt[t].value?r->txt[t].value:"NULL");
}
*p++ = '}';
*p++ = ',';
}
a = r->addr;
while(a){
if(a->addr.type != IPADDR_TYPE_V6){
p += sprintf(p, "\"ip\":\"" IPSTR "\",", IP2STR(&(a->addr.u_addr.ip4)));
p += sprintf(p, "\"id\":\"" IPSTR ":%u\",", IP2STR(&(a->addr.u_addr.ip4)), r->port);
break;
}
a = a->next;
}
p += sprintf(p, "\"service\":\"%s\",", service_name);
p += sprintf(p, "\"proto\":\"%s\"", proto);
*p++ = '}';
r = r->next;
if (r) {
*p++ = ',';
}
}
xSemaphoreGive(query_lock);
*p++ = ']';
*out_len = (uint32_t)p - (uint32_t)json_response;
*p++ = '\0';
ESP_LOGI(TAG, "JSON: %uB", *out_len);
return (const char *)json_response;
}
void app_mdns_update_framesize(int size)
{
snprintf(framesize, 4, "%d", size);
if(mdns_service_txt_item_set(service_name, proto, "framesize", (char*)framesize)){
ESP_LOGE(TAG, "mdns_service_txt_item_set() framesize Failed");
}
}
void app_mdns_main()
{
uint8_t mac[6];
query_lock = xSemaphoreCreateBinary();
if (query_lock == NULL) {
ESP_LOGE(TAG, "xSemaphoreCreateMutex() Failed");
return;
}
xSemaphoreGive(query_lock);
sensor_t * s = esp_camera_sensor_get();
if(s == NULL){
return;
}
switch(s->id.PID){
case OV2640_PID: model = "OV2640"; break;
case OV3660_PID: model = "OV3660"; break;
case OV5640_PID: model = "OV5640"; break;
case OV7725_PID: model = "OV7725"; break;
default: model = "UNKNOWN"; break;
}
if (strlen(CONFIG_ESP_HOST_NAME) > 0) {
snprintf(iname, 64, "%s", CONFIG_ESP_HOST_NAME);
} else {
if (esp_read_mac(mac, ESP_MAC_WIFI_STA) != ESP_OK) {
ESP_LOGE(TAG, "esp_read_mac() Failed");
return;
}
snprintf(iname, 64, "%s-%s-%02X%02X%02X", CAMERA_MODULE_NAME, model, mac[3], mac[4], mac[5]);
}
snprintf(framesize, 4, "%d", s->status.framesize);
snprintf(pixformat, 4, "%d", s->pixformat);
char * src = iname, * dst = hname, c;
while (*src) {
c = *src++;
if (c >= 'A' && c <= 'Z') {
c -= 'A' - 'a';
}
*dst++ = c;
}
*dst++ = '\0';
if(mdns_init() != ESP_OK){
ESP_LOGE(TAG, "mdns_init() Failed");
return;
}
if(mdns_hostname_set(hname) != ESP_OK){
ESP_LOGE(TAG, "mdns_hostname_set(\"%s\") Failed", hname);
return;
}
if(mdns_instance_name_set(iname) != ESP_OK){
ESP_LOGE(TAG, "mdns_instance_name_set(\"%s\") Failed", iname);
return;
}
if(mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0) != ESP_OK){
ESP_LOGE(TAG, "mdns_service_add() HTTP Failed");
return;
}
mdns_txt_item_t camera_txt_data[] = {
{(char*)"board" ,(char*)CAMERA_MODULE_NAME},
{(char*)"model" ,(char*)model},
{(char*)"stream_port" ,(char*)"81"},
{(char*)"framesize" ,(char*)framesize},
{(char*)"pixformat" ,(char*)pixformat}
};
if(mdns_service_add(NULL, service_name, proto, 80, camera_txt_data, 5)) {
ESP_LOGE(TAG, "mdns_service_add() ESP-CAM Failed");
return;
}
xTaskCreate(mdns_task, "mdns-cam", 2048, NULL, 2, NULL);
}

View File

@ -0,0 +1,16 @@
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
#include <stddef.h>
void app_mdns_main();
void app_mdns_update_framesize(int size);
const char *app_mdns_query(size_t *out_len);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,196 @@
/* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "sdkconfig.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "mdns.h"
/* The examples use WiFi configuration that you can set via 'make menuconfig'.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
#define EXAMPLE_ESP_MAXIMUM_RETRY CONFIG_ESP_MAXIMUM_RETRY
#define EXAMPLE_ESP_WIFI_AP_SSID CONFIG_ESP_WIFI_AP_SSID
#define EXAMPLE_ESP_WIFI_AP_PASS CONFIG_ESP_WIFI_AP_PASSWORD
#define EXAMPLE_MAX_STA_CONN CONFIG_MAX_STA_CONN
#define EXAMPLE_IP_ADDR CONFIG_SERVER_IP
#define EXAMPLE_ESP_WIFI_AP_CHANNEL CONFIG_ESP_WIFI_AP_CHANNEL
static const char *TAG = "camera wifi";
static int s_retry_num = 0;
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
switch (event->event_id)
{
case SYSTEM_EVENT_AP_STACONNECTED:
ESP_LOGI(TAG, "station:" MACSTR " join, AID=%d",
MAC2STR(event->event_info.sta_connected.mac),
event->event_info.sta_connected.aid);
break;
case SYSTEM_EVENT_AP_STADISCONNECTED:
ESP_LOGI(TAG, "station:" MACSTR "leave, AID=%d",
MAC2STR(event->event_info.sta_disconnected.mac),
event->event_info.sta_disconnected.aid);
break;
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP:
ESP_LOGI(TAG, "got ip:%s",
ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
s_retry_num = 0;
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
{
if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY)
{
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
}
ESP_LOGI(TAG, "connect to the AP fail");
break;
}
default:
break;
}
mdns_handle_system_event(ctx, event);
return ESP_OK;
}
void wifi_init_softap()
{
if (strcmp(EXAMPLE_IP_ADDR, "192.168.4.1"))
{
int a, b, c, d;
sscanf(EXAMPLE_IP_ADDR, "%d.%d.%d.%d", &a, &b, &c, &d);
tcpip_adapter_ip_info_t ip_info;
IP4_ADDR(&ip_info.ip, a, b, c, d);
IP4_ADDR(&ip_info.gw, a, b, c, d);
IP4_ADDR(&ip_info.netmask, 255, 255, 255, 0);
ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(WIFI_IF_AP));
ESP_ERROR_CHECK(tcpip_adapter_set_ip_info(WIFI_IF_AP, &ip_info));
ESP_ERROR_CHECK(tcpip_adapter_dhcps_start(WIFI_IF_AP));
}
wifi_config_t wifi_config;
memset(&wifi_config, 0, sizeof(wifi_config_t));
snprintf((char *)wifi_config.ap.ssid, 32, "%s", EXAMPLE_ESP_WIFI_AP_SSID);
wifi_config.ap.ssid_len = strlen((char *)wifi_config.ap.ssid);
snprintf((char *)wifi_config.ap.password, 64, "%s", EXAMPLE_ESP_WIFI_AP_PASS);
wifi_config.ap.max_connection = EXAMPLE_MAX_STA_CONN;
wifi_config.ap.authmode = WIFI_AUTH_WPA_WPA2_PSK;
if (strlen(EXAMPLE_ESP_WIFI_AP_PASS) == 0)
{
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
}
if (strlen(EXAMPLE_ESP_WIFI_AP_CHANNEL))
{
int channel;
sscanf(EXAMPLE_ESP_WIFI_AP_CHANNEL, "%d", &channel);
wifi_config.ap.channel = channel;
}
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config));
ESP_LOGI(TAG, "wifi_init_softap finished.SSID:%s password:%s",
EXAMPLE_ESP_WIFI_AP_SSID, EXAMPLE_ESP_WIFI_AP_PASS);
}
void wifi_init_sta()
{
wifi_config_t wifi_config;
memset(&wifi_config, 0, sizeof(wifi_config_t));
snprintf((char *)wifi_config.sta.ssid, 32, "%s", EXAMPLE_ESP_WIFI_SSID);
snprintf((char *)wifi_config.sta.password, 64, "%s", EXAMPLE_ESP_WIFI_PASS);
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_LOGI(TAG, "wifi_init_sta finished.");
ESP_LOGI(TAG, "connect to ap SSID:%s password:%s",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
}
void app_wifi_main()
{
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
wifi_mode_t mode = WIFI_MODE_NULL;
if (strlen(EXAMPLE_ESP_WIFI_AP_SSID) && strlen(EXAMPLE_ESP_WIFI_SSID))
{
mode = WIFI_MODE_APSTA;
}
else if (strlen(EXAMPLE_ESP_WIFI_AP_SSID))
{
mode = WIFI_MODE_AP;
}
else if (strlen(EXAMPLE_ESP_WIFI_SSID))
{
mode = WIFI_MODE_STA;
}
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
{
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
if (mode == WIFI_MODE_NULL)
{
ESP_LOGW(TAG, "Neither AP or STA have been configured. WiFi will be off.");
return;
}
tcpip_adapter_init();
ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_mode(mode));
if (mode & WIFI_MODE_AP)
{
wifi_init_softap();
}
if (mode & WIFI_MODE_STA)
{
wifi_init_sta();
}
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
}

View File

@ -0,0 +1,37 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2017 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef _APP_WIFI_H_
#define _APP_WIFI_H_
#ifdef __cplusplus
extern "C" {
#endif
void app_wifi_main();
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,7 @@
#!/bin/bash
for file in `ls *.html`; do
echo "Compressing: $file"
cp "$file" "copy_$file" && \
gzip -f "$file" && \
mv "copy_$file" "$file"
done

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.