|
3 | 3 | #include <esp_task_wdt.h> |
4 | 4 | #include <WiFi.h> |
5 | 5 | #include <DNSServer.h> |
| 6 | +#include <WiFiUdp.h> |
6 | 7 | #include <ArduinoOTA.h> |
7 | 8 | #include "src/parsebytes.h" |
8 | 9 | #include "time.h" |
|
53 | 54 | // Pin Mappings |
54 | 55 | #include "camera_pins.h" |
55 | 56 |
|
| 57 | +// Camera config structure |
| 58 | +camera_config_t config; |
| 59 | + |
56 | 60 | // Internal filesystem (SPIFFS) |
57 | 61 | // used for non-volatile camera settings |
58 | 62 | #include "storage.h" |
@@ -303,6 +307,142 @@ void calcURLs() { |
303 | 307 | #endif |
304 | 308 | } |
305 | 309 |
|
| 310 | +void StartCamera() { |
| 311 | + // Populate camera config structure with hardware and other defaults |
| 312 | + config.ledc_channel = LEDC_CHANNEL_0; |
| 313 | + config.ledc_timer = LEDC_TIMER_0; |
| 314 | + config.pin_d0 = Y2_GPIO_NUM; |
| 315 | + config.pin_d1 = Y3_GPIO_NUM; |
| 316 | + config.pin_d2 = Y4_GPIO_NUM; |
| 317 | + config.pin_d3 = Y5_GPIO_NUM; |
| 318 | + config.pin_d4 = Y6_GPIO_NUM; |
| 319 | + config.pin_d5 = Y7_GPIO_NUM; |
| 320 | + config.pin_d6 = Y8_GPIO_NUM; |
| 321 | + config.pin_d7 = Y9_GPIO_NUM; |
| 322 | + config.pin_xclk = XCLK_GPIO_NUM; |
| 323 | + config.pin_pclk = PCLK_GPIO_NUM; |
| 324 | + config.pin_vsync = VSYNC_GPIO_NUM; |
| 325 | + config.pin_href = HREF_GPIO_NUM; |
| 326 | + config.pin_sscb_sda = SIOD_GPIO_NUM; |
| 327 | + config.pin_sscb_scl = SIOC_GPIO_NUM; |
| 328 | + config.pin_pwdn = PWDN_GPIO_NUM; |
| 329 | + config.pin_reset = RESET_GPIO_NUM; |
| 330 | + config.xclk_freq_hz = xclk * 1000000; |
| 331 | + config.pixel_format = PIXFORMAT_JPEG; |
| 332 | + config.grab_mode = CAMERA_GRAB_LATEST; |
| 333 | + // Pre-allocate large buffers |
| 334 | + if(psramFound()){ |
| 335 | + config.frame_size = FRAMESIZE_UXGA; |
| 336 | + config.jpeg_quality = 10; |
| 337 | + config.fb_count = 2; |
| 338 | + } else { |
| 339 | + config.frame_size = FRAMESIZE_SVGA; |
| 340 | + config.jpeg_quality = 12; |
| 341 | + config.fb_count = 1; |
| 342 | + } |
| 343 | + |
| 344 | + #if defined(CAMERA_MODEL_ESP_EYE) |
| 345 | + pinMode(13, INPUT_PULLUP); |
| 346 | + pinMode(14, INPUT_PULLUP); |
| 347 | + #endif |
| 348 | + |
| 349 | + // camera init |
| 350 | + esp_err_t err = esp_camera_init(&config); |
| 351 | + if (err != ESP_OK) { |
| 352 | + delay(100); // need a delay here or the next serial o/p gets missed |
| 353 | + Serial.printf("\r\n\r\nCRITICAL FAILURE: Camera sensor failed to initialise.\r\n\r\n"); |
| 354 | + Serial.printf("A full (hard, power off/on) reboot will probably be needed to recover from this.\r\n"); |
| 355 | + Serial.printf("Meanwhile; this unit will reboot in 1 minute since these errors sometime clear automatically\r\n"); |
| 356 | + // Reset the I2C bus.. may help when rebooting. |
| 357 | + periph_module_disable(PERIPH_I2C0_MODULE); // try to shut I2C down properly in case that is the problem |
| 358 | + periph_module_disable(PERIPH_I2C1_MODULE); |
| 359 | + periph_module_reset(PERIPH_I2C0_MODULE); |
| 360 | + periph_module_reset(PERIPH_I2C1_MODULE); |
| 361 | + // And set the error text for the UI |
| 362 | + critERR = "<h1>Error!</h1><hr><p>Camera module failed to initialise!</p><p>Please reset (power off/on) the camera.</p>"; |
| 363 | + critERR += "<p>We will continue to reboot once per minute since this error sometimes clears automatically.</p>"; |
| 364 | + // Start a 60 second watchdog timer |
| 365 | + esp_task_wdt_init(60,true); |
| 366 | + esp_task_wdt_add(NULL); |
| 367 | + } else { |
| 368 | + Serial.println("Camera init succeeded"); |
| 369 | + |
| 370 | + // Get a reference to the sensor |
| 371 | + sensor_t * s = esp_camera_sensor_get(); |
| 372 | + |
| 373 | + // Dump camera module, warn for unsupported modules. |
| 374 | + switch (s->id.PID) { |
| 375 | + case OV9650_PID: Serial.println("WARNING: OV9650 camera module is not properly supported, will fallback to OV2640 operation"); break; |
| 376 | + case OV7725_PID: Serial.println("WARNING: OV7725 camera module is not properly supported, will fallback to OV2640 operation"); break; |
| 377 | + case OV2640_PID: Serial.println("OV2640 camera module detected"); break; |
| 378 | + case OV3660_PID: Serial.println("OV3660 camera module detected"); break; |
| 379 | + default: Serial.println("WARNING: Camera module is unknown and not properly supported, will fallback to OV2640 operation"); |
| 380 | + } |
| 381 | + |
| 382 | + // OV3660 initial sensors are flipped vertically and colors are a bit saturated |
| 383 | + if (s->id.PID == OV3660_PID) { |
| 384 | + s->set_vflip(s, 1); //flip it back |
| 385 | + s->set_brightness(s, 1); //up the blightness just a bit |
| 386 | + s->set_saturation(s, -2); //lower the saturation |
| 387 | + } |
| 388 | + |
| 389 | + // M5 Stack Wide has special needs |
| 390 | + #if defined(CAMERA_MODEL_M5STACK_WIDE) |
| 391 | + s->set_vflip(s, 1); |
| 392 | + s->set_hmirror(s, 1); |
| 393 | + #endif |
| 394 | + |
| 395 | + // Config can override mirror and flip |
| 396 | + #if defined(H_MIRROR) |
| 397 | + s->set_hmirror(s, H_MIRROR); |
| 398 | + #endif |
| 399 | + #if defined(V_FLIP) |
| 400 | + s->set_vflip(s, V_FLIP); |
| 401 | + #endif |
| 402 | + |
| 403 | + // set initial frame rate |
| 404 | + #if defined(DEFAULT_RESOLUTION) |
| 405 | + s->set_framesize(s, DEFAULT_RESOLUTION); |
| 406 | + #else |
| 407 | + s->set_framesize(s, FRAMESIZE_SVGA); |
| 408 | + #endif |
| 409 | + |
| 410 | + /* |
| 411 | + * Add any other defaults you want to apply at startup here: |
| 412 | + * uncomment the line and set the value as desired (see the comments) |
| 413 | + * |
| 414 | + * these are defined in the esp headers here: |
| 415 | + * https://github.com/espressif/esp32-camera/blob/master/driver/include/sensor.h#L149 |
| 416 | + */ |
| 417 | + |
| 418 | + //s->set_framesize(s, FRAMESIZE_SVGA); // FRAMESIZE_[QQVGA|HQVGA|QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA|QXGA(ov3660)]); |
| 419 | + //s->set_quality(s, val); // 10 to 63 |
| 420 | + //s->set_brightness(s, 0); // -2 to 2 |
| 421 | + //s->set_contrast(s, 0); // -2 to 2 |
| 422 | + //s->set_saturation(s, 0); // -2 to 2 |
| 423 | + //s->set_special_effect(s, 0); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) |
| 424 | + //s->set_whitebal(s, 1); // aka 'awb' in the UI; 0 = disable , 1 = enable |
| 425 | + //s->set_awb_gain(s, 1); // 0 = disable , 1 = enable |
| 426 | + //s->set_wb_mode(s, 0); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) |
| 427 | + //s->set_exposure_ctrl(s, 1); // 0 = disable , 1 = enable |
| 428 | + //s->set_aec2(s, 0); // 0 = disable , 1 = enable |
| 429 | + //s->set_ae_level(s, 0); // -2 to 2 |
| 430 | + //s->set_aec_value(s, 300); // 0 to 1200 |
| 431 | + //s->set_gain_ctrl(s, 1); // 0 = disable , 1 = enable |
| 432 | + //s->set_agc_gain(s, 0); // 0 to 30 |
| 433 | + //s->set_gainceiling(s, (gainceiling_t)0); // 0 to 6 |
| 434 | + //s->set_bpc(s, 0); // 0 = disable , 1 = enable |
| 435 | + //s->set_wpc(s, 1); // 0 = disable , 1 = enable |
| 436 | + //s->set_raw_gma(s, 1); // 0 = disable , 1 = enable |
| 437 | + //s->set_lenc(s, 1); // 0 = disable , 1 = enable |
| 438 | + //s->set_hmirror(s, 0); // 0 = disable , 1 = enable |
| 439 | + //s->set_vflip(s, 0); // 0 = disable , 1 = enable |
| 440 | + //s->set_dcw(s, 1); // 0 = disable , 1 = enable |
| 441 | + //s->set_colorbar(s, 0); // 0 = disable , 1 = enable |
| 442 | + } |
| 443 | + // We now have camera with default init |
| 444 | +} |
| 445 | + |
306 | 446 | void WifiSetup() { |
307 | 447 | // Feedback that we are now attempting to connect |
308 | 448 | flashLED(300); |
@@ -529,148 +669,15 @@ void setup() { |
529 | 669 | delay(200); // a short delay to let spi bus settle after SPIFFS init |
530 | 670 | } |
531 | 671 |
|
532 | | - // Create camera config structure; and populate with hardware and other defaults |
533 | | - camera_config_t config; |
534 | | - config.ledc_channel = LEDC_CHANNEL_0; |
535 | | - config.ledc_timer = LEDC_TIMER_0; |
536 | | - config.pin_d0 = Y2_GPIO_NUM; |
537 | | - config.pin_d1 = Y3_GPIO_NUM; |
538 | | - config.pin_d2 = Y4_GPIO_NUM; |
539 | | - config.pin_d3 = Y5_GPIO_NUM; |
540 | | - config.pin_d4 = Y6_GPIO_NUM; |
541 | | - config.pin_d5 = Y7_GPIO_NUM; |
542 | | - config.pin_d6 = Y8_GPIO_NUM; |
543 | | - config.pin_d7 = Y9_GPIO_NUM; |
544 | | - config.pin_xclk = XCLK_GPIO_NUM; |
545 | | - config.pin_pclk = PCLK_GPIO_NUM; |
546 | | - config.pin_vsync = VSYNC_GPIO_NUM; |
547 | | - config.pin_href = HREF_GPIO_NUM; |
548 | | - config.pin_sscb_sda = SIOD_GPIO_NUM; |
549 | | - config.pin_sscb_scl = SIOC_GPIO_NUM; |
550 | | - config.pin_pwdn = PWDN_GPIO_NUM; |
551 | | - config.pin_reset = RESET_GPIO_NUM; |
552 | | - config.xclk_freq_hz = xclk * 1000000; |
553 | | - config.pixel_format = PIXFORMAT_JPEG; |
554 | | - config.grab_mode = CAMERA_GRAB_LATEST; |
555 | | - // Pre-allocate large buffers |
556 | | - if(psramFound()){ |
557 | | - config.frame_size = FRAMESIZE_UXGA; |
558 | | - config.jpeg_quality = 10; |
559 | | - config.fb_count = 2; |
560 | | - } else { |
561 | | - config.frame_size = FRAMESIZE_SVGA; |
562 | | - config.jpeg_quality = 12; |
563 | | - config.fb_count = 1; |
564 | | - } |
| 672 | + // Start (init) the camera |
| 673 | + StartCamera(); |
565 | 674 |
|
566 | | - #if defined(CAMERA_MODEL_ESP_EYE) |
567 | | - pinMode(13, INPUT_PULLUP); |
568 | | - pinMode(14, INPUT_PULLUP); |
569 | | - #endif |
570 | | - |
571 | | - // camera init |
572 | | - esp_err_t err = esp_camera_init(&config); |
573 | | - if (err != ESP_OK) { |
574 | | - delay(100); // need a delay here or the next serial o/p gets missed |
575 | | - Serial.printf("\r\n\r\nCRITICAL FAILURE: Camera sensor failed to initialise.\r\n\r\n"); |
576 | | - Serial.printf("A full (hard, power off/on) reboot will probably be needed to recover from this.\r\n"); |
577 | | - Serial.printf("Meanwhile; this unit will reboot in 1 minute since these errors sometime clear automatically\r\n"); |
578 | | - // Reset the I2C bus.. may help when rebooting. |
579 | | - periph_module_disable(PERIPH_I2C0_MODULE); // try to shut I2C down properly in case that is the problem |
580 | | - periph_module_disable(PERIPH_I2C1_MODULE); |
581 | | - periph_module_reset(PERIPH_I2C0_MODULE); |
582 | | - periph_module_reset(PERIPH_I2C1_MODULE); |
583 | | - // And set the error text for the UI |
584 | | - critERR = "<h1>Error!</h1><hr><p>Camera module failed to initialise!</p><p>Please reset (power off/on) the camera.</p>"; |
585 | | - critERR += "<p>We will continue to reboot once per minute since this error sometimes clears automatically.</p>"; |
586 | | - // Start a 60 second watchdog timer |
587 | | - esp_task_wdt_init(60,true); |
588 | | - esp_task_wdt_add(NULL); |
| 675 | + // Now load and apply any saved preferences |
| 676 | + if (filesystem) { |
| 677 | + delay(200); // a short delay to let spi bus settle after camera init |
| 678 | + loadPrefs(SPIFFS); |
589 | 679 | } else { |
590 | | - Serial.println("Camera init succeeded"); |
591 | | - |
592 | | - // Get a reference to the sensor |
593 | | - sensor_t * s = esp_camera_sensor_get(); |
594 | | - |
595 | | - // Dump camera module, warn for unsupported modules. |
596 | | - switch (s->id.PID) { |
597 | | - case OV9650_PID: Serial.println("WARNING: OV9650 camera module is not properly supported, will fallback to OV2640 operation"); break; |
598 | | - case OV7725_PID: Serial.println("WARNING: OV7725 camera module is not properly supported, will fallback to OV2640 operation"); break; |
599 | | - case OV2640_PID: Serial.println("OV2640 camera module detected"); break; |
600 | | - case OV3660_PID: Serial.println("OV3660 camera module detected"); break; |
601 | | - default: Serial.println("WARNING: Camera module is unknown and not properly supported, will fallback to OV2640 operation"); |
602 | | - } |
603 | | - |
604 | | - // OV3660 initial sensors are flipped vertically and colors are a bit saturated |
605 | | - if (s->id.PID == OV3660_PID) { |
606 | | - s->set_vflip(s, 1); //flip it back |
607 | | - s->set_brightness(s, 1); //up the blightness just a bit |
608 | | - s->set_saturation(s, -2); //lower the saturation |
609 | | - } |
610 | | - |
611 | | - // M5 Stack Wide has special needs |
612 | | - #if defined(CAMERA_MODEL_M5STACK_WIDE) |
613 | | - s->set_vflip(s, 1); |
614 | | - s->set_hmirror(s, 1); |
615 | | - #endif |
616 | | - |
617 | | - // Config can override mirror and flip |
618 | | - #if defined(H_MIRROR) |
619 | | - s->set_hmirror(s, H_MIRROR); |
620 | | - #endif |
621 | | - #if defined(V_FLIP) |
622 | | - s->set_vflip(s, V_FLIP); |
623 | | - #endif |
624 | | - |
625 | | - // set initial frame rate |
626 | | - #if defined(DEFAULT_RESOLUTION) |
627 | | - s->set_framesize(s, DEFAULT_RESOLUTION); |
628 | | - #else |
629 | | - s->set_framesize(s, FRAMESIZE_SVGA); |
630 | | - #endif |
631 | | - |
632 | | - /* |
633 | | - * Add any other defaults you want to apply at startup here: |
634 | | - * uncomment the line and set the value as desired (see the comments) |
635 | | - * |
636 | | - * these are defined in the esp headers here: |
637 | | - * https://github.com/espressif/esp32-camera/blob/master/driver/include/sensor.h#L149 |
638 | | - */ |
639 | | - |
640 | | - //s->set_framesize(s, FRAMESIZE_SVGA); // FRAMESIZE_[QQVGA|HQVGA|QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA|QXGA(ov3660)]); |
641 | | - //s->set_quality(s, val); // 10 to 63 |
642 | | - //s->set_brightness(s, 0); // -2 to 2 |
643 | | - //s->set_contrast(s, 0); // -2 to 2 |
644 | | - //s->set_saturation(s, 0); // -2 to 2 |
645 | | - //s->set_special_effect(s, 0); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) |
646 | | - //s->set_whitebal(s, 1); // aka 'awb' in the UI; 0 = disable , 1 = enable |
647 | | - //s->set_awb_gain(s, 1); // 0 = disable , 1 = enable |
648 | | - //s->set_wb_mode(s, 0); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) |
649 | | - //s->set_exposure_ctrl(s, 1); // 0 = disable , 1 = enable |
650 | | - //s->set_aec2(s, 0); // 0 = disable , 1 = enable |
651 | | - //s->set_ae_level(s, 0); // -2 to 2 |
652 | | - //s->set_aec_value(s, 300); // 0 to 1200 |
653 | | - //s->set_gain_ctrl(s, 1); // 0 = disable , 1 = enable |
654 | | - //s->set_agc_gain(s, 0); // 0 to 30 |
655 | | - //s->set_gainceiling(s, (gainceiling_t)0); // 0 to 6 |
656 | | - //s->set_bpc(s, 0); // 0 = disable , 1 = enable |
657 | | - //s->set_wpc(s, 1); // 0 = disable , 1 = enable |
658 | | - //s->set_raw_gma(s, 1); // 0 = disable , 1 = enable |
659 | | - //s->set_lenc(s, 1); // 0 = disable , 1 = enable |
660 | | - //s->set_hmirror(s, 0); // 0 = disable , 1 = enable |
661 | | - //s->set_vflip(s, 0); // 0 = disable , 1 = enable |
662 | | - //s->set_dcw(s, 1); // 0 = disable , 1 = enable |
663 | | - //s->set_colorbar(s, 0); // 0 = disable , 1 = enable |
664 | | - |
665 | | - // We now have camera with default init |
666 | | - // check for saved preferences and apply them |
667 | | - |
668 | | - if (filesystem) { |
669 | | - delay(200); // a short delay to let spi bus settle after camera init |
670 | | - loadPrefs(SPIFFS); |
671 | | - } else { |
672 | | - Serial.println("No Internal Filesystem, cannot load or save preferences"); |
673 | | - } |
| 680 | + Serial.println("No Internal Filesystem, cannot load or save preferences"); |
674 | 681 | } |
675 | 682 |
|
676 | 683 | /* |
@@ -700,27 +707,31 @@ void setup() { |
700 | 707 | } |
701 | 708 | ArduinoOTA |
702 | 709 | .onStart([]() { |
703 | | - String type; |
704 | | - if (ArduinoOTA.getCommand() == U_FLASH) |
705 | | - type = "sketch"; |
706 | | - else // U_SPIFFS |
707 | | - type = "filesystem"; |
708 | | - // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() |
709 | | - Serial.println("Start updating " + type); |
| 710 | + String type; |
| 711 | + if (ArduinoOTA.getCommand() == U_FLASH) |
| 712 | + type = "sketch"; |
| 713 | + else // U_SPIFFS |
| 714 | + // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() |
| 715 | + type = "filesystem"; |
| 716 | + Serial.println("Start updating " + type); |
| 717 | + // Stop the camera since OTA will crash the module if it is running. |
| 718 | + // the unit will need rebooting to restart it, either by OTA on success, or manually by the user |
| 719 | + Serial.println("Stopping Camera"); |
| 720 | + esp_err_t err = esp_camera_deinit(); |
710 | 721 | }) |
711 | 722 | .onEnd([]() { |
712 | | - Serial.println("\r\nEnd"); |
| 723 | + Serial.println("\r\nEnd"); |
713 | 724 | }) |
714 | 725 | .onProgress([](unsigned int progress, unsigned int total) { |
715 | | - Serial.printf("Progress: %u%%\r", (progress / (total / 100))); |
| 726 | + Serial.printf("Progress: %u%%\r", (progress / (total / 100))); |
716 | 727 | }) |
717 | 728 | .onError([](ota_error_t error) { |
718 | | - Serial.printf("Error[%u]: ", error); |
719 | | - if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); |
720 | | - else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); |
721 | | - else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); |
722 | | - else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); |
723 | | - else if (error == OTA_END_ERROR) Serial.println("End Failed"); |
| 729 | + Serial.printf("Error[%u]: ", error); |
| 730 | + if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); |
| 731 | + else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); |
| 732 | + else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); |
| 733 | + else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); |
| 734 | + else if (error == OTA_END_ERROR) Serial.println("End Failed"); |
724 | 735 | }); |
725 | 736 | ArduinoOTA.begin(); |
726 | 737 | } else { |
|
0 commit comments