diff --git a/components/esp32-camera b/components/esp32-camera index 193b090..4af111a 160000 --- a/components/esp32-camera +++ b/components/esp32-camera @@ -1 +1 @@ -Subproject commit 193b090df99dd73e18df4d8ab494ebd32d433648 +Subproject commit 4af111a5e274a2973fa10cd3c1ec69174a1bdb93 diff --git a/examples/single_chip/camera_web_server/README.md b/examples/single_chip/camera_web_server/README.md index 52316ff..7b7782b 100755 --- a/examples/single_chip/camera_web_server/README.md +++ b/examples/single_chip/camera_web_server/README.md @@ -5,7 +5,7 @@ To run this example, you need the following components: * An ESP32 Module: Either **ESP32-WROVER-KIT** or **ESP-EYE**, which we highly recommend for beginners, is used in this example. -* A Camera Module: Either **OV2640** or **OV3660** image sensor, which we highly recommend for beginners, is used in this example. +* A Camera Module: Either **OV2640** or **OV3660** or **OV5640** image sensor, which we highly recommend for beginners, is used in this example. # Quick Start @@ -17,5 +17,6 @@ After you've completed the hardware settings, please follow the steps below: 4. **Open Your Browser** and point it to `http://[ip-of-esp32]/`; 5. **To Get Image** press `Get Still` or `Start Stream`; 6. **Use The Options** to enable/disable Face Detection, Face Recognition and more; +t. **View The Stream** in a player like VLC: Open Network `http://[ip-of-esp32]:81/stream`; For more details of the http handler, please refer to [esp32-camera](https://github.com/espressif/esp32-camera). diff --git a/examples/single_chip/camera_web_server/main/CMakeLists.txt b/examples/single_chip/camera_web_server/main/CMakeLists.txt index cb2f78c..86bc4e9 100644 --- a/examples/single_chip/camera_web_server/main/CMakeLists.txt +++ b/examples/single_chip/camera_web_server/main/CMakeLists.txt @@ -11,6 +11,7 @@ set(COMPONENT_REQUIRES set(COMPONENT_EMBED_FILES "www/index_ov2640.html.gz" - "www/index_ov3660.html.gz") + "www/index_ov3660.html.gz" + "www/index_ov5640.html.gz") register_component() diff --git a/examples/single_chip/camera_web_server/main/Kconfig.projbuild b/examples/single_chip/camera_web_server/main/Kconfig.projbuild index 79e41be..c591426 100644 --- a/examples/single_chip/camera_web_server/main/Kconfig.projbuild +++ b/examples/single_chip/camera_web_server/main/Kconfig.projbuild @@ -100,6 +100,8 @@ choice CAMERA_MODEL config CAMERA_MODEL_WROVER_KIT bool "WROVER-KIT With OV2640 Module" +config CAMERA_MODEL_ESP32_CAM_BOARD + bool "ESP32 Camera Development Board" config CAMERA_MODEL_ESP_EYE bool "ESP_EYE DevKit" config CAMERA_MODEL_M5STACK_PSRAM diff --git a/examples/single_chip/camera_web_server/main/app_camera.c b/examples/single_chip/camera_web_server/main/app_camera.c index 0c03df5..6d4fa89 100755 --- a/examples/single_chip/camera_web_server/main/app_camera.c +++ b/examples/single_chip/camera_web_server/main/app_camera.c @@ -30,7 +30,7 @@ static const char *TAG = "app_camera"; void app_camera_main () { -#if CONFIG_CAMERA_MODEL_ESP_EYE +#if CONFIG_CAMERA_MODEL_ESP_EYE || CONFIG_CAMERA_MODEL_ESP32_CAM_BOARD /* IO13, IO14 is designed for JTAG by default, * to use it as generalized input, * firstly declair it as pullup input */ @@ -97,7 +97,7 @@ void app_camera_main () config.xclk_freq_hz = 20000000; config.pixel_format = PIXFORMAT_JPEG; //init with high specs to pre-allocate larger buffers - config.frame_size = FRAMESIZE_UXGA; + config.frame_size = FRAMESIZE_QSXGA; config.jpeg_quality = 10; config.fb_count = 2; @@ -116,5 +116,5 @@ void app_camera_main () s->set_saturation(s, -2);//lower the saturation } //drop down frame size for higher initial frame rate - s->set_framesize(s, FRAMESIZE_QVGA); + s->set_framesize(s, FRAMESIZE_HD); } diff --git a/examples/single_chip/camera_web_server/main/app_httpd.c b/examples/single_chip/camera_web_server/main/app_httpd.c index e51304b..3099791 100644 --- a/examples/single_chip/camera_web_server/main/app_httpd.c +++ b/examples/single_chip/camera_web_server/main/app_httpd.c @@ -75,7 +75,7 @@ typedef struct #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\n\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; @@ -341,6 +341,10 @@ static esp_err_t capture_handler(httpd_req_t *req) 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", fb->timestamp.tv_sec, fb->timestamp.tv_usec); + httpd_resp_set_hdr(req, "X-Timestamp", (const char *)ts); + #if CONFIG_ESP_FACE_DETECT_ENABLED size_t out_len, out_width, out_height; uint8_t *out_buf; @@ -437,10 +441,11 @@ static esp_err_t capture_handler(httpd_req_t *req) static esp_err_t stream_handler(httpd_req_t *req) { camera_fb_t *fb = NULL; + struct timeval _timestamp; esp_err_t res = ESP_OK; size_t _jpg_buf_len = 0; uint8_t *_jpg_buf = NULL; - char *part_buf[64]; + char *part_buf[128]; #if CONFIG_ESP_FACE_DETECT_ENABLED dl_matrix3du_t *image_matrix = NULL; bool detected = false; @@ -465,6 +470,7 @@ static esp_err_t stream_handler(httpd_req_t *req) } httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_set_hdr(req, "X-Framerate", "60"); #ifdef CONFIG_LED_ILLUMINATOR_ENABLED enable_led(true); @@ -486,6 +492,8 @@ static esp_err_t stream_handler(httpd_req_t *req) } else { + _timestamp.tv_sec = fb->timestamp.tv_sec; + _timestamp.tv_usec = fb->timestamp.tv_usec; #if CONFIG_ESP_FACE_DETECT_ENABLED fr_start = esp_timer_get_time(); fr_ready = fr_start; @@ -593,7 +601,7 @@ static esp_err_t stream_handler(httpd_req_t *req) } if (res == ESP_OK) { - size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len); + 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) @@ -654,60 +662,49 @@ static esp_err_t stream_handler(httpd_req_t *req) return res; } -static esp_err_t cmd_handler(httpd_req_t *req) +static esp_err_t parse_get(httpd_req_t *req, char **obuf) { - char *buf; - size_t buf_len; - char variable[32] = { - 0, - }; - char value[32] = { - 0, - }; + char *buf = NULL; + size_t buf_len = 0; buf_len = httpd_req_get_url_query_len(req) + 1; - if (buf_len > 1) - { + if (buf_len > 1) { buf = (char *)malloc(buf_len); - if (!buf) - { + if (!buf) { httpd_resp_send_500(req); return ESP_FAIL; } - if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) - { - if (httpd_query_key_value(buf, "var", variable, sizeof(variable)) == ESP_OK && - httpd_query_key_value(buf, "val", value, sizeof(value)) == ESP_OK) - { - } - else - { - free(buf); - httpd_resp_send_404(req); - return ESP_FAIL; - } - } - else - { - free(buf); - httpd_resp_send_404(req); - return ESP_FAIL; + if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) { + *obuf = buf; + return ESP_OK; } free(buf); } - else - { + 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 (!strcmp(variable, "framesize")) { if (s->pixformat == PIXFORMAT_JPEG) res = s->set_framesize(s, (framesize_t)val); } @@ -758,8 +755,7 @@ static esp_err_t cmd_handler(httpd_req_t *req) else if (!strcmp(variable, "ae_level")) res = s->set_ae_level(s, val); #ifdef CONFIG_LED_ILLUMINATOR_ENABLED - else if (!strcmp(variable, "led_intensity")) - { + else if (!strcmp(variable, "led_intensity")) { led_duty = val; if (isStreaming) enable_led(true); @@ -767,12 +763,10 @@ static esp_err_t cmd_handler(httpd_req_t *req) #endif #if CONFIG_ESP_FACE_DETECT_ENABLED - else if (!strcmp(variable, "face_detect")) - { + else if (!strcmp(variable, "face_detect")) { detection_enabled = val; #if CONFIG_ESP_FACE_RECOGNITION_ENABLED - if (!detection_enabled) - { + if (!detection_enabled) { recognition_enabled = 0; } #endif @@ -780,23 +774,19 @@ static esp_err_t cmd_handler(httpd_req_t *req) #if CONFIG_ESP_FACE_RECOGNITION_ENABLED else if (!strcmp(variable, "face_enroll")) is_enrolling = val; - else if (!strcmp(variable, "face_recognize")) - { + else if (!strcmp(variable, "face_recognize")) { recognition_enabled = val; - if (recognition_enabled) - { + if (recognition_enabled) { detection_enabled = val; } } #endif #endif - else - { + else { res = -1; } - if (res) - { + if (res) { return httpd_resp_send_500(req); } @@ -804,6 +794,10 @@ static esp_err_t cmd_handler(httpd_req_t *req) 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]; @@ -812,6 +806,35 @@ static esp_err_t status_handler(httpd_req_t *req) 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, "\"framesize\":%u,", s->status.framesize); p += sprintf(p, "\"quality\":%u,", s->status.quality); p += sprintf(p, "\"brightness\":%d,", s->status.brightness); @@ -855,6 +878,169 @@ static esp_err_t status_handler(httpd_req_t *req) return httpd_resp_send(req, json_response, strlen(json_response)); } +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"); @@ -865,22 +1051,22 @@ static esp_err_t index_handler(httpd_req_t *req) 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) - { + 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 - { + } 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 - { + } else { ESP_LOGE(TAG, "Camera sensor not found"); return httpd_resp_send_500(req); } @@ -889,6 +1075,7 @@ static esp_err_t index_handler(httpd_req_t *req) void app_httpd_main() { httpd_config_t config = HTTPD_DEFAULT_CONFIG(); + config.max_uri_handlers = 10; httpd_uri_t index_uri = { .uri = "/", @@ -920,6 +1107,36 @@ void app_httpd_main() .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}; + ra_filter_init(&ra_filter, 20); #if CONFIG_ESP_FACE_DETECT_ENABLED @@ -956,6 +1173,12 @@ void app_httpd_main() 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, ®_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); } config.server_port += 1; diff --git a/examples/single_chip/camera_web_server/main/component.mk b/examples/single_chip/camera_web_server/main/component.mk index c2ecf38..0d16c28 100644 --- a/examples/single_chip/camera_web_server/main/component.mk +++ b/examples/single_chip/camera_web_server/main/component.mk @@ -8,3 +8,4 @@ # COMPONENT_EMBED_FILES := www/index_ov2640.html.gz COMPONENT_EMBED_FILES += www/index_ov3660.html.gz +COMPONENT_EMBED_FILES += www/index_ov5640.html.gz diff --git a/examples/single_chip/camera_web_server/main/include/app_camera.h b/examples/single_chip/camera_web_server/main/include/app_camera.h index 8cccfd4..be229b4 100755 --- a/examples/single_chip/camera_web_server/main/include/app_camera.h +++ b/examples/single_chip/camera_web_server/main/include/app_camera.h @@ -43,6 +43,25 @@ #define HREF_GPIO_NUM 23 #define PCLK_GPIO_NUM 22 +#elif CONFIG_CAMERA_MODEL_ESP32_CAM_BOARD +#define PWDN_GPIO_NUM 32 +#define RESET_GPIO_NUM 33 +#define XCLK_GPIO_NUM 4 +#define SIOD_GPIO_NUM 18 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 36 +#define Y8_GPIO_NUM 19 +#define Y7_GPIO_NUM 21 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 35 +#define Y4_GPIO_NUM 14 +#define Y3_GPIO_NUM 13 +#define Y2_GPIO_NUM 34 +#define VSYNC_GPIO_NUM 5 +#define HREF_GPIO_NUM 27 +#define PCLK_GPIO_NUM 25 + #elif CONFIG_CAMERA_MODEL_ESP_EYE #define PWDN_GPIO_NUM -1 #define RESET_GPIO_NUM -1 diff --git a/examples/single_chip/camera_web_server/main/www/index_ov2640.html b/examples/single_chip/camera_web_server/main/www/index_ov2640.html index 3477ebb..cac38f9 100644 --- a/examples/single_chip/camera_web_server/main/www/index_ov2640.html +++ b/examples/single_chip/camera_web_server/main/www/index_ov2640.html @@ -345,6 +345,38 @@ .hidden { display: none } + + input[type=text] { + border: 1px solid #363636; + font-size: 14px; + height: 20px; + margin: 1px; + outline: 0; + border-radius: 5px + } + + .inline-button { + line-height: 20px; + margin: 2px; + padding: 1px 4px 2px 4px; + } + + label.toggle-section-label { + cursor: pointer; + display: block + } + + input.toggle-section-button { + outline: 0; + opacity: 0; + width: 0; + height: 0 + } + + input.toggle-section-button:checked+section.toggle-section { + display: none + } + @@ -356,24 +388,41 @@
@@ -572,6 +714,187 @@ document.addEventListener('DOMContentLoaded', function (event) { var baseHost = document.location.origin var streamUrl = baseHost + ':81' + function fetchUrl(url, cb){ + fetch(url) + .then(function (response) { + if (response.status !== 200) { + cb(response.status, response.statusText); + } else { + response.text().then(function(data){ + cb(200, data); + }).catch(function(err) { + cb(-1, err); + }); + } + }) + .catch(function(err) { + cb(-1, err); + }); + } + + function setReg(reg, offset, mask, value, cb){ + //console.log('Set Reg', '0x'+reg.toString(16), offset, '0x'+mask.toString(16), '0x'+value.toString(16), '('+value+')'); + value = (value & mask) << offset; + mask = mask << offset; + fetchUrl(`${baseHost}/reg?reg=${reg}&mask=${mask}&val=${value}`, cb); + } + + function getReg(reg, offset, mask, cb){ + mask = mask << offset; + fetchUrl(`${baseHost}/greg?reg=${reg}&mask=${mask}`, function(code, txt){ + let value = 0; + if(code == 200){ + value = parseInt(txt); + value = (value & mask) >> offset; + txt = ''+value; + } + cb(code, txt); + }); + } + + function setXclk(xclk, cb){ + fetchUrl(`${baseHost}/xclk?xclk=${xclk}`, cb); + } + + function setWindow(start_x, start_y, end_x, end_y, offset_x, offset_y, total_x, total_y, output_x, output_y, scaling, binning, cb){ + fetchUrl(`${baseHost}/resolution?sx=${start_x}&sy=${start_y}&ex=${end_x}&ey=${end_y}&offx=${offset_x}&offy=${offset_y}&tx=${total_x}&ty=${total_y}&ox=${output_x}&oy=${output_y}&scale=${scaling}&binning=${binning}`, cb); + } + + const setRegButton = document.getElementById('set-reg') + setRegButton.onclick = () => { + let reg = parseInt(document.getElementById('reg-addr').value); + let mask = parseInt(document.getElementById('reg-mask').value); + let value = parseInt(document.getElementById('reg-value').value); + + setReg(reg, 0, mask, value, function(code, txt){ + if(code != 200){ + alert('Error['+code+']: '+txt); + } + }); + } + + const getRegButton = document.getElementById('get-reg') + getRegButton.onclick = () => { + let reg = parseInt(document.getElementById('get-reg-addr').value); + let mask = parseInt(document.getElementById('get-reg-mask').value); + let value = document.getElementById('get-reg-value'); + + getReg(reg, 0, mask, function(code, txt){ + if(code != 200){ + value.innerHTML = 'Error['+code+']: '+txt; + } else { + value.innerHTML = '0x'+parseInt(txt).toString(16)+' ('+txt+')'; + } + }); + } + + const setXclkButton = document.getElementById('set-xclk') + setXclkButton.onclick = () => { + let xclk = parseInt(document.getElementById('xclk').value); + + setXclk(xclk, function(code, txt){ + if(code != 200){ + alert('Error['+code+']: '+txt); + } + }); + } + + const setResButton = document.getElementById('set-resolution') + setResButton.onclick = () => { + let start_x = parseInt(document.getElementById('start-x').value); + let offset_x = parseInt(document.getElementById('offset-x').value); + let offset_y = parseInt(document.getElementById('offset-y').value); + let total_x = parseInt(document.getElementById('total-x').value); + let total_y = parseInt(document.getElementById('total-y').value); + let output_x = parseInt(document.getElementById('output-x').value); + let output_y = parseInt(document.getElementById('output-y').value); + + setWindow(start_x, 0, 0, 0, offset_x, offset_y, total_x, total_y, output_x, output_y, false, false, function(code, txt){ + if(code != 200){ + alert('Error['+code+']: '+txt); + } + }); + } + + const setRegValue = (el) => { + let reg = el.attributes.reg?parseInt(el.attributes.reg.nodeValue):0; + let offset = el.attributes.offset?parseInt(el.attributes.offset.nodeValue):0; + let mask = el.attributes.mask?parseInt(el.attributes.mask.nodeValue):255; + let value = 0; + switch (el.type) { + case 'checkbox': + value = el.checked ? mask : 0; + break; + case 'range': + case 'text': + case 'select-one': + value = el.value; + break + default: + return; + } + + setReg(reg, offset, mask, value, function(code, txt){ + if(code != 200){ + alert('Error['+code+']: '+txt); + } + }); + } + + // Attach on change action for register elements + document + .querySelectorAll('.reg-action') + .forEach(el => { + if (el.type === 'text') { + el.onkeyup = function(e){ + if(e.keyCode == 13){ + setRegValue(el); + } + } + } else { + el.onchange = () => setRegValue(el) + } + }) + + + const updateRegValue = (el, value, updateRemote) => { + let initialValue; + let offset = el.attributes.offset?parseInt(el.attributes.offset.nodeValue):0; + let mask = (el.attributes.mask?parseInt(el.attributes.mask.nodeValue):255) << offset; + value = (value & mask) >> offset; + if (el.type === 'checkbox') { + initialValue = el.checked + value = !!value + el.checked = value + } else { + initialValue = el.value + el.value = value + } + } + + + const printReg = (el) => { + let reg = el.attributes.reg?parseInt(el.attributes.reg.nodeValue):0; + let offset = el.attributes.offset?parseInt(el.attributes.offset.nodeValue):0; + let mask = el.attributes.mask?parseInt(el.attributes.mask.nodeValue):255; + let value = 0; + switch (el.type) { + case 'checkbox': + value = el.checked ? mask : 0; + break; + case 'range': + case 'select-one': + value = el.value; + break + default: + return; + } + value = (value & mask) << offset; + return '0x'+reg.toString(16)+', 0x'+value.toString(16); + } + + + const hide = el => { el.classList.add('hidden') } @@ -669,6 +992,15 @@ document.addEventListener('DOMContentLoaded', function (event) { .forEach(el => { updateValue(el, state[el.id], false) }) + document + .querySelectorAll('.reg-action') + .forEach(el => { + let reg = el.attributes.reg?parseInt(el.attributes.reg.nodeValue):0; + if(reg == 0){ + return; + } + updateRegValue(el, state['0x'+reg.toString(16)], false) + }) }) const view = document.getElementById('stream') diff --git a/examples/single_chip/camera_web_server/main/www/index_ov2640.html.gz b/examples/single_chip/camera_web_server/main/www/index_ov2640.html.gz index 60cd5e6..b0e1ddb 100644 Binary files a/examples/single_chip/camera_web_server/main/www/index_ov2640.html.gz and b/examples/single_chip/camera_web_server/main/www/index_ov2640.html.gz differ diff --git a/examples/single_chip/camera_web_server/main/www/index_ov3660.html b/examples/single_chip/camera_web_server/main/www/index_ov3660.html index 37f2dfd..e7b71cf 100644 --- a/examples/single_chip/camera_web_server/main/www/index_ov3660.html +++ b/examples/single_chip/camera_web_server/main/www/index_ov3660.html @@ -361,6 +361,23 @@ padding: 1px 4px 2px 4px; } + label.toggle-section-label { + cursor: pointer; + display: block + } + + input.toggle-section-button { + outline: 0; + opacity: 0; + width: 0; + height: 0 + } + + input.toggle-section-button:checked+section.toggle-section { + display: none + } + + @@ -372,19 +389,40 @@
@@ -601,6 +910,212 @@ document.addEventListener('DOMContentLoaded', function (event) { var baseHost = document.location.origin var streamUrl = baseHost + ':81' + function fetchUrl(url, cb){ + fetch(url) + .then(function (response) { + if (response.status !== 200) { + cb(response.status, response.statusText); + } else { + response.text().then(function(data){ + cb(200, data); + }).catch(function(err) { + cb(-1, err); + }); + } + }) + .catch(function(err) { + cb(-1, err); + }); + } + + function setReg(reg, offset, mask, value, cb){ + console.log('Set Reg', '0x'+reg.toString(16), offset, '0x'+mask.toString(16), '0x'+value.toString(16), '('+value+')'); + value = (value & mask) << offset; + mask = mask << offset; + fetchUrl(`${baseHost}/reg?reg=${reg}&mask=${mask}&val=${value}`, cb); + } + + function getReg(reg, offset, mask, cb){ + mask = mask << offset; + fetchUrl(`${baseHost}/greg?reg=${reg}&mask=${mask}`, function(code, txt){ + let value = 0; + if(code == 200){ + value = parseInt(txt); + value = (value & mask) >> offset; + txt = ''+value; + } + cb(code, txt); + }); + } + + function setXclk(xclk, cb){ + fetchUrl(`${baseHost}/xclk?xclk=${xclk}`, cb); + } + + function setPll(bypass, mul, sys, root_, pre, seld5, pclken, pclk, cb){ + fetchUrl(`${baseHost}/pll?bypass=${bypass}&mul=${mul}&sys=${sys}&root=${root_}&pre=${pre}&seld5=${seld5}&pclken=${pclken}&pclk=${pclk}`, cb); + } + + function setWindow(start_x, start_y, end_x, end_y, offset_x, offset_y, total_x, total_y, output_x, output_y, scaling, binning, cb){ + fetchUrl(`${baseHost}/resolution?sx=${start_x}&sy=${start_y}&ex=${end_x}&ey=${end_y}&offx=${offset_x}&offy=${offset_y}&tx=${total_x}&ty=${total_y}&ox=${output_x}&oy=${output_y}&scale=${scaling}&binning=${binning}`, cb); + } + + const setRegButton = document.getElementById('set-reg') + setRegButton.onclick = () => { + let reg = parseInt(document.getElementById('reg-addr').value); + let mask = parseInt(document.getElementById('reg-mask').value); + let value = parseInt(document.getElementById('reg-value').value); + + setReg(reg, 0, mask, value, function(code, txt){ + if(code != 200){ + alert('Error['+code+']: '+txt); + } + }); + } + + const getRegButton = document.getElementById('get-reg') + getRegButton.onclick = () => { + let reg = parseInt(document.getElementById('get-reg-addr').value); + let mask = parseInt(document.getElementById('get-reg-mask').value); + let value = document.getElementById('get-reg-value'); + + getReg(reg, 0, mask, function(code, txt){ + if(code != 200){ + value.innerHTML = 'Error['+code+']: '+txt; + } else { + value.innerHTML = '0x'+parseInt(txt).toString(16)+' ('+txt+')'; + } + }); + } + + const setXclkButton = document.getElementById('set-xclk') + setXclkButton.onclick = () => { + let xclk = parseInt(document.getElementById('xclk').value); + + setXclk(xclk, function(code, txt){ + if(code != 200){ + alert('Error['+code+']: '+txt); + } + }); + } + + const setResButton = document.getElementById('set-resolution') + setResButton.onclick = () => { + let start_x = parseInt(document.getElementById('start-x').value); + let start_y = parseInt(document.getElementById('start-y').value); + let end_x = parseInt(document.getElementById('end-x').value); + let end_y = parseInt(document.getElementById('end-y').value); + let offset_x = parseInt(document.getElementById('offset-x').value); + let offset_y = parseInt(document.getElementById('offset-y').value); + let total_x = parseInt(document.getElementById('total-x').value); + let total_y = parseInt(document.getElementById('total-y').value); + let output_x = parseInt(document.getElementById('output-x').value); + let output_y = parseInt(document.getElementById('output-y').value); + let scaling = document.getElementById('scaling').checked?1:0; + let binning = document.getElementById('binning').checked?1:0; + + setWindow(start_x, start_y, end_x, end_y, offset_x, offset_y, total_x, total_y, output_x, output_y, scaling, binning, function(code, txt){ + if(code != 200){ + alert('Error['+code+']: '+txt); + } + }); + } + + const setPllButton = document.getElementById('set-pll') + setPllButton.onclick = () => { + var bypass = document.getElementById('bypass-pll').checked?1:0; + var mul = parseInt(document.getElementById('mul-pll').value); + var sys = parseInt(document.getElementById('sys-pll').value); + var root_ = parseInt(document.getElementById('root-pll').value); + var pre = parseInt(document.getElementById('pre-pll').value); + var seld5 = parseInt(document.getElementById('seld5-pll').value); + var pclken = document.getElementById('pclk-en').checked?1:0; + var pclk = parseInt(document.getElementById('pclk-pll').value); + + setPll(bypass, mul, sys, root_, pre, seld5, pclken, pclk, function(code, txt){ + if(code != 200){ + alert('Error['+code+']: '+txt); + } + }); + } + + const setRegValue = (el) => { + let reg = el.attributes.reg?parseInt(el.attributes.reg.nodeValue):0; + let offset = el.attributes.offset?parseInt(el.attributes.offset.nodeValue):0; + let mask = el.attributes.mask?parseInt(el.attributes.mask.nodeValue):255; + let value = 0; + switch (el.type) { + case 'checkbox': + value = el.checked ? mask : 0; + break; + case 'range': + case 'text': + case 'select-one': + value = el.value; + break + default: + return; + } + + setReg(reg, offset, mask, value, function(code, txt){ + if(code != 200){ + alert('Error['+code+']: '+txt); + } + }); + } + + // Attach on change action for register elements + document + .querySelectorAll('.reg-action') + .forEach(el => { + if (el.type === 'text') { + el.onkeyup = function(e){ + if(e.keyCode == 13){ + setRegValue(el); + } + } + } else { + el.onchange = () => setRegValue(el) + } + }) + + + const updateRegValue = (el, value, updateRemote) => { + let initialValue; + let offset = el.attributes.offset?parseInt(el.attributes.offset.nodeValue):0; + let mask = (el.attributes.mask?parseInt(el.attributes.mask.nodeValue):255) << offset; + value = (value & mask) >> offset; + if (el.type === 'checkbox') { + initialValue = el.checked + value = !!value + el.checked = value + } else { + initialValue = el.value + el.value = value + } + } + + + const printReg = (el) => { + let reg = el.attributes.reg?parseInt(el.attributes.reg.nodeValue):0; + let offset = el.attributes.offset?parseInt(el.attributes.offset.nodeValue):0; + let mask = el.attributes.mask?parseInt(el.attributes.mask.nodeValue):255; + let value = 0; + switch (el.type) { + case 'checkbox': + value = el.checked ? mask : 0; + break; + case 'range': + case 'select-one': + value = el.value; + break + default: + return; + } + value = (value & mask) << offset; + return '0x'+reg.toString(16)+', 0x'+value.toString(16); + } + const hide = el => { el.classList.add('hidden') } @@ -696,6 +1211,15 @@ document.addEventListener('DOMContentLoaded', function (event) { .forEach(el => { updateValue(el, state[el.id], false) }) + document + .querySelectorAll('.reg-action') + .forEach(el => { + let reg = el.attributes.reg?parseInt(el.attributes.reg.nodeValue):0; + if(reg == 0){ + return; + } + updateRegValue(el, state['0x'+reg.toString(16)], false) + }) }) const view = document.getElementById('stream') diff --git a/examples/single_chip/camera_web_server/main/www/index_ov3660.html.gz b/examples/single_chip/camera_web_server/main/www/index_ov3660.html.gz index db85d56..8274a21 100644 Binary files a/examples/single_chip/camera_web_server/main/www/index_ov3660.html.gz and b/examples/single_chip/camera_web_server/main/www/index_ov3660.html.gz differ diff --git a/examples/single_chip/camera_web_server/main/www/index_ov5640.html b/examples/single_chip/camera_web_server/main/www/index_ov5640.html new file mode 100644 index 0000000..2d1cf8f --- /dev/null +++ b/examples/single_chip/camera_web_server/main/www/index_ov5640.html @@ -0,0 +1,1359 @@ + + + + + + ESP32 OV5640 + + + +
+ +
+ +
+ +
+
+
+ + + diff --git a/examples/single_chip/camera_web_server/main/www/index_ov5640.html.gz b/examples/single_chip/camera_web_server/main/www/index_ov5640.html.gz new file mode 100644 index 0000000..3deba92 Binary files /dev/null and b/examples/single_chip/camera_web_server/main/www/index_ov5640.html.gz differ