mirror of
https://github.com/MrUnknownDE/OpenIris-ESPIDF.git
synced 2026-04-11 10:43:45 +02:00
# Conflicts: # components/CameraManager/CameraManager/CameraManager.cpp # dependencies.lock # main/openiris_main.cpp # sdkconfig
282 lines
10 KiB
C++
282 lines
10 KiB
C++
#include "CameraManager.hpp"
|
|
|
|
const char *CAMERA_MANAGER_TAG = "[CAMERA_MANAGER]";
|
|
|
|
CameraManager::CameraManager(std::shared_ptr<ProjectConfig> projectConfig, QueueHandle_t eventQueue)
|
|
: projectConfig(projectConfig), eventQueue(eventQueue) {}
|
|
|
|
void CameraManager::setupCameraPinout()
|
|
{
|
|
// Workaround for espM5SStack not having a defined camera
|
|
#ifdef CONFIG_CAMERA_MODULE_NAME
|
|
ESP_LOGI(CAMERA_MANAGER_TAG, "[Camera]: Camera module is %s", CONFIG_CAMERA_MODULE_NAME);
|
|
#else
|
|
ESP_LOGI(CAMERA_MANAGER_TAG, "[Camera]: Camera module is undefined");
|
|
#endif
|
|
|
|
// camera external clock signal frequencies
|
|
// 10000000 stable
|
|
// 16500000 optimal freq on ESP32-CAM (default)
|
|
// 20000000 max freq on ESP32-CAM
|
|
// 24000000 optimal freq on ESP32-S3 // 23MHz same fps
|
|
int xclk_freq_hz = CONFIG_CAMERA_WIFI_XCLK_FREQ;
|
|
|
|
#if CONFIG_CAMERA_MODULE_ESP_EYE
|
|
/* IO13, IO14 is designed for JTAG by default,
|
|
* to use it as generalized input,
|
|
* firstly declare it as pullup input
|
|
**/
|
|
gpio_reset_pin(13);
|
|
gpio_reset_pin(14);
|
|
gpio_set_direction(13, GPIO_MODE_INPUT);
|
|
gpio_set_direction(14, GPIO_MODE_INPUT);
|
|
gpio_set_pull_mode(13, GPIO_PULLUP_ONLY);
|
|
gpio_set_pull_mode(14, GPIO_PULLUP_ONLY);
|
|
ESP_LOGI(CAMERA_MANAGER_TAG, "ESP_EYE");
|
|
#elif CONFIG_CAMERA_MODULE_CAM_BOARD
|
|
/* IO13, IO14 is designed for JTAG by default,
|
|
* to use it as generalized input,
|
|
* firstly declare it as pullup input
|
|
**/
|
|
|
|
gpio_reset_pin(13);
|
|
gpio_reset_pin(14);
|
|
gpio_set_direction(13, GPIO_MODE_INPUT);
|
|
gpio_set_direction(14, GPIO_MODE_INPUT);
|
|
gpio_set_pull_mode(13, GPIO_PULLUP_ONLY);
|
|
gpio_set_pull_mode(14, GPIO_PULLUP_ONLY);
|
|
|
|
ESP_LOGI(CAMERA_MANAGER_TAG, "CAM_BOARD");
|
|
#endif
|
|
#if CONFIG_GENERAL_WIRED_MODE
|
|
xclk_freq_hz = CONFIG_CAMERA_USB_XCLK_FREQ;
|
|
#endif
|
|
|
|
config = {
|
|
.pin_pwdn = CONFIG_PWDN_GPIO_NUM, // CAM_PIN_PWDN,
|
|
.pin_reset = CONFIG_RESET_GPIO_NUM, // CAM_PIN_RESET,
|
|
.pin_xclk = CONFIG_XCLK_GPIO_NUM, // CAM_PIN_XCLK,
|
|
.pin_sccb_sda = CONFIG_SIOD_GPIO_NUM, // CAM_PIN_SIOD,
|
|
.pin_sccb_scl = CONFIG_SIOC_GPIO_NUM, // CAM_PIN_SIOC,
|
|
|
|
.pin_d7 = CONFIG_Y9_GPIO_NUM, /// CAM_PIN_D7,
|
|
.pin_d6 = CONFIG_Y8_GPIO_NUM, /// CAM_PIN_D6,
|
|
.pin_d5 = CONFIG_Y7_GPIO_NUM, // CAM_PIN_D5,
|
|
.pin_d4 = CONFIG_Y6_GPIO_NUM, // CAM_PIN_D4,
|
|
.pin_d3 = CONFIG_Y5_GPIO_NUM, // CAM_PIN_D3,
|
|
.pin_d2 = CONFIG_Y4_GPIO_NUM, // CAM_PIN_D2,
|
|
.pin_d1 = CONFIG_Y3_GPIO_NUM, // CAM_PIN_D1,
|
|
.pin_d0 = CONFIG_Y2_GPIO_NUM, // CAM_PIN_D0,
|
|
.pin_vsync = CONFIG_VSYNC_GPIO_NUM, // CAM_PIN_VSYNC,
|
|
.pin_href = CONFIG_HREF_GPIO_NUM, // CAM_PIN_HREF,
|
|
.pin_pclk = CONFIG_PCLK_GPIO_NUM, // CAM_PIN_PCLK,
|
|
|
|
.xclk_freq_hz = xclk_freq_hz, // Set in config
|
|
.ledc_timer = LEDC_TIMER_0,
|
|
.ledc_channel = LEDC_CHANNEL_0,
|
|
|
|
// this causes problems
|
|
.pixel_format = PIXFORMAT_JPEG, // YUV422,GRAYSCALE,RGB565,JPEG
|
|
.frame_size = FRAMESIZE_240X240, // QQVGA-UXGA, For ESP32, do not use sizes above QVGA when not JPEG. The performance of the ESP32-S series has improved a lot, but JPEG mode always gives better frame rates.
|
|
|
|
.jpeg_quality = 7, // 0-63, for OV series camera sensors, lower number means higher quality // Below 6 stability problems
|
|
.fb_count = 2, // When jpeg mode is used, if fb_count more than one, the driver will work in continuous mode.
|
|
.fb_location = CAMERA_FB_IN_DRAM,
|
|
.grab_mode = CAMERA_GRAB_WHEN_EMPTY,
|
|
};
|
|
}
|
|
|
|
void CameraManager::setupBasicResolution()
|
|
{
|
|
|
|
if (!esp_psram_is_initialized())
|
|
{
|
|
ESP_LOGE(CAMERA_MANAGER_TAG, "PSRAM not initialized!");
|
|
ESP_LOGD(CAMERA_MANAGER_TAG, "Setting fb_location to CAMERA_FB_IN_DRAM with lower picture quality");
|
|
config.fb_location = CAMERA_FB_IN_DRAM;
|
|
config.jpeg_quality = 7;
|
|
config.fb_count = 2;
|
|
return;
|
|
}
|
|
|
|
ESP_LOGE(CAMERA_MANAGER_TAG, "PSRAM size: %u", esp_psram_get_size());
|
|
}
|
|
|
|
void CameraManager::setupCameraSensor()
|
|
{
|
|
ESP_LOGI(CAMERA_MANAGER_TAG, "Setting up camera sensor");
|
|
|
|
camera_sensor = esp_camera_sensor_get();
|
|
// fixes corrupted jpegs, https://github.com/espressif/esp32-camera/issues/203
|
|
// documentation https://www.uctronics.com/download/cam_module/OV2640DS.pdf
|
|
camera_sensor->set_reg(
|
|
camera_sensor, 0xff, 0xff,
|
|
0x00); // banksel, here we're directly writing to the registers.
|
|
// 0xFF==0x00 is the first bank, there's also 0xFF==0x01
|
|
camera_sensor->set_reg(camera_sensor, 0xd3, 0xff, 5); // clock
|
|
camera_sensor->set_brightness(camera_sensor, 2); // -2 to 2
|
|
camera_sensor->set_contrast(camera_sensor, 2); // -2 to 2
|
|
camera_sensor->set_saturation(camera_sensor, -2); // -2 to 2
|
|
|
|
// white balance control
|
|
camera_sensor->set_whitebal(camera_sensor, 1); // 0 = disable , 1 = enable
|
|
camera_sensor->set_awb_gain(camera_sensor, 0); // 0 = disable , 1 = enable
|
|
camera_sensor->set_wb_mode(camera_sensor,
|
|
0); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 -
|
|
// Sunny, 2 - Cloudy, 3 - Office, 4 - Home)
|
|
|
|
// controls the exposure
|
|
camera_sensor->set_exposure_ctrl(camera_sensor,
|
|
0); // 0 = disable , 1 = enable
|
|
camera_sensor->set_aec2(camera_sensor, 0); // 0 = disable , 1 = enable
|
|
camera_sensor->set_ae_level(camera_sensor, 0); // -2 to 2
|
|
camera_sensor->set_aec_value(camera_sensor, 300); // 0 to 1200
|
|
|
|
// controls the gain
|
|
camera_sensor->set_gain_ctrl(camera_sensor, 0); // 0 = disable , 1 = enable
|
|
|
|
// automatic gain control gain, controls by how much the resulting image
|
|
// should be amplified
|
|
camera_sensor->set_agc_gain(camera_sensor, 2); // 0 to 30
|
|
camera_sensor->set_gainceiling(camera_sensor, (gainceiling_t)6); // 0 to 6
|
|
|
|
// black and white pixel correction, averages the white and black spots
|
|
camera_sensor->set_bpc(camera_sensor, 1); // 0 = disable , 1 = enable
|
|
camera_sensor->set_wpc(camera_sensor, 1); // 0 = disable , 1 = enable
|
|
// digital clamp white balance
|
|
camera_sensor->set_dcw(camera_sensor, 0); // 0 = disable , 1 = enable
|
|
|
|
// gamma correction
|
|
camera_sensor->set_raw_gma(
|
|
camera_sensor,
|
|
1); // 0 = disable , 1 = enable (makes much lighter and noisy)
|
|
|
|
camera_sensor->set_lenc(camera_sensor, 0); // 0 = disable , 1 = enable // 0 =
|
|
// disable , 1 = enable
|
|
|
|
camera_sensor->set_colorbar(camera_sensor, 0); // 0 = disable , 1 = enable
|
|
|
|
camera_sensor->set_special_effect(
|
|
camera_sensor,
|
|
2); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint,
|
|
// 4 - Green Tint, 5 - Blue Tint, 6 - Sepia)
|
|
|
|
// it gets overriden somewhere somehow
|
|
camera_sensor->set_framesize(camera_sensor, FRAMESIZE_240X240);
|
|
ESP_LOGI(CAMERA_MANAGER_TAG, "Setting up camera sensor done");
|
|
}
|
|
|
|
bool CameraManager::setupCamera()
|
|
{
|
|
ESP_LOGI(CAMERA_MANAGER_TAG, "Setting up camera pinout");
|
|
this->setupCameraPinout();
|
|
ESP_LOGI(CAMERA_MANAGER_TAG, "Setting up camera with resolution");
|
|
// this->setupBasicResolution();
|
|
|
|
ESP_LOGI(CAMERA_MANAGER_TAG, "Initializing camera...");
|
|
|
|
if (auto const hasCameraBeenInitialized = esp_camera_init(&config); hasCameraBeenInitialized == ESP_OK)
|
|
{
|
|
ESP_LOGI(CAMERA_MANAGER_TAG, "Camera initialized: %s \r\n",
|
|
esp_err_to_name(hasCameraBeenInitialized));
|
|
|
|
constexpr auto event = SystemEvent{EventSource::CAMERA, CameraState_e::Camera_Success};
|
|
xQueueSend(this->eventQueue, &event, 10);
|
|
}
|
|
else
|
|
{
|
|
ESP_LOGE(CAMERA_MANAGER_TAG, "Camera initialization failed with error: %s \r\n",
|
|
esp_err_to_name(hasCameraBeenInitialized));
|
|
ESP_LOGE(CAMERA_MANAGER_TAG, "Camera most likely not seated properly in the socket. "
|
|
"Please "
|
|
"fix the "
|
|
"camera and reboot the device.\r\n");
|
|
constexpr auto event = SystemEvent{EventSource::CAMERA, CameraState_e::Camera_Error};
|
|
xQueueSend(this->eventQueue, &event, 10);
|
|
return false;
|
|
}
|
|
|
|
#if CONFIG_GENERAL_WIRED_MODE
|
|
const auto temp_sensor = esp_camera_sensor_get();
|
|
|
|
// Thanks to lick_it, we discovered that OV5640 likes to overheat when
|
|
// running at higher than usual xclk frequencies.
|
|
// Hence, why we're limiting the faster ones for OV2640
|
|
if (const auto camera_id = temp_sensor->id.PID; camera_id == OV5640_PID) {
|
|
config.xclk_freq_hz = OV5640_XCLK_FREQ_HZ;
|
|
esp_camera_deinit();
|
|
esp_camera_init(&config);
|
|
}
|
|
|
|
#endif
|
|
|
|
this->setupCameraSensor();
|
|
// this->loadConfigData(); // move this to update method once implemented
|
|
return true;
|
|
}
|
|
|
|
void CameraManager::loadConfigData()
|
|
{
|
|
ESP_LOGD(CAMERA_MANAGER_TAG, "Loading camera config data");
|
|
CameraConfig_t cameraConfig = projectConfig->getCameraConfig();
|
|
this->setHFlip(cameraConfig.href);
|
|
this->setVFlip(cameraConfig.vflip);
|
|
this->setCameraResolution(static_cast<framesize_t>(cameraConfig.framesize));
|
|
camera_sensor->set_quality(camera_sensor, cameraConfig.quality);
|
|
camera_sensor->set_agc_gain(camera_sensor, cameraConfig.brightness);
|
|
ESP_LOGD(CAMERA_MANAGER_TAG, "Loading camera config data done");
|
|
}
|
|
|
|
int CameraManager::setCameraResolution(const framesize_t frameSize)
|
|
{
|
|
if (camera_sensor->pixformat == PIXFORMAT_JPEG)
|
|
{
|
|
return camera_sensor->set_framesize(camera_sensor, frameSize);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int CameraManager::setVFlip(const int direction)
|
|
{
|
|
return camera_sensor->set_vflip(camera_sensor, direction);
|
|
}
|
|
|
|
int CameraManager::setHFlip(const int direction)
|
|
{
|
|
return camera_sensor->set_hmirror(camera_sensor, direction);
|
|
}
|
|
|
|
int CameraManager::setVieWindow(int offsetX,
|
|
int offsetY,
|
|
int outputX,
|
|
int outputY)
|
|
{
|
|
|
|
// todo safariMonkey made a PoC, implement it here
|
|
return 0;
|
|
}
|
|
|
|
//! either hardware(1) or software(0)
|
|
void CameraManager::resetCamera(bool type)
|
|
{
|
|
// TODO add camera reset
|
|
|
|
// if (type)
|
|
// {
|
|
// // power cycle the camera module (handy if camera stops responding)
|
|
// digitalWrite(PWDN_GPIO_NUM, HIGH); // turn power off to camera module
|
|
// Network_Utilities::my_delay(0.3); // a for loop with a delay of 300ms
|
|
// digitalWrite(PWDN_GPIO_NUM, LOW);
|
|
// Network_Utilities::my_delay(0.3);
|
|
// setupCamera();
|
|
// }
|
|
// else
|
|
// {
|
|
// // reset via software (handy if you wish to change resolution or image type
|
|
// // etc. - see test procedure)
|
|
// esp_camera_deinit();
|
|
// Network_Utilities::my_delay(0.05);
|
|
// setupCamera();
|
|
// }
|
|
}
|