diff --git a/esp3d/src/core/espcmd/ESP170.cpp b/esp3d/src/core/espcmd/ESP170.cpp index f48f9e2a..763860de 100644 --- a/esp3d/src/core/espcmd/ESP170.cpp +++ b/esp3d/src/core/espcmd/ESP170.cpp @@ -58,7 +58,7 @@ bool Commands::ESP170(const char* cmd_params, level_authenticate_type auth_type, if (parameter == "ON") { esp3d_camera.begin(); } else { - esp3d_camera.end(); + esp3d_camera.stopHardware(); } output->printMSG ("ok"); } diff --git a/esp3d/src/core/espcmd/ESP172.cpp b/esp3d/src/core/espcmd/ESP172.cpp index 207c5353..f2117947 100644 --- a/esp3d/src/core/espcmd/ESP172.cpp +++ b/esp3d/src/core/espcmd/ESP172.cpp @@ -39,13 +39,25 @@ bool Commands::ESP172(const char* cmd_params, level_authenticate_type auth_type, #else (void)auth_type; #endif //AUTHENTICATION_FEATURE + if (!esp3d_camera.started()) { + output->printERROR("No camera initialized!", 401); + return false; + } parameter = get_param (cmd_params, ""); //get bool plain = hastag (cmd_params, "plain"); if ((parameter.length() == 0) || plain) { sensor_t * s = esp_camera_sensor_get(); + if (s == nullptr) { + if (!plain) { + output->print ("{\"status\":\"error\"}"); + } else { + output->printERROR("No camera initialized!", 401); + } + return false; + } if (!plain) { - output->print ("{"); + output->print ("{\"status\":\"ok\","); } //framesize if (!plain) { diff --git a/esp3d/src/include/pins.h b/esp3d/src/include/pins.h index ebe86819..e9cb105f 100644 --- a/esp3d/src/include/pins.h +++ b/esp3d/src/include/pins.h @@ -142,15 +142,15 @@ #endif //CAMERA_MODEL_M5STACK_WIDE #if CAMERA_DEVICE == CAMERA_MODEL_AI_THINKER -#define CAM_LED_PIN -1 +#define CAM_LED_PIN -1 //used by SD so must left unset #define CAM_PULLUP1 -1 #define CAM_PULLUP2 -1 + #define PWDN_GPIO_NUM 32 #define RESET_GPIO_NUM -1 #define XCLK_GPIO_NUM 0 #define SIOD_GPIO_NUM 26 #define SIOC_GPIO_NUM 27 - #define Y9_GPIO_NUM 35 #define Y8_GPIO_NUM 34 #define Y7_GPIO_NUM 39 @@ -167,7 +167,7 @@ //Pins for the support of SD Card Reader //-1 means use default pins of your board defined core #define ESP_SD_CS_PIN -1 -//These are hardcoded on ESP8266 to 12/13/14 +//These are hardcoded on ESP8266 to 12/13/14 //so modifications are ignored on ESP8266 #define ESP_SD_MISO_PIN -1 #define ESP_SD_MOSI_PIN -1 diff --git a/esp3d/src/include/version.h b/esp3d/src/include/version.h index c5960401..45f7a23e 100644 --- a/esp3d/src/include/version.h +++ b/esp3d/src/include/version.h @@ -22,7 +22,7 @@ #define _VERSION_ESP3D_H //version and sources location -#define FW_VERSION "3.0.0.a26" +#define FW_VERSION "3.0.0.a27" #define REPOSITORY "https://github.com/luc-github/ESP3D" #endif //_VERSION_ESP3D_H diff --git a/esp3d/src/modules/camera/camera.cpp b/esp3d/src/modules/camera/camera.cpp index 443dc196..f604c5f3 100644 --- a/esp3d/src/modules/camera/camera.cpp +++ b/esp3d/src/modules/camera/camera.cpp @@ -28,9 +28,12 @@ #include "esp_http_server.h" #include #include "fd_forward.h" +//#include //not sure this one is needed #include +#include #define DEFAULT_FRAME_SIZE FRAMESIZE_SVGA +#define HTTP_TASK_PRIORITY 5 #define PART_BUFFER_SIZE 64 #define JPEG_COMPRESSION 80 #define MIN_WIDTH_COMPRESSION 400 @@ -45,12 +48,17 @@ Camera esp3d_camera; //to break the loop static void disconnected_uri(httpd_handle_t hd, int sockfd) { + log_esp3d("Camera stream disconnected"); esp3d_camera.connect(false); } static esp_err_t stream_handler(httpd_req_t *req) { + log_esp3d("Camera stream reached"); if (!esp3d_camera.started()) { + const char* resp = "Camera not started"; + log_esp3d("Camera not started"); + httpd_resp_send(req, resp, strlen(resp)); return ESP_FAIL; } esp3d_camera.connect(true); @@ -63,21 +71,33 @@ static esp_err_t stream_handler(httpd_req_t *req) uint8_t * _jpg_buf = NULL; char * part_buf[PART_BUFFER_SIZE]; dl_matrix3du_t *image_matrix = NULL; - log_esp3d("Camera stream reached"); res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE); if(res != ESP_OK) { esp3d_camera.connect(false); + const char* resp = "Stream type failed"; + log_esp3d("Stream type failed"); + httpd_resp_send(req, resp, strlen(resp)); return res; } + uint8_t retry = 0; while(true) { if (!esp3d_camera.isconnected()) { + const char* resp = "Camera is not connected"; + log_esp3d("Camera is not connected"); + httpd_resp_send(req, resp, strlen(resp)); return ESP_FAIL; } log_esp3d("Camera capture ongoing"); fb = esp_camera_fb_get(); if (!fb) { log_esp3d("Camera capture failed"); - res = ESP_FAIL; + if ( retry < 3) { + log_esp3d("Retry %d",retry ); + retry ++; + continue; + } else { + res = ESP_FAIL; + } } else { if(fb->width > MIN_WIDTH_COMPRESSION) { if(fb->format != PIXFORMAT_JPEG) { @@ -164,6 +184,9 @@ int Camera::command(const char * param, const char * value) int res = 0; int val = atoi(value); sensor_t * s = esp_camera_sensor_get(); + if (s == nullptr) { + res = -1; + } #if CAM_LED_PIN != -1 if (!strcmp(param, "light")) { digitalWrite(CAM_LED_PIN, val==1?HIGH:LOW); @@ -233,7 +256,7 @@ bool Camera::initHardware(bool forceinit) if (_initialised) { return _initialised; } - stopHardware(); + log_esp3d("Disable brown out"); WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector camera_config_t config; config.ledc_channel = LEDC_CHANNEL_0; @@ -254,19 +277,20 @@ bool Camera::initHardware(bool forceinit) config.pin_sscb_scl = SIOC_GPIO_NUM; config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM; - config.xclk_freq_hz = 20000000; + config.xclk_freq_hz = 10000000; config.pixel_format = PIXFORMAT_JPEG; - //init with high specs to pre-allocate larger buffers - if(psramFound()) { - config.frame_size = DEFAULT_FRAME_SIZE; - config.jpeg_quality = 10; - config.fb_count = 2; - } else { - config.frame_size = DEFAULT_FRAME_SIZE; - config.jpeg_quality = 12; - config.fb_count = 1; + config.jpeg_quality = 5; + config.fb_count = 1; + config.frame_size = DEFAULT_FRAME_SIZE; + if(!psramFound()) { + _initialised = false; + log_esp3d("psram is not enabled"); + return false; } - + if (!stopHardware()) { + log_esp3d("Stop camera failed"); + } + log_esp3d("Init camera"); #if CAM_PULLUP1 != -1 pinMode(CAM_PULLUP1, INPUT_PULLUP); #endif //CAM_PULLUP1 @@ -277,28 +301,28 @@ bool Camera::initHardware(bool forceinit) pinMode(CAM_LED_PIN, OUTPUT); digitalWrite(CAM_LED_PIN, LOW); #endif //CAM_LED_PIN - // camera init + //initialize the camera + +//https://github.com/espressif/esp32-camera/issues/66#issuecomment-526283681 +#if CAMERA_DEVICE == CAMERA_MODEL_AI_THINKER + log_esp3d("Specific config for CAMERA_MODEL_AI_THINKER"); + gpio_config_t gpio_pwr_config; + gpio_pwr_config.pin_bit_mask = (1ULL << 32); + gpio_pwr_config.mode = GPIO_MODE_OUTPUT; + gpio_pwr_config.pull_down_en = GPIO_PULLDOWN_DISABLE; + gpio_pwr_config.pull_up_en = GPIO_PULLUP_DISABLE; + gpio_pwr_config.intr_type = GPIO_INTR_DISABLE; + gpio_config(&gpio_pwr_config); + gpio_set_level(GPIO_NUM_32,0); +#endif //CAMERA_DEVICE == CAMERA_MODEL_AI_THINKER + log_esp3d("Init camera config"); esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { log_esp3d("Camera init failed with error 0x%x", err); - return false; + _initialised = false; + } else { + _initialised = true; } - sensor_t * s = esp_camera_sensor_get(); - //initial sensors are flipped vertically and colors are a bit saturated - if (s->id.PID == OV3660_PID) { - s->set_brightness(s, 1);//up the blightness just a bit - s->set_saturation(s, -2);//lower the saturation - } - - s->set_framesize(s, DEFAULT_FRAME_SIZE); - -#if defined(CAMERA_DEVICE_FLIP_HORIZONTALY) - s->set_hmirror(s, 1); -#endif //CAMERA_DEVICE_FLIP_HORIZONTALY -#if defined(CAMERA_DEVICE_FLIP_VERTICALY) - s->set_vflip(s, 1); -#endif //CAMERA_DEVICE_FLIP_VERTICALY - _initialised = true; return _initialised; } @@ -306,17 +330,50 @@ bool Camera::stopHardware() { end(); _initialised = false; - log_esp3d("Stop cam"); - return (esp_camera_deinit() == ESP_OK); + log_esp3d("deinit camera"); + esp_err_t err = esp_camera_deinit(); + if(err == ESP_OK) { + //seems sometimes i2c install failed when doing camera init so let's remove if already installed + if(i2c_driver_delete(I2C_NUM_1)!= ESP_OK) { + log_esp3d("I2C 1 delete failed"); + } + return true; + } else { + log_esp3d("Camera deinit failed with error 0x%x", err); + return false; + } } //need to be call by device and by network bool Camera::begin(bool forceinit) { end(); + log_esp3d("Begin camera"); if (!initHardware(forceinit) ) { + log_esp3d("Init hardware failed"); return false; } + delay(1000); + log_esp3d("Init camera sensor settings"); + sensor_t * s = esp_camera_sensor_get(); + if (s != nullptr) { + //initial sensors are flipped vertically and colors are a bit saturated + if (s->id.PID == OV3660_PID) { + s->set_brightness(s, 1);//up the blightness just a bit + s->set_saturation(s, -2);//lower the saturation + } + + s->set_framesize(s, DEFAULT_FRAME_SIZE); + +#if defined(CAMERA_DEVICE_FLIP_HORIZONTALY) + s->set_hmirror(s, 1); +#endif //CAMERA_DEVICE_FLIP_HORIZONTALY +#if defined(CAMERA_DEVICE_FLIP_VERTICALY) + s->set_vflip(s, 1); +#endif //CAMERA_DEVICE_FLIP_VERTICALY + } else { + log_esp3d("Cannot access camera sensor"); + } if (NetConfig::started() && (NetConfig::getMode()!= ESP_BT)) { ESP3DOutput output(ESP_ALL_CLIENTS); httpd_config_t httpdconfig = HTTPD_DEFAULT_CONFIG(); @@ -330,17 +387,30 @@ bool Camera::begin(bool forceinit) _port = Settings_ESP3D::read_uint32(ESP_CAMERA_PORT); httpdconfig.server_port = _port; httpdconfig.ctrl_port = httpdconfig.server_port +1; - httpdconfig.task_priority = 1; + httpdconfig.task_priority = HTTP_TASK_PRIORITY; + log_esp3d("Starting camera server"); if (httpd_start(&stream_httpd, &httpdconfig) == ESP_OK) { - httpd_register_uri_handler(stream_httpd, &stream_uri); String stmp = "Camera server started port " + String(httpdconfig.server_port); output.printMSG(stmp.c_str()); + log_esp3d("Registering /stream"); + if (httpd_register_uri_handler(stream_httpd, &stream_uri) != ESP_OK) { + log_esp3d("Registering /stream failed"); + } } else { + log_esp3d("Starting camera server failed"); output.printERROR("Starting camera server failed"); return false; } _started = true; } + for (int j = 0; j < 5; j++) { + camera_fb_t * fb = esp_camera_fb_get(); // start the camera ... warm it up + if (fb == nullptr) { + log_esp3d("Failed to get fb"); + } + esp_camera_fb_return(fb); + delay(20); + } return _started; } @@ -349,22 +419,27 @@ void Camera::end() if (_started) { _started = false; _connected = false; + log_esp3d("unregister /stream"); if (ESP_OK != httpd_unregister_uri(stream_httpd, "/stream")) { log_esp3d("Error unregistering /stream"); } + log_esp3d("Stop httpd"); if (ESP_OK != httpd_stop(stream_httpd)) { log_esp3d("Error stopping stream server"); } } } + void Camera::handle() { //so far nothing to do } + uint8_t Camera::GetModel() { return CAMERA_DEVICE; } + const char *Camera::GetModelString() { #if defined(CUSTOM_CAMERA_NAME) diff --git a/esp3d/src/modules/devices/devices_services.cpp b/esp3d/src/modules/devices/devices_services.cpp index d19717a1..d1468b68 100644 --- a/esp3d/src/modules/devices/devices_services.cpp +++ b/esp3d/src/modules/devices/devices_services.cpp @@ -57,6 +57,12 @@ bool DevicesServices::begin() { bool res = true; _started = false; +#ifdef SD_DEVICE + if (!ESP_SD::begin()) { + log_esp3d("Error sd intialization failed"); + res = false; + } +#endif //SD_DEVICE #ifdef DISPLAY_DEVICE if (!esp3d_display.begin()) { log_esp3d("Error starting display device"); @@ -87,12 +93,6 @@ bool DevicesServices::begin() res = false; } #endif //CAMERA_DEVICE -#ifdef SD_DEVICE - if (!ESP_SD::begin()) { - log_esp3d("Error sd intialization failed"); - res = false; - } -#endif //SD_DEVICE if (!res) { end(); } diff --git a/esp3d/src/modules/filesystem/sd/sdio_esp32.cpp b/esp3d/src/modules/filesystem/sd/sdio_esp32.cpp index f390f00a..bed2add4 100644 --- a/esp3d/src/modules/filesystem/sd/sdio_esp32.cpp +++ b/esp3d/src/modules/filesystem/sd/sdio_esp32.cpp @@ -29,8 +29,14 @@ sdio_esp32.cpp - ESP3D sd support class extern File tSDFile_handle[ESP_MAX_SD_OPENHANDLE]; +#define SDMMC_FORCE_BEGIN + uint8_t ESP_SD::getState(bool refresh) { + static bool lastinitok = false; +#ifdef SDMMC_FORCE_BEGIN + lastinitok = false; +#endif //SDMMC_LIGHT_CHECK #if defined(ESP_SD_DETECT_PIN) && ESP_SD_DETECT_PIN != -1 //no need to go further if SD detect is not correct if (!((digitalRead (ESP_SD_DETECT_PIN) == ESP_SD_DETECT_VALUE) ? true : false)) { @@ -46,14 +52,44 @@ uint8_t ESP_SD::getState(bool refresh) return _state; //to avoid refresh=true + busy to reset SD and waste time } //SD is idle or not detected, let see if still the case - - SD_MMC.end(); _state = ESP_SDCARD_NOT_PRESENT; -//using default value for speed ? should be parameter //refresh content if card was removed - if (SD_MMC.begin()) { - if ( SD_MMC.cardSize() > 0 ) { + if (!lastinitok) { + log_esp3d("last init was failed try sd_mmc begin"); + //SD_MMC.end(); + if (SD_MMC.begin()) { + log_esp3d("sd_mmc begin succeed"); + if (SD_MMC.cardType() != CARD_NONE ) { + _state = ESP_SDCARD_IDLE; + lastinitok = true; + log_esp3d("sd_mmc card type succeed"); + } else { + log_esp3d("sd_mmc card type failed"); + } + } else { + log_esp3d("sd_mmc begin failed"); + } + } else { + log_esp3d("last init was ok try card type"); + if(SD_MMC.cardType() != CARD_NONE) { + log_esp3d("checking sd_mmc card type succeed"); _state = ESP_SDCARD_IDLE; + } else { + lastinitok = false; + log_esp3d("Soft sd check failed"); + //SD_MMC.end(); + if (SD_MMC.begin()) { + log_esp3d("new sd_mmc begin succeed"); + if ( SD_MMC.cardType() != CARD_NONE ) { + _state = ESP_SDCARD_IDLE; + lastinitok = true; + log_esp3d("new sd_mmc card type succeed"); + } else { + log_esp3d("new sd_mmc card type failed"); + } + } else { + log_esp3d("new sd_mmc begin failed"); + } } } return _state; @@ -61,8 +97,14 @@ uint8_t ESP_SD::getState(bool refresh) bool ESP_SD::begin() { + log_esp3d("Begin SDIO"); _started = true; +#ifdef SDMMC_FORCE_BEGIN _state = ESP_SDCARD_NOT_PRESENT; +#else + _state = getState(true); +#endif //SDMMC_FORCE_BEGIN + return _started; }